PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / 2.6.1
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More v2.6.1
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
← All changes | inc/functions/developers.php +256 -61 2.0.12 → 2.6.1 View file →
@@ -8,10 +8,13 @@
8 8 */
9 9
10 10 namespace ContentControl;
11 11
12 +use ContentControl\Models\Restriction;
13 +
12 14 use function ContentControl\plugin;
13 15 use function ContentControl\set_rules_query;
16 +use function ContentControl\is_rest;
14 17
15 18 defined( 'ABSPATH' ) || exit;
16 19
17 20 /**
@@ -16,22 +19,22 @@
16 19
17 20 /**
18 21 * Check if content has restrictions.
19 22 *
20 - * @param int|null $post_id Post ID.
23 + * @param int|null $content_id Content ID.
21 24 *
22 25 * @return bool
23 26 *
24 27 * @since 2.0.0
25 28 */
26 -function content_has_restrictions( $post_id = null ) {
27 - $overload_post = setup_post( $post_id );
29 +function content_has_restrictions( $content_id = null ) {
30 + $overload_content = setup_content_globals( $content_id );
28 31
29 - $has_restrictions = plugin( 'restrictions' )->has_applicable_restrictions( $post_id );
32 + $has_restrictions = plugin( 'restrictions' )->has_applicable_restrictions( $content_id );
30 33
31 - // Clear post if we overloaded it.
32 - if ( $overload_post ) {
33 - clear_post();
34 + // Clear content if we overloaded it.
35 + if ( $overload_content ) {
36 + reset_content_globals();
34 37 }
35 38
36 39 /**
37 40 * Filter whether content has restrictions.
@@ -36,28 +39,28 @@
36 39 /**
37 40 * Filter whether content has restrictions.
38 41 *
39 42 * @param bool $has_restrictions Whether content has restrictions.
40 - * @param int|null $post_id Post ID.
43 + * @param int|null $content_id Content ID.
41 44 *
42 45 * @return bool
43 46 *
44 47 * @since 2.0.0
45 48 */
46 - return (bool) apply_filters( 'content_control/content_has_restriction', $has_restrictions, $post_id );
49 + return (bool) apply_filters( 'content_control/content_has_restrictions', $has_restrictions, $content_id );
47 50 }
48 51
49 52 /**
50 53 * Check if user can access content.
51 54 *
52 - * @param int|null $post_id Post ID.
55 + * @param int|null $content_id Content ID.
53 56 *
54 57 * @return bool True if user meets requirements, false if not.
55 58 *
56 59 * @since 2.0.0
57 60 */
58 -function user_can_view_content( $post_id = null ) {
59 - if ( ! content_has_restrictions( $post_id ) ) {
61 +function user_can_view_content( $content_id = null ) {
62 + if ( ! content_has_restrictions( $content_id ) ) {
60 63 return true;
61 64 }
62 65
63 66 $can_view = true;
@@ -63,17 +66,27 @@
63 66 $can_view = true;
64 67
65 68 $restrictions = [];
66 69
67 - if ( false === (bool) apply_filters( 'content_control/check_all_restrictions', false, $post_id ) ) {
68 - $restriction = get_applicable_restriction( $post_id );
70 + if ( false === (bool) apply_filters( 'content_control/check_all_restrictions', false, $content_id ) ) {
71 + /**
72 + * Fetch first applicable restriction.
73 + *
74 + * @var Restriction|false $restriction
75 + */
76 + $restriction = get_applicable_restrictions( $content_id, true );
69 77
70 - if ( null !== $restriction ) {
78 + if ( $restriction ) {
71 79 $can_view = $restriction->user_meets_requirements();
72 80 $restrictions[] = $restriction;
73 81 }
74 82 } else {
75 - $restrictions = get_all_applicable_restrictions( $post_id );
83 + /**
84 + * Fetch all applicable restrictions.
85 + *
86 + * @var Restriction[]|false $restrictions
87 + */
88 + $restrictions = get_applicable_restrictions( $content_id, false );
76 89
77 90 if ( count( $restrictions ) ) {
78 91 $checks = [];
79 92
@@ -89,62 +102,66 @@
89 102 /**
90 103 * Filter whether user can view content.
91 104 *
92 105 * @param bool $can_view Whether user can view content.
93 - * @param int|null $post_id Post ID.
94 - * @param \ContentControl\Models\Restriction[] $restrictions Restrictions.
106 + * @param int|null $content_id Content ID.
107 + * @param Restriction[] $restrictions Restrictions.
95 108 *
96 109 * @return bool
97 110 *
98 111 * @since 2.0.0
99 112 */
100 - return (bool) apply_filters( 'content_control/user_can_view_content', $can_view, $post_id, $restrictions );
113 + return (bool) apply_filters( 'content_control/user_can_view_content', $can_view, $content_id, $restrictions );
101 114 }
102 115
103 116 /**
104 - * Helper that checks if given or current post is restricted or not.
117 + * Helper that checks if given or current content is restricted or not.
105 118 *
106 119 * @see \ContentControl\user_can_view_content() to check if user can view content.
107 120 *
108 - * @param int|null $post_id Post ID.
121 + * @param int|null $content_id Content ID.
109 122 *
110 123 * @return bool
111 124 *
112 125 * @since 2.0.0
113 126 */
114 -function content_is_restricted( $post_id = null ) {
115 - $is_restricted = ! user_can_view_content( $post_id );
127 +function content_is_restricted( $content_id = null ) {
128 + $is_restricted = ! user_can_view_content( $content_id );
116 129
117 130 /**
118 131 * Filter whether content is restricted.
119 132 *
120 133 * @param bool $is_restricted Whether content is restricted.
121 - * @param int|null $post_id Post ID.
134 + * @param int|null $content_id Content ID.
122 135 *
123 136 * @return bool
124 137 *
125 138 * @since 2.0.0
126 139 */
127 - return (bool) apply_filters( 'content_control/content_is_restricted', $is_restricted, $post_id );
140 + return (bool) apply_filters( 'content_control/content_is_restricted', $is_restricted, $content_id );
128 141 }
129 142
130 143 /**
131 - * Get applicable restriction.
144 + * Get applicable restrictions for the given content.
132 145 *
133 - * @param int|null $post_id Post ID.
146 + * If $single is true, return the first applicable restriction. If false, return all applicable restrictions.
147 + * Sorted by priority and cached internally.
134 148 *
135 - * @return \ContentControl\Models\Restriction|false
149 + * @param int|null $content_id Content ID.
150 + * @param bool $single Whether to return a single match or an array of matches.
136 151 *
137 - * @since 2.0.0
152 + * @return Restriction|Restriction[]|false
153 + *
154 + * @since 2.4.0
138 155 */
139 -function get_applicable_restriction( $post_id = null ) {
140 - $overload_post = setup_post( $post_id );
156 +function get_applicable_restrictions( $content_id = null, $single = true ) {
157 + $overload_content = setup_content_globals( $content_id );
141 158
142 - $restriction = plugin( 'restrictions' )->get_applicable_restriction( $post_id );
159 + $restriction = plugin( 'restrictions' )->get_applicable_restrictions( $content_id, $single );
143 160
144 - // Clear post if we overloaded it.
145 - if ( $overload_post ) {
146 - clear_post();
161 + // Clear content if we overloaded it.
162 + if ( $overload_content ) {
163 + reset_content_globals();
147 164 }
148 165
149 166 return $restriction;
150 167 }
@@ -149,27 +166,31 @@
149 166 return $restriction;
150 167 }
151 168
152 169 /**
170 + * Get applicable restriction.
171 + *
172 + * @param int|null $content_id Content ID.
173 + *
174 + * @return Restriction|false
175 + *
176 + * @since 2.0.0
177 + */
178 +function get_applicable_restriction( $content_id = null ) {
179 + return get_applicable_restrictions( $content_id, true );
180 +}
181 +
182 +/**
153 183 * Get all applicable restrictions.
154 184 *
155 - * @param int|null $post_id Post ID.
185 + * @param int|null $content_id Content ID.
156 186 *
157 - * @return \ContentControl\Models\Restriction[]
187 + * @return Restriction[]
158 188 *
159 189 * @since 2.0.11
160 190 */
161 -function get_all_applicable_restrictions( $post_id = null ) {
162 - $overload_post = setup_post( $post_id );
163 -
164 - $restrictions = plugin( 'restrictions' )->get_all_applicable_restrictions( $post_id );
165 -
166 - // Clear post if we overloaded it.
167 - if ( $overload_post ) {
168 - clear_post();
169 - }
170 -
171 - return $restrictions;
191 +function get_all_applicable_restrictions( $content_id = null ) {
192 + return get_applicable_restrictions( $content_id, false );
172 193 }
173 194
174 195 /**
175 196 * Check if query has restrictions.
@@ -175,9 +196,9 @@
175 196 * Check if query has restrictions.
176 197 *
177 198 * @param \WP_Query $query Query object.
178 199 *
179 - * @return array<array{restriction:\ContentControl\Models\Restriction,post_ids:int[]}>|false
200 + * @return array<array{restriction:Restriction,post_ids:int[]}>|false
180 201 *
181 202 * @since 2.0.0
182 203 */
183 204 function get_restriction_matches_for_queried_posts( $query ) {
@@ -201,11 +222,21 @@
201 222
202 223 set_rules_query( $query );
203 224
204 225 foreach ( $query->posts as $post ) {
226 + /**
227 + * Post ID.
228 + *
229 + * @var \WP_Post $post
230 + */
205 231 if ( content_is_restricted( $post->ID ) ) {
232 + // TODO This needs to likely respect the filter for checking all applicable restrictions.
206 233 $restriction = get_applicable_restriction( $post->ID );
207 234
235 + if ( ! $restriction ) {
236 + continue;
237 + }
238 +
208 239 if ( ! isset( $restrictions[ $cache_key ][ $restriction->priority ] ) ) {
209 240 // Handles deduplication & sorting.
210 241 $restrictions[ $cache_key ][ $restriction->priority ] = [
211 242 'restriction' => $restriction,
@@ -232,8 +263,174 @@
232 263 return $restrictions[ $cache_key ];
233 264 }
234 265
235 266 /**
267 + * Check if query has restrictions.
268 + *
269 + * @param \WP_Term_Query $query Query object.
270 + *
271 + * @return array<array{restriction:Restriction,term_ids:int[]}>|false
272 + *
273 + * @since 2.2.0
274 + */
275 +function get_restriction_matches_for_queried_terms( $query ) {
276 + if ( empty( $query->terms ) ) {
277 + return false;
278 + }
279 +
280 + static $restrictions;
281 +
282 + // Generate cache key from hasing $wp_query.
283 + $cache_key = md5( (string) wp_json_encode( $query ) );
284 +
285 + if ( isset( $restrictions[ $cache_key ] ) ) {
286 + return $restrictions[ $cache_key ];
287 + }
288 +
289 + set_rules_query( $query );
290 +
291 + foreach ( $query->terms as $term ) {
292 + $term_id = false;
293 +
294 + if ( is_object( $term ) && isset( $term->term_id ) ) {
295 + $term_id = (int) $term->term_id;
296 + } elseif ( is_numeric( $term ) ) {
297 + $term_id = absint( $term );
298 + }
299 +
300 + if ( $term_id > 0 && content_is_restricted( $term_id ) ) {
301 + // TODO This needs to likely respect the filter for checking all applicable restrictions.
302 + $restriction = get_applicable_restrictions( $term_id, true );
303 +
304 + if ( ! $restriction ) {
305 + continue;
306 + }
307 +
308 + if ( ! isset( $restrictions[ $cache_key ][ $restriction->priority ] ) ) {
309 + // Handles deduplication & sorting.
310 + $restrictions[ $cache_key ][ $restriction->priority ] = [
311 + 'restriction' => $restriction,
312 + 'term_ids' => [],
313 + ];
314 + }
315 +
316 + // Add term to restriction.
317 + $restrictions[ $cache_key ][ $restriction->priority ]['term_ids'][] = $term_id;
318 + }
319 + }
320 +
321 + set_rules_query( null );
322 +
323 + if ( empty( $restrictions[ $cache_key ] ) ) {
324 + $restrictions[ $cache_key ] = false;
325 + } else {
326 + // Sort by priority.
327 + ksort( $restrictions[ $cache_key ] );
328 + // Remove priority keys.
329 + $restrictions[ $cache_key ] = array_values( $restrictions[ $cache_key ] );
330 + }
331 +
332 + return $restrictions[ $cache_key ];
333 +}
334 +
335 +/**
336 + * Check if the referrer is the sites admin area.
337 + *
338 + * @return bool
339 + *
340 + * @since 2.2.0
341 + */
342 +function check_referrer_is_admin() {
343 + $referrer = wp_get_raw_referer();
344 + if ( empty( $referrer ) ) {
345 + return false;
346 + }
347 +
348 + $admin_url = admin_url();
349 + // Normalize URLs for comparison.
350 + $normalized_referrer = strtolower( $referrer );
351 + $normalized_admin_url = strtolower( $admin_url );
352 +
353 + // Compare the beginning of the referrer with the admin URL.
354 + return str_starts_with( $normalized_referrer, $normalized_admin_url );
355 +}
356 +
357 +/**
358 + * Check if request is excluded.
359 + *
360 + * @return bool
361 + *
362 + * @since 2.3.1
363 + */
364 +function request_is_excluded_rest_endpoint() {
365 + /**
366 + * Filter whether to exclude a request from being restricted.
367 + *
368 + * @param bool $is_excluded Whether to exclude the request.
369 + *
370 + * @return bool
371 + */
372 + return apply_filters( 'content_control/request_is_excluded_rest_endpoint', ! is_wp_core_rest_namespace() );
373 +}
374 +
375 +/**
376 + * Check if request is excluded.
377 + *
378 + * @return bool
379 + *
380 + * @since 2.3.0
381 + */
382 +function request_is_excluded() {
383 + static $is_excluded;
384 +
385 + if ( isset( $is_excluded ) ) {
386 + return $is_excluded;
387 + }
388 +
389 + $is_excluded = false;
390 +
391 + if (
392 + // Check if doing cron.
393 + is_cron() ||
394 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
395 + ( is_ajax() && isset( $_REQUEST['action'] ) && 'heartbeat' === $_REQUEST['action'] ) ||
396 + // If this is rest request and not core wp namespace.
397 + ( is_rest() && request_is_excluded_rest_endpoint() )
398 + ) {
399 + $is_excluded = true;
400 + }
401 +
402 + return $is_excluded;
403 +}
404 +
405 +/**
406 + * Check if the request is for a priveleged user in the admin area.
407 + *
408 + * @return bool
409 + *
410 + * @since 2.3.0
411 + */
412 +function request_for_user_is_excluded() {
413 + // Check if user has permission to manage settings and is on the admin area.
414 + if ( user_is_excludable() ) {
415 + if (
416 + // Is in the admin area.
417 + is_admin() ||
418 + ( is_preview() && current_user_can( 'edit_post', get_the_ID() ) ) ||
419 + // Is an ajax request from the admin area.
420 + (
421 + ( is_ajax() || is_rest() ) &&
422 + check_referrer_is_admin()
423 + )
424 + ) {
425 + return true;
426 + }
427 + }
428 +
429 + return false;
430 +}
431 +
432 +/**
236 433 * Check if protection methods should be disabled.
237 434 *
238 435 * Generally used to bypass protections when using page editors.
239 436 *
@@ -241,17 +438,16 @@
241 438 *
242 439 * @since 2.0.0
243 440 */
244 441 function protection_is_disabled() {
245 - $checks = [
246 - // Disable protection when not on the frontend.
247 - ! \ContentControl\is_frontend(),
248 - // Disable protection when user is excluded.
249 - user_is_excluded(),
250 - // Disable protection when viewing post previews.
251 - is_preview() && current_user_can( 'edit_post', get_the_ID() ),
252 - ];
442 + static $protection_disabled;
253 443
444 + if ( isset( $protection_disabled ) ) {
445 + return $protection_disabled;
446 + }
447 +
448 + $protection_disabled = user_is_excluded() || request_is_excluded() || request_for_user_is_excluded();
449 +
254 450 /**
255 451 * Filter whether protection is disabled.
256 452 *
257 453 * @param bool $is_disabled Whether protection is disabled.
@@ -259,9 +455,8 @@
259 455 * @return bool
260 456 *
261 457 * @since 2.0.0
262 458 */
263 - return apply_filters(
264 - 'content_control/protection_is_disabled',
265 - in_array( true, $checks, true )
266 - );
459 + $protection_disabled = apply_filters( 'content_control/protection_is_disabled', $protection_disabled );
460 +
461 + return $protection_disabled;
267 462 }