PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.12
Advanced Ads – Ad Manager & AdSense v2.0.12
2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / classes / visitor-conditions.php
advanced-ads / classes Last commit date
ad-health-notices.php 1 year ago checks.php 1 year ago display-conditions.php 10 months ago filesystem.php 2 years ago frontend_checks.php 1 year ago in-content-injector.php 1 year ago inline-css.php 1 year ago utils.php 1 year ago visitor-conditions.php 1 year ago
visitor-conditions.php
516 lines
1 <?php // phpcs:ignore WordPress.Files.FileName
2
3 use AdvancedAds\Utilities\WordPress;
4
5 /**
6 * Visitor conditions under which to (not) show an ad
7 *
8 * @since 1.5.4
9 */
10 class Advanced_Ads_Visitor_Conditions {
11
12 /**
13 * Instance of Advanced_Ads_Visitor_Conditions
14 *
15 * @var Advanced_Ads_Visitor_Conditions
16 */
17 protected static $instance;
18
19 /**
20 * Registered visitor conditions
21 *
22 * @var array $conditions
23 */
24 public $conditions;
25
26 /**
27 * Start of name in form elements
28 */
29 const FORM_NAME = 'advanced_ad[visitors]';
30
31 /**
32 * Advanced_Ads_Visitor_Conditions constructor
33 */
34 public function __construct() {
35
36 // register conditions.
37 $this->conditions = apply_filters(
38 'advanced-ads-visitor-conditions',
39 [
40 'mobile' => [
41 // type of the condition.
42 'label' => __( 'Device', 'advanced-ads' ),
43 'metabox' => [ 'Advanced_Ads_Visitor_Conditions', 'mobile_is_or_not' ], // callback to generate the metabox.
44 'check' => [ 'Advanced_Ads_Visitor_Conditions', 'check_device' ], // callback for frontend check.
45 'helplink' => 'https://wpadvancedads.com/manual/display-ads-either-on-mobile-or-desktop/?utm_source=advanced-ads&utm_medium=link&utm_campaign=condition-device',
46 'device_types' => [
47 'mobile' => [
48 'id' => 'mobile',
49 'label' => _x( 'Mobile', 'Device condition', 'advanced-ads' ),
50 ],
51 'tablet' => [
52 'id' => 'tablet',
53 'label' => _x( 'Tablet', 'Device condition', 'advanced-ads' ),
54 ],
55 'desktop' => [
56 'id' => 'desktop',
57 'label' => _x( 'Desktop', 'Device condition', 'advanced-ads' ),
58 ],
59 ],
60 ],
61 'loggedin' => [
62 'label' => __( 'logged-in visitor', 'advanced-ads' ),
63 'description' => __( 'Whether the visitor has to be logged in or not in order to see the ad.', 'advanced-ads' ),
64 'metabox' => [ 'Advanced_Ads_Visitor_Conditions', 'metabox_is_or_not' ], // callback to generate the metabox.
65 'check' => [ 'Advanced_Ads_Visitor_Conditions', 'check_logged_in' ], // callback for frontend check.
66 'helplink' => 'https://wpadvancedads.com/manual/logged-in-visitors/?utm_source=advanced-ads&utm_medium=link&utm_campaign=condition-logged-in-visitors',
67 'passive_info' => [
68 'hash_fields' => null,
69 'remove' => 'login',
70 'function' => 'is_user_logged_in',
71 ],
72 ],
73 ]
74 );
75 }
76
77 /**
78 * Load instance of Advanced_Ads_Visitor_Conditions
79 *
80 * @return Advanced_Ads_Visitor_Conditions
81 */
82 public static function get_instance() {
83 // If the single instance hasn't been set, set it now.
84 if ( null === self::$instance ) {
85 self::$instance = new self();
86 }
87
88 return self::$instance;
89 }
90
91
92 /**
93 * Get the conditions array alphabetically by label
94 *
95 * @since 1.8.12
96 */
97 public function get_conditions() {
98 uasort( $this->conditions, [ WordPress::class, 'sort_array_by_label' ] );
99
100 return $this->conditions;
101 }
102
103 /**
104 * Callback to render the mobile condition using the "is not" condition
105 *
106 * @param array $options options of the condition.
107 * @param int $index index of the condition.
108 * @param string $form_name name of the form, falls back to class constant.
109 */
110 public static function mobile_is_or_not( $options, $index = 0, $form_name = '' ) {
111
112 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
113 return;
114 }
115
116 $type_options = self::get_instance()->conditions;
117
118 if ( ! isset( $type_options[ $options['type'] ] ) ) {
119 return;
120 }
121
122 // options.
123 $operator = isset( $options['operator'] ) ? $options['operator'] : 'is';
124
125 // convert previous binary option to device selector.
126 if ( ! array_key_exists( 'value', $options ) ) {
127 $options['value'] = 'is' === $operator ? [ 'tablet', 'mobile' ] : [ 'desktop' ];
128 $operator = 'is';
129 }
130
131 $type_options[ $options['type'] ]['device_types'] = array_map(
132 function ( $device_type ) use ( $options ) {
133 $device_type['checked'] = in_array( $device_type['id'], $options['value'], true );
134
135 return $device_type;
136 },
137 $type_options[ $options['type'] ]['device_types']
138 );
139
140 // form name basis.
141 $name = self::get_form_name_with_index( $form_name, $index );
142
143 include ADVADS_ABSPATH . 'admin/views/conditions/condition-device.php';
144 }
145
146 /**
147 * Callback to display the "is not" condition
148 *
149 * @param array $options options of the condition.
150 * @param int $index index of the condition.
151 * @param string $form_name name of the form, falls back to class constant.
152 */
153 public static function metabox_is_or_not( $options, $index = 0, $form_name = '' ) {
154 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
155 return;
156 }
157
158 $type_options = self::get_instance()->conditions;
159 if ( ! isset( $type_options[ $options['type'] ] ) ) {
160 return;
161 }
162
163 // form name basis.
164 $name = self::get_form_name_with_index( $form_name, $index );
165 $operator = isset( $options['operator'] ) ? $options['operator'] : 'is';
166
167 include ADVADS_ABSPATH . 'admin/views/conditions/condition-is-or-not.php';
168 }
169
170 /**
171 * Callback to display the any condition based on a number
172 *
173 * @param array $options options of the condition.
174 * @param int $index index of the condition.
175 * @param string $form_name name of the form, falls back to class constant.
176 */
177 public static function metabox_number( $options, $index = 0, $form_name = '' ) {
178
179 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
180 return;
181 }
182
183 $type_options = self::get_instance()->conditions;
184
185 if ( ! isset( $type_options[ $options['type'] ] ) ) {
186 return;
187 }
188
189 // form name basis.
190 $name = self::get_form_name_with_index( $form_name, $index );
191
192 // options.
193 $value = isset( $options['value'] ) ? $options['value'] : 0;
194 $operator = isset( $options['operator'] ) ? $options['operator'] : 'is_equal';
195
196 include ADVADS_ABSPATH . 'admin/views/conditions/condition-number.php';
197 }
198
199 /**
200 * Callback to display the any condition based on a number
201 *
202 * @param array $options options of the condition.
203 * @param int $index index of the condition.
204 * @param string $form_name name of the form, falls back to class constant.
205 */
206 public static function metabox_string( $options, $index = 0, $form_name = '' ) {
207
208 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
209 return;
210 }
211
212 $type_options = self::get_instance()->conditions;
213
214 if ( ! isset( $type_options[ $options['type'] ] ) ) {
215 return;
216 }
217
218 // form name basis.
219 $name = self::get_form_name_with_index( $form_name, $index );
220
221 // options.
222 $value = isset( $options['value'] ) ? $options['value'] : '';
223 $operator = isset( $options['operator'] ) ? $options['operator'] : 'contains';
224
225 include ADVADS_ABSPATH . 'admin/views/conditions/condition-string.php';
226 }
227
228 /**
229 * Controls frontend checks for conditions
230 *
231 * @param array $options Options of the condition.
232 * @param bool|Ad $ad Ad instance.
233 *
234 * @return bool false, if ad can’t be delivered
235 */
236 public static function frontend_check( $options = [], $ad = false ) {
237 $visitor_conditions = self::get_instance()->conditions;
238
239 if ( is_array( $options ) && isset( $visitor_conditions[ $options['type'] ]['check'] ) ) {
240 $check = $visitor_conditions[ $options['type'] ]['check'];
241 } else {
242 return true;
243 }
244
245 // call frontend check callback.
246 if ( method_exists( $check[0], $check[1] ) ) {
247 return call_user_func( [ $check[0], $check[1] ], $options, $ad );
248 }
249
250 return true;
251 }
252
253 /**
254 * Render the list of set visisor conditions
255 *
256 * @param array $set_conditions array of existing conditions.
257 * @param string $list_target ID of the list with the conditions.
258 * @param string $form_name prefix of the form.
259 */
260 public static function render_condition_list( array $set_conditions, $list_target = '', $form_name = '' ) {
261
262 $conditions = self::get_instance()->get_conditions();
263
264 // use default form name if not given explicitly.
265 // TODO: create a random form name, in case we have more than one form per page and the parameter is not given.
266 $form_name = ! $form_name ? self::FORM_NAME : $form_name;
267
268 include ADVADS_ABSPATH . 'admin/views/conditions/visitor-conditions-list.php';
269
270 /**
271 * Prepare condition form
272 *
273 * @todo if needed, allow to disable the form to add new conditions
274 */
275
276 // add mockup conditions if add-ons are missing.
277 $pro_conditions = [];
278 if ( ! defined( 'AAP_VERSION' ) ) {
279 $pro_conditions[] = __( 'browser language', 'advanced-ads' );
280 $pro_conditions[] = __( 'cookie', 'advanced-ads' );
281 $pro_conditions[] = __( 'max. ad clicks', 'advanced-ads' );
282 $pro_conditions[] = __( 'max. ad impressions', 'advanced-ads' );
283 $pro_conditions[] = __( 'new visitor', 'advanced-ads' );
284 $pro_conditions[] = __( 'page impressions', 'advanced-ads' );
285 $pro_conditions[] = __( 'geo location', 'advanced-ads' );
286 $pro_conditions[] = __( 'referrer url', 'advanced-ads' );
287 $pro_conditions[] = __( 'user agent', 'advanced-ads' );
288 $pro_conditions[] = __( 'user can (capabilities)', 'advanced-ads' );
289 $pro_conditions[] = __( 'user role', 'advanced-ads' );
290 $pro_conditions[] = __( 'browser width', 'advanced-ads' );
291 }
292
293 asort( $pro_conditions );
294
295 // the action to call using AJAX.
296 $action = 'load_visitor_conditions_metabox';
297 $connector_default = 'and';
298
299 $empty_options = ! is_array( $set_conditions ) || ! count( $set_conditions );
300
301 include ADVADS_ABSPATH . 'admin/views/conditions/conditions-form.php';
302 }
303
304 /**
305 * Render connector option
306 *
307 * @param int $index incremental index of the options.
308 * @param string $value connector value.
309 * @param string $form_name name of the form, falls back to class constant.
310 *
311 * @return string HTML of the connector option
312 * @todo combine this with the same function used for Display Conditions
313 *
314 * @since 1.7.0.4
315 */
316 public static function render_connector_option( $index, $value, $form_name ) {
317
318 $label = ( 'or' === $value ) ? __( 'or', 'advanced-ads' ) : __( 'and', 'advanced-ads' );
319
320 $name = self::get_form_name_with_index( $form_name, $index );
321
322 // create random value to identify the form field.
323 $rand = uniqid();
324
325 return '<input type="checkbox" name="' . $name . '[connector]' . '" value="or" id="advads-conditions-' . // phpcs:ignore
326 $index . '-connector-' . $rand . '"' .
327 checked( 'or', $value, false )
328 . '><label for="advads-conditions-' . $index . '-connector-' . $rand . '">' . $label . '</label>';
329 }
330
331 /**
332 * Helper function to the name of a form field.
333 * falls back to default
334 *
335 * @param string $form_name form name if submitted.
336 * @param int $index index of the condition.
337 *
338 * @return string
339 */
340 public static function get_form_name_with_index( $form_name = '', $index = 0 ) {
341 return ! empty( $form_name ) ? $form_name . '[' . $index . ']' : self::FORM_NAME . '[' . $index . ']';
342 }
343
344 /**
345 * Check whether device visitor condition in frontend is true.
346 *
347 * @param array $options options of the condition.
348 *
349 * @return bool
350 */
351 public static function check_device( $options = [] ) {
352 if ( ! array_key_exists( 'value', $options ) ) {
353 return self::check_mobile( $options );
354 }
355
356 $mobile_detect = new \Detection\MobileDetect();
357 // register callbacks to decide whether device "is".
358 $callbacks = array_intersect_key(
359 [
360 'mobile' => function () use ( $mobile_detect ) {
361 return $mobile_detect->isMobile() && ! $mobile_detect->isTablet();
362 },
363 'tablet' => function () use ( $mobile_detect ) {
364 return $mobile_detect->isTablet();
365 },
366 'desktop' => function () use ( $mobile_detect ) {
367 return ! $mobile_detect->isTablet() && ! $mobile_detect->isMobile();
368 },
369 ],
370 array_flip( $options['value'] )
371 );
372
373 // Only call devices that are part of the condition.
374 array_walk(
375 $callbacks,
376 function ( callable &$value ) {
377 $value = $value();
378 }
379 );
380
381 return array_filter( $callbacks ) !== [];
382 }
383
384 /**
385 * Check mobile visitor condition in frontend
386 *
387 * @param array $options options of the condition.
388 * @deprecated -- Only used if new options hasn't been saved
389 *
390 * @return bool
391 */
392 private static function check_mobile( $options ) {
393 if ( ! isset( $options['operator'] ) ) {
394 return true;
395 }
396
397 switch ( $options['operator'] ) {
398 case 'is':
399 if ( ! wp_is_mobile() ) {
400 return false;
401 }
402 break;
403 case 'is_not':
404 if ( wp_is_mobile() ) {
405 return false;
406 }
407 break;
408 }
409
410 return true;
411 }
412
413 /**
414 * Check mobile visitor condition in frontend
415 *
416 * @param array $options options of the condition.
417 *
418 * @return bool true if can be displayed
419 * @since 1.6.3
420 */
421 public static function check_logged_in( $options = [] ) {
422
423 if ( ! isset( $options['operator'] ) ) {
424 return true;
425 }
426
427 switch ( $options['operator'] ) {
428 case 'is':
429 if ( ! is_user_logged_in() ) {
430 return false;
431 }
432 break;
433 case 'is_not':
434 if ( is_user_logged_in() ) {
435 return false;
436 }
437 break;
438 }
439
440 return true;
441 }
442
443 /**
444 * Helper for check with strings
445 *
446 * @param string $string string that is going to be checked.
447 * @param array $options options of this condition.
448 *
449 * @return bool true if ad can be displayed
450 * @since 1.6.3
451 */
452 public static function helper_check_string( $string = '', $options = [] ) { // phpcs:ignore
453 if ( ! isset( $options['operator'] ) || empty( $options['value'] ) ) {
454 return true;
455 }
456
457 $operator = $options['operator'];
458 $string = (string) maybe_serialize( $string );
459 $value = (string) maybe_serialize( $options['value'] );
460
461 // check the condition by mode and bool.
462 $condition = true;
463 switch ( $operator ) {
464 // referrer contains string on any position.
465 case 'contain':
466 $condition = stripos( $string, $value ) !== false;
467 break;
468 // referrer does not contain string on any position.
469 case 'contain_not':
470 $condition = stripos( $string, $value ) === false;
471 break;
472 // referrer starts with the string.
473 case 'start':
474 $condition = stripos( $string, $value ) === 0;
475 break;
476 // referrer does not start with the string.
477 case 'start_not':
478 $condition = stripos( $string, $value ) !== 0;
479 break;
480 // referrer ends with the string.
481 case 'end':
482 $condition = substr( $string, - strlen( $value ) ) === $value;
483 break;
484 // referrer does not end with the string.
485 case 'end_not':
486 $condition = substr( $string, - strlen( $value ) ) !== $value;
487 break;
488 // referrer is equal to the string.
489 case 'match':
490 // strings do match, but should not or not match but should.
491 $condition = strcasecmp( $value, $string ) === 0;
492 break;
493 // referrer is not equal to the string.
494 case 'match_not':
495 // strings do match, but should not or not match but should.
496 $condition = strcasecmp( $value, $string ) !== 0;
497 break;
498 case 'regex':
499 case 'regex_not':
500 $condition = @preg_match( sprintf( '/%s/', $value ), $string ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
501 // If the return value is `false`, the regex is incorrect.
502 if ( false === $condition ) {
503 Advanced_Ads::log( "Advanced Ads: regular expression '$value' in visitor condition is broken." );
504 break;
505 }
506
507 if ( 'regex_not' === $operator ) {
508 $condition = ! $condition;
509 }
510 break;
511 }
512
513 return $condition;
514 }
515 }
516