PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / trunk
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More vtrunk
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
content-control / inc / functions / developers.php

developers.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More trunk, at inc/functions/developers.php

464 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Restriction utility & helper functions.
4 *
5 * @package ContentControl
6 * @subpackage Functions
7 * @copyright (c) 2023 Code Atlantic LLC
8 */
9
10 namespace ContentControl;
11
12 use ContentControl\Models\Restriction;
13
14 use function ContentControl\plugin;
15 use function ContentControl\set_rules_query;
16 use function ContentControl\is_rest;
17
18 defined( 'ABSPATH' ) || exit;
19
20 /**
21 * Check if content has restrictions.
22 *
23 * @param int|null $content_id Content ID.
24 *
25 * @return bool
26 *
27 * @since 2.0.0
28 */
29 function content_has_restrictions( $content_id = null ) {
30 $overload_content = setup_content_globals( $content_id );
31
32 $has_restrictions = plugin( 'restrictions' )->has_applicable_restrictions( $content_id );
33
34 // Clear content if we overloaded it.
35 if ( $overload_content ) {
36 reset_content_globals();
37 }
38
39 /**
40 * Filter whether content has restrictions.
41 *
42 * @param bool $has_restrictions Whether content has restrictions.
43 * @param int|null $content_id Content ID.
44 *
45 * @return bool
46 *
47 * @since 2.0.0
48 */
49 return (bool) apply_filters( 'content_control/content_has_restrictions', $has_restrictions, $content_id );
50 }
51
52 /**
53 * Check if user can access content.
54 *
55 * @param int|null $content_id Content ID.
56 *
57 * @return bool True if user meets requirements, false if not.
58 *
59 * @since 2.0.0
60 */
61 function user_can_view_content( $content_id = null ) {
62 if ( ! content_has_restrictions( $content_id ) ) {
63 return true;
64 }
65
66 $can_view = true;
67
68 $restrictions = [];
69
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 );
77
78 if ( $restriction ) {
79 $can_view = $restriction->user_meets_requirements();
80 $restrictions[] = $restriction;
81 }
82 } else {
83 /**
84 * Fetch all applicable restrictions.
85 *
86 * @var Restriction[]|false $restrictions
87 */
88 $restrictions = get_applicable_restrictions( $content_id, false );
89
90 if ( count( $restrictions ) ) {
91 $checks = [];
92
93 foreach ( $restrictions as $restriction ) {
94 $checks[] = $restriction->user_meets_requirements();
95 }
96
97 // When checking all, we are looking for any true value.
98 $can_view = in_array( true, $checks, true );
99 }
100 }
101
102 /**
103 * Filter whether user can view content.
104 *
105 * @param bool $can_view Whether user can view content.
106 * @param int|null $content_id Content ID.
107 * @param Restriction[] $restrictions Restrictions.
108 *
109 * @return bool
110 *
111 * @since 2.0.0
112 */
113 return (bool) apply_filters( 'content_control/user_can_view_content', $can_view, $content_id, $restrictions );
114 }
115
116 /**
117 * Helper that checks if given or current content is restricted or not.
118 *
119 * @see \ContentControl\user_can_view_content() to check if user can view content.
120 *
121 * @param int|null $content_id Content ID.
122 *
123 * @return bool
124 *
125 * @since 2.0.0
126 */
127 function content_is_restricted( $content_id = null ) {
128 $is_restricted = ! user_can_view_content( $content_id );
129
130 /**
131 * Filter whether content is restricted.
132 *
133 * @param bool $is_restricted Whether content is restricted.
134 * @param int|null $content_id Content ID.
135 *
136 * @return bool
137 *
138 * @since 2.0.0
139 */
140 return (bool) apply_filters( 'content_control/content_is_restricted', $is_restricted, $content_id );
141 }
142
143 /**
144 * Get applicable restrictions for the given content.
145 *
146 * If $single is true, return the first applicable restriction. If false, return all applicable restrictions.
147 * Sorted by priority and cached internally.
148 *
149 * @param int|null $content_id Content ID.
150 * @param bool $single Whether to return a single match or an array of matches.
151 *
152 * @return Restriction|Restriction[]|false
153 *
154 * @since 2.4.0
155 */
156 function get_applicable_restrictions( $content_id = null, $single = true ) {
157 $overload_content = setup_content_globals( $content_id );
158
159 $restriction = plugin( 'restrictions' )->get_applicable_restrictions( $content_id, $single );
160
161 // Clear content if we overloaded it.
162 if ( $overload_content ) {
163 reset_content_globals();
164 }
165
166 return $restriction;
167 }
168
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 /**
183 * Get all applicable restrictions.
184 *
185 * @param int|null $content_id Content ID.
186 *
187 * @return Restriction[]
188 *
189 * @since 2.0.11
190 */
191 function get_all_applicable_restrictions( $content_id = null ) {
192 return get_applicable_restrictions( $content_id, false );
193 }
194
195 /**
196 * Check if query has restrictions.
197 *
198 * @param \WP_Query $query Query object.
199 *
200 * @return array<array{restriction:Restriction,post_ids:int[]}>|false
201 *
202 * @since 2.0.0
203 */
204 function get_restriction_matches_for_queried_posts( $query ) {
205 // If its the main query, and not an archive-like page, bail.
206 if ( $query->is_main_query() && ( ! $query->is_home() && ! $query->is_archive() && ! $query->is_search() ) ) {
207 return false;
208 }
209
210 if ( empty( $query->posts ) ) {
211 return false;
212 }
213
214 static $restrictions;
215
216 // Generate cache key from hasing $wp_query.
217 $cache_key = md5( (string) wp_json_encode( $query ) );
218
219 if ( isset( $restrictions[ $cache_key ] ) ) {
220 return $restrictions[ $cache_key ];
221 }
222
223 set_rules_query( $query );
224
225 foreach ( $query->posts as $post ) {
226 /**
227 * Post ID.
228 *
229 * @var \WP_Post $post
230 */
231 if ( content_is_restricted( $post->ID ) ) {
232 // TODO This needs to likely respect the filter for checking all applicable restrictions.
233 $restriction = get_applicable_restriction( $post->ID );
234
235 if ( ! $restriction ) {
236 continue;
237 }
238
239 if ( ! isset( $restrictions[ $cache_key ][ $restriction->priority ] ) ) {
240 // Handles deduplication & sorting.
241 $restrictions[ $cache_key ][ $restriction->priority ] = [
242 'restriction' => $restriction,
243 'post_ids' => [],
244 ];
245 }
246
247 // Add post to restriction.
248 $restrictions[ $cache_key ][ $restriction->priority ]['post_ids'][] = $post->ID;
249 }
250 }
251
252 set_rules_query( null );
253
254 if ( empty( $restrictions[ $cache_key ] ) ) {
255 $restrictions[ $cache_key ] = false;
256 } else {
257 // Sort by priority.
258 ksort( $restrictions[ $cache_key ] );
259 // Remove priority keys.
260 $restrictions[ $cache_key ] = array_values( $restrictions[ $cache_key ] );
261 }
262
263 return $restrictions[ $cache_key ];
264 }
265
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 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only request classification.
392 if (
393 // Check if doing cron.
394 is_cron() ||
395 ( is_ajax() && isset( $_REQUEST['action'] ) && is_string( $_REQUEST['action'] ) && 'heartbeat' === sanitize_key( wp_unslash( $_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 // phpcs:enable WordPress.Security.NonceVerification.Recommended
402
403 return $is_excluded;
404 }
405
406 /**
407 * Check if the request is for a priveleged user in the admin area.
408 *
409 * @return bool
410 *
411 * @since 2.3.0
412 */
413 function request_for_user_is_excluded() {
414 // Check if user has permission to manage settings and is on the admin area.
415 if ( user_is_excludable() ) {
416 if (
417 // Is in the admin area.
418 is_admin() ||
419 ( is_preview() && current_user_can( 'edit_post', get_the_ID() ) ) ||
420 // Is an ajax request from the admin area.
421 (
422 ( is_ajax() || is_rest() ) &&
423 check_referrer_is_admin()
424 )
425 ) {
426 return true;
427 }
428 }
429
430 return false;
431 }
432
433 /**
434 * Check if protection methods should be disabled.
435 *
436 * Generally used to bypass protections when using page editors.
437 *
438 * @return bool
439 *
440 * @since 2.0.0
441 */
442 function protection_is_disabled() {
443 static $protection_disabled;
444
445 if ( isset( $protection_disabled ) ) {
446 return $protection_disabled;
447 }
448
449 $protection_disabled = user_is_excluded() || request_is_excluded() || request_for_user_is_excluded();
450
451 /**
452 * Filter whether protection is disabled.
453 *
454 * @param bool $is_disabled Whether protection is disabled.
455 *
456 * @return bool
457 *
458 * @since 2.0.0
459 */
460 $protection_disabled = apply_filters( 'content_control/protection_is_disabled', $protection_disabled );
461
462 return $protection_disabled;
463 }
464