PluginProbe
Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code / 5.5.4
Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code v5.5.4
5.5.4 5.5.3 3.1.0 3.2.0 3.2.1 3.3.0 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.6.0 3.7.0 3.8.0 3.8.1 3.8.2 3.8.3 4.0.0 4.0.2 4.0.3 4.0.4 4.0.5 4.1.0 All 79 releases
copy-the-code / includes / global-injector / class-display-conditions.php

class-display-conditions.php in Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code 5.5.4, at includes/global-injector/class-display-conditions.php

432 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Display Conditions for Global Injector
4 *
5 * Defines available display conditions, operators, and evaluation logic.
6 * Conditions determine when/where the copy button should be displayed.
7 *
8 * @package CTC
9 * @since 5.0.0
10 */
11
12 namespace CTC\Global_Injector;
13
14 /**
15 * Display Conditions Class
16 */
17 class Display_Conditions {
18
19 /**
20 * Get all available display conditions.
21 *
22 * Each condition has:
23 * - key: Unique identifier
24 * - label: Human-readable name
25 * - icon: SVG icon key
26 * - operators: Available comparison operators
27 * - value_type: 'select', 'text', 'number'
28 * - values: For select type, array of options
29 * - is_pro: Whether this is a Pro-only condition
30 *
31 * @return array Array of conditions.
32 */
33 public static function get_conditions() {
34 $conditions = [
35 // Free conditions.
36 'post_type' => [
37 'key' => 'post_type',
38 'label' => __( 'Post Type', 'ctc' ),
39 'icon' => 'document',
40 'operators' => [ 'eq', 'neq' ],
41 'value_type' => 'select',
42 'values' => self::get_post_types(),
43 'is_pro' => false,
44 ],
45 'user_logged_in' => [
46 'key' => 'user_logged_in',
47 'label' => __( 'User Logged In', 'ctc' ),
48 'icon' => 'user',
49 'operators' => [ 'is' ],
50 'value_type' => 'select',
51 'values' => [
52 [
53 'value' => 'yes',
54 'label' => __( 'Yes', 'ctc' ),
55 ],
56 [
57 'value' => 'no',
58 'label' => __( 'No', 'ctc' ),
59 ],
60 ],
61 'is_pro' => false,
62 ],
63 'page_id' => [
64 'key' => 'page_id',
65 'label' => __( 'Page ID', 'ctc' ),
66 'icon' => 'page',
67 'operators' => [ 'eq', 'neq' ],
68 'value_type' => 'text',
69 'values' => [],
70 'is_pro' => false,
71 ],
72 'post_id' => [
73 'key' => 'post_id',
74 'label' => __( 'Post ID', 'ctc' ),
75 'icon' => 'post',
76 'operators' => [ 'eq', 'neq' ],
77 'value_type' => 'text',
78 'values' => [],
79 'is_pro' => false,
80 ],
81
82 // Pro conditions.
83 'user_role' => [
84 'key' => 'user_role',
85 'label' => __( 'User Role', 'ctc' ),
86 'icon' => 'users',
87 'operators' => [ 'eq', 'neq' ],
88 'value_type' => 'select',
89 'values' => self::get_user_roles(),
90 'is_pro' => true,
91 ],
92 'device' => [
93 'key' => 'device',
94 'label' => __( 'Device', 'ctc' ),
95 'icon' => 'device',
96 'operators' => [ 'is' ],
97 'value_type' => 'select',
98 'values' => [
99 [
100 'value' => 'mobile',
101 'label' => __( 'Mobile', 'ctc' ),
102 ],
103 [
104 'value' => 'tablet',
105 'label' => __( 'Tablet', 'ctc' ),
106 ],
107 [
108 'value' => 'desktop',
109 'label' => __( 'Desktop', 'ctc' ),
110 ],
111 ],
112 'is_pro' => true,
113 ],
114 'url_contains' => [
115 'key' => 'url_contains',
116 'label' => __( 'URL Contains', 'ctc' ),
117 'icon' => 'link',
118 'operators' => [ 'contains', 'not_contains' ],
119 'value_type' => 'text',
120 'values' => [],
121 'is_pro' => true,
122 ],
123 ];
124
125 /**
126 * Filter the available display conditions.
127 *
128 * Allows developers to add, modify, or remove display conditions.
129 *
130 * @since 5.0.0
131 *
132 * @param array $conditions Array of condition definitions.
133 */
134 return apply_filters( 'ctc/display_conditions/list', $conditions );
135 }
136
137 /**
138 * Get available operators.
139 *
140 * @return array Array of operators with key => label.
141 */
142 public static function get_operators() {
143 $operators = [
144 'eq' => __( 'Is Equal To', 'ctc' ),
145 'neq' => __( 'Is Not Equal To', 'ctc' ),
146 'is' => __( 'Is', 'ctc' ),
147 'contains' => __( 'Contains', 'ctc' ),
148 'not_contains' => __( 'Does Not Contain', 'ctc' ),
149 'gt' => __( 'Greater Than', 'ctc' ),
150 'lt' => __( 'Less Than', 'ctc' ),
151 'gte' => __( 'Greater Than or Equal', 'ctc' ),
152 'lte' => __( 'Less Than or Equal', 'ctc' ),
153 ];
154
155 /**
156 * Filter the available operators.
157 *
158 * @since 5.0.0
159 *
160 * @param array $operators Array of operator definitions.
161 */
162 return apply_filters( 'ctc/display_conditions/operators', $operators );
163 }
164
165 /**
166 * Get available post types for condition values.
167 *
168 * @return array Array of post types with value/label.
169 */
170 public static function get_post_types() {
171 $post_types = get_post_types( [ 'public' => true ], 'objects' );
172 $options = [];
173
174 foreach ( $post_types as $post_type ) {
175 $options[] = [
176 'value' => $post_type->name,
177 'label' => $post_type->label,
178 ];
179 }
180
181 return $options;
182 }
183
184 /**
185 * Get available user roles for condition values.
186 *
187 * @return array Array of user roles with value/label.
188 */
189 public static function get_user_roles() {
190 $roles = wp_roles()->roles;
191 $options = [];
192
193 foreach ( $roles as $key => $role ) {
194 $options[] = [
195 'value' => $key,
196 'label' => $role['name'],
197 ];
198 }
199
200 return $options;
201 }
202
203 /**
204 * Get the current page context for frontend evaluation.
205 *
206 * This data is localized to JS so conditions can be evaluated client-side.
207 *
208 * @return array Current page context.
209 */
210 public static function get_page_context() {
211 global $post;
212
213 $context = [
214 'post_type' => get_post_type(),
215 'post_id' => get_the_ID(),
216 'page_id' => is_page() ? get_the_ID() : 0,
217 'user_logged_in' => is_user_logged_in() ? 'yes' : 'no',
218 'user_role' => self::get_current_user_role(),
219 'url' => self::get_current_url(),
220 'device' => 'desktop', // Will be detected by JS.
221 ];
222
223 /**
224 * Filter the page context for condition evaluation.
225 *
226 * @since 5.0.0
227 *
228 * @param array $context Current page context.
229 */
230 return apply_filters( 'ctc/display_conditions/page_context', $context );
231 }
232
233 /**
234 * Get the current user's primary role.
235 *
236 * @return string User role or empty string if not logged in.
237 */
238 private static function get_current_user_role() {
239 if ( ! is_user_logged_in() ) {
240 return '';
241 }
242
243 $user = wp_get_current_user();
244 $roles = $user->roles;
245
246 return ! empty( $roles ) ? reset( $roles ) : '';
247 }
248
249 /**
250 * Get the current page URL.
251 *
252 * @return string Current URL.
253 */
254 private static function get_current_url() {
255 global $wp;
256 return home_url( add_query_arg( [], $wp->request ) );
257 }
258
259 /**
260 * Evaluate conditions for a rule.
261 *
262 * Groups are OR (any match = true).
263 * Rules within a group are AND (all must match = true).
264 *
265 * @param array $display_conditions The display conditions array.
266 * @param array $context The page context to evaluate against.
267 * @return bool Whether the conditions are met.
268 */
269 public static function evaluate( $display_conditions, $context = [] ) {
270 // No conditions = show everywhere.
271 if ( empty( $display_conditions ) || ! is_array( $display_conditions ) ) {
272 return true;
273 }
274
275 // Use current page context if not provided.
276 if ( empty( $context ) ) {
277 $context = self::get_page_context();
278 }
279
280 // OR logic: Any group matching = true.
281 foreach ( $display_conditions as $group ) {
282 if ( self::evaluate_group( $group, $context ) ) {
283 return true;
284 }
285 }
286
287 // No groups matched.
288 return false;
289 }
290
291 /**
292 * Evaluate a single condition group.
293 *
294 * All rules in the group must match (AND logic).
295 *
296 * @param array $group The condition group.
297 * @param array $context The page context.
298 * @return bool Whether all rules in the group match.
299 */
300 private static function evaluate_group( $group, $context ) {
301 if ( empty( $group['rules'] ) || ! is_array( $group['rules'] ) ) {
302 return true; // Empty group = always true.
303 }
304
305 // AND logic: All rules must match.
306 foreach ( $group['rules'] as $rule ) {
307 if ( ! self::evaluate_rule( $rule, $context ) ) {
308 return false;
309 }
310 }
311
312 return true;
313 }
314
315 /**
316 * Evaluate a single rule.
317 *
318 * @param array $rule The rule to evaluate.
319 * @param array $context The page context.
320 * @return bool Whether the rule matches.
321 */
322 private static function evaluate_rule( $rule, $context ) {
323 $param = isset( $rule['param'] ) ? $rule['param'] : '';
324 $operator = isset( $rule['op'] ) ? $rule['op'] : 'eq';
325 $value = isset( $rule['value'] ) ? $rule['value'] : '';
326
327 // Get the actual value from context.
328 $actual = isset( $context[ $param ] ) ? $context[ $param ] : '';
329
330 return self::compare( $actual, $operator, $value );
331 }
332
333 /**
334 * Compare two values using an operator.
335 *
336 * @param mixed $actual The actual value from context.
337 * @param string $operator The comparison operator.
338 * @param mixed $expected The expected value from rule.
339 * @return bool Comparison result.
340 */
341 private static function compare( $actual, $operator, $expected ) {
342 switch ( $operator ) {
343 case 'eq':
344 case 'is':
345 return (string) $actual === (string) $expected;
346
347 case 'neq':
348 return (string) $actual !== (string) $expected;
349
350 case 'contains':
351 return false !== strpos( (string) $actual, (string) $expected );
352
353 case 'not_contains':
354 return false === strpos( (string) $actual, (string) $expected );
355
356 case 'gt':
357 return (float) $actual > (float) $expected;
358
359 case 'lt':
360 return (float) $actual < (float) $expected;
361
362 case 'gte':
363 return (float) $actual >= (float) $expected;
364
365 case 'lte':
366 return (float) $actual <= (float) $expected;
367
368 default:
369 return false;
370 }
371 }
372
373 /**
374 * Get data to localize for JavaScript.
375 *
376 * @return array Data for wp_localize_script.
377 */
378 public static function get_localize_data() {
379 return [
380 'conditions' => self::get_conditions(),
381 'operators' => self::get_operators(),
382 'pageContext' => self::get_page_context(),
383 ];
384 }
385
386 /**
387 * Sanitize display conditions before saving.
388 *
389 * @param mixed $conditions Raw conditions data.
390 * @return array Sanitized conditions.
391 */
392 public static function sanitize( $conditions ) {
393 if ( ! is_array( $conditions ) ) {
394 return [];
395 }
396
397 $sanitized = [];
398
399 foreach ( $conditions as $group ) {
400 if ( ! is_array( $group ) ) {
401 continue;
402 }
403
404 $sanitized_group = [
405 'id' => isset( $group['id'] ) ? sanitize_key( $group['id'] ) : wp_generate_uuid4(),
406 'rules' => [],
407 ];
408
409 if ( isset( $group['rules'] ) && is_array( $group['rules'] ) ) {
410 foreach ( $group['rules'] as $rule ) {
411 if ( ! is_array( $rule ) ) {
412 continue;
413 }
414
415 $sanitized_group['rules'][] = [
416 'param' => isset( $rule['param'] ) ? sanitize_key( $rule['param'] ) : '',
417 'op' => isset( $rule['op'] ) ? sanitize_key( $rule['op'] ) : 'eq',
418 'value' => isset( $rule['value'] ) ? sanitize_text_field( $rule['value'] ) : '',
419 ];
420 }
421 }
422
423 // Only add groups that have rules.
424 if ( ! empty( $sanitized_group['rules'] ) ) {
425 $sanitized[] = $sanitized_group;
426 }
427 }
428
429 return $sanitized;
430 }
431 }
432