PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.25
Advanced Ads – Ad Manager & AdSense v2.0.25
2.0.25 2.0.24 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 / display-conditions.php
advanced-ads / classes Last commit date
ad-health-notices.php 1 month ago checks.php 3 months ago display-conditions.php 1 day ago filesystem.php 1 month ago frontend_checks.php 1 week ago inline-css.php 1 year ago utils.php 1 week ago visitor-conditions.php 1 day ago
display-conditions.php
1522 lines
1 <?php // phpcs:ignore WordPress.Files.FileName
2
3 use AdvancedAds\Abstracts\Ad;
4 use AdvancedAds\Framework\Utilities\Params;
5
6 /**
7 * Display Conditions under which to (not) show an ad
8 *
9 * @since 1.7
10 */
11 class Advanced_Ads_Display_Conditions {
12 /**
13 * Conditions
14 *
15 * Registered display conditions.
16 *
17 * @var array
18 */
19 public $conditions;
20
21 /**
22 * Start of name in form elements
23 */
24 const FORM_NAME = 'advanced_ad[conditions]';
25
26 /**
27 * List of query var values
28 *
29 * @var array
30 */
31 protected static $query_var_keys = [
32 'is_archive',
33 'is_search',
34 'is_home',
35 'is_404',
36 'is_attachment',
37 'is_singular',
38 'is_front_page',
39 'is_feed',
40 ];
41
42 /**
43 * List of options for the General Conditions
44 *
45 * @var array
46 */
47
48 protected static $default_general_keys = [
49 'is_front_page',
50 'is_singular',
51 'is_archive',
52 'is_search',
53 'is_404',
54 'is_attachment',
55 'is_main_query',
56 'is_feed',
57 'is_rest_api',
58 ];
59
60 /**
61 * Instance of Advanced_Ads_Display_Conditions
62 *
63 * @return Advanced_Ads_Display_Conditions
64 */
65 public static function get_instance() {
66 static $instance = null;
67 if ( null === $instance ) {
68 $instance = new Advanced_Ads_Display_Conditions();
69 }
70
71 return $instance;
72 }
73
74 /**
75 * Constructor
76 */
77 private function __construct() {
78 add_filter( 'advanced-ads-ad-select-args', [ $this, 'ad_select_args_callback' ] );
79 add_filter( 'advanced-ads-can-display-ad', [ $this, 'can_display' ], 10, 2 );
80
81 // Register conditions with init hook, register as late as possible so other plugins can use the same hook to add new taxonomies.
82 add_action( 'init', [ $this, 'register_conditions' ], 100 );
83 }
84
85 /**
86 * Register display conditions
87 *
88 * @since 1.7.1.4
89 */
90 public function register_conditions() {
91 $conditions = [
92 // Post types condition.
93 'posttypes' => [
94 'label' => __( 'post type', 'advanced-ads' ),
95 'description' => __( 'Choose the public post types on which to display the ad.', 'advanced-ads' ),
96 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_post_type' ], // callback to generate the metabox.
97 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_post_type' ], // callback for frontend check.
98 ],
99 // Post id condition.
100 'postids' => [
101 'label' => __( 'specific pages', 'advanced-ads' ),
102 'description' => __( 'Choose on which individual posts, pages and public post type pages you want to display or hide ads.', 'advanced-ads' ),
103 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_post_ids' ], // callback to generate the metabox.
104 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_post_ids' ], // callback for frontend check.
105 ],
106 // General conditions.
107 'general' => [
108 'label' => __( 'general conditions', 'advanced-ads' ),
109 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_general' ], // callback to generate the metabox.
110 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_general' ], // callback for frontend check.
111 ],
112 // Author conditions.
113 'author' => [
114 'label' => __( 'author', 'advanced-ads' ),
115 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_author' ], // callback to generate the metabox.
116 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_author' ], // callback for frontend check.
117 ],
118 // Display ads only in content older or younger than a specific age.
119 'content_age' => [
120 'label' => __( 'content age', 'advanced-ads' ),
121 'description' => __( 'Display ads based on age of the page.', 'advanced-ads' ),
122 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_content_age' ], // callback to generate the metabox.
123 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_content_age' ], // callback for frontend check.
124 ],
125 // Condition for taxonomies in general.
126 'taxonomy' => [
127 'label' => __( 'taxonomy', 'advanced-ads' ),
128 'description' => __( 'Display ads based on the taxonomy of an archive page.', 'advanced-ads' ),
129 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_taxonomies' ], // callback to generate the metabox.
130 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_taxonomy' ], // callback for frontend check.
131 ],
132 ];
133
134 // Register a condition for each taxonomy for posts.
135 $taxonomies = get_taxonomies(
136 [
137 'public' => true,
138 'publicly_queryable' => true,
139 ],
140 'objects',
141 'or'
142 );
143
144 $tax_label_counts = [];
145
146 foreach ( $taxonomies as $_tax ) :
147 if ( in_array( $_tax->name, [ 'advanced_ads_groups' ], true ) ) {
148 continue;
149 }
150
151 /**
152 * Count names of taxonomies and adjust label if there are duplicates.
153 * we can’t use `array_count_values` here because "label" might not always be a simple string (though it should be)
154 */
155 $tax_label_counts[ $_tax->label ] = isset( $tax_label_counts[ $_tax->label ] ) ? $tax_label_counts[ $_tax->label ] + 1 : $tax_label_counts[ $_tax->label ] = 1;
156
157 // add tax type to label if we find it multiple times.
158 if ( $tax_label_counts[ $_tax->label ] < 2 ) {
159 $archive_label = $_tax->label;
160 $label = $archive_label;
161 } else {
162 $label = sprintf( '%s (%s)', $_tax->label, $_tax->name );
163 $archive_label = sprintf( '%s (%s)', $_tax->labels->singular_name, $_tax->name );
164 }
165
166 $conditions[ 'taxonomy_' . $_tax->name ] = [
167 'label' => $label,
168 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_taxonomy_terms' ], // callback to generate the metabox.
169 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_taxonomies' ], // callback for frontend check.
170 'taxonomy' => $_tax->name, // unique for this type: the taxonomy name.
171 ];
172
173 $conditions[ 'archive_' . $_tax->name ] = [
174 'label' => sprintf(
175 /* translators: %s is a label of an archive page. */
176 __( 'archive: %s', 'advanced-ads' ),
177 $archive_label
178 ),
179 'metabox' => [ 'Advanced_Ads_Display_Conditions', 'metabox_taxonomy_terms' ], // callback to generate the metabox.
180 'check' => [ 'Advanced_Ads_Display_Conditions', 'check_taxonomy_archive' ], // callback for frontend check.
181 'taxonomy' => $_tax->name, // unique for this type: the taxonomy name.
182 ];
183 endforeach;
184
185 $this->conditions = apply_filters( 'advanced-ads-display-conditions', $conditions );
186 }
187
188 /**
189 * Get the conditions array alphabetically by label
190 *
191 * @since 1.8.12
192 */
193 public function get_conditions() {
194 uasort(
195 $this->conditions,
196 static function ( $a, $b ) {
197 if ( ! isset( $a['label'], $b['label'] ) ) {
198 return 0;
199 }
200
201 return strcmp( strtolower( $a['label'] ), strtolower( $b['label'] ) );
202 }
203 );
204
205 return $this->conditions;
206 }
207
208 /**
209 * Controls frontend checks for conditions
210 *
211 * @param array $options options of the condition.
212 * @param Ad $ad Ad object.
213 *
214 * @return bool false, if ad can’t be delivered
215 */
216 public static function frontend_check( $options = [], $ad = false ) {
217 // Early bail!!
218 if ( ! $ad ) {
219 return true;
220 }
221
222 $display_conditions = self::get_instance()->conditions;
223
224 if ( is_array( $options ) && isset( $options['type'] ) && isset( $display_conditions[ $options['type'] ]['check'] ) ) {
225 $check = $display_conditions[ $options['type'] ]['check'];
226 } else {
227 return true;
228 }
229
230 // call frontend check callback.
231 if ( method_exists( $check[0], $check[1] ) ) {
232 return call_user_func( [ $check[0], $check[1] ], $options, $ad );
233 }
234
235 return true;
236 }
237
238 /**
239 * Render the list of set display conditions.
240 *
241 * @param array $set_conditions array of existing conditions.
242 * @param string $list_target ID of the list with the conditions.
243 * @param string $form_name prefix of the form field name attribute.
244 * @param array $options {
245 * Optional. Render options.
246 *
247 * @type string/array $in May be:
248 * - set to `all` (default) to include all conditions, including not global.
249 * - set to `global` to include all conditions, except for not global.
250 * - set to array of condition ID's to include only them.
251 * }
252 */
253 public static function render_condition_list( array $set_conditions, $list_target = '', $form_name = '', $options = [] ) {
254 $conditions = self::get_instance()->get_conditions();
255
256 if ( isset( $options['in'] ) ) {
257 if ( 'global' === $options['in'] ) {
258 $conditions = array_filter(
259 $conditions,
260 function ( $condition ) {
261 return ! isset( $condition['options']['global'] ) || $condition['options']['global'];
262 }
263 );
264 } elseif ( is_array( $options['in'] ) ) {
265 // Include already set condition types.
266 $set_types = [];
267 foreach ( $set_conditions as $set_condition ) {
268 if ( isset( $set_condition['type'] ) ) {
269 $set_types[] = $set_condition['type'];
270 }
271 }
272
273 $in = array_merge( $options['in'], $set_types );
274 $conditions = array_intersect_key( $conditions, array_flip( $in ) );
275 }
276 }
277
278 // use default form name if not given explicitly.
279 // @todo create a random form name, in case we have more than one form per page and the parameter is not given.
280 $form_name = ! $form_name ? self::FORM_NAME : $form_name;
281
282 include ADVADS_ABSPATH . 'admin/views/conditions/display-conditions-list.php';
283
284 /**
285 * Prepare condition form
286 *
287 * @todo if needed, allow to disable the form to add new conditions
288 */
289
290 // add mockup conditions if add-ons are missing.
291 $pro_conditions = [];
292 if ( ! defined( 'AAP_VERSION' ) ) {
293 $pro_conditions[] = __( 'parent page', 'advanced-ads' );
294 $pro_conditions[] = __( 'post meta', 'advanced-ads' );
295 $pro_conditions[] = __( 'page template', 'advanced-ads' );
296 $pro_conditions[] = __( 'url parameters', 'advanced-ads' );
297 }
298 if ( ! defined( 'AAR_VERSION' ) ) {
299 $pro_conditions[] = __( 'accelerated mobile pages', 'advanced-ads' );
300 }
301 asort( $pro_conditions );
302
303 // the action to call using AJAX.
304 $action = 'load_display_conditions_metabox';
305 $connector_default = 'or';
306
307 $empty_options = ! is_array( $set_conditions ) || ! count( $set_conditions );
308
309 include ADVADS_ABSPATH . 'admin/views/conditions/conditions-form.php';
310 }
311
312 /**
313 * Render connector option
314 *
315 * @param int $index incremental index of the options.
316 * @param string $value connector value.
317 * @param string $form_name name of the form, falls back to class constant.
318 *
319 * @return string HTML for connector option.
320 * @since 1.7.0.4
321 */
322 public static function render_connector_option( $index, $value, $form_name ) {
323 $label = ( 'or' === $value ) ? __( 'or', 'advanced-ads' ) : __( 'and', 'advanced-ads' );
324
325 $name = self::get_form_name_with_index( $form_name, $index );
326
327 // create random value to identify the form field.
328 $rand = uniqid();
329
330 return sprintf(
331 "<input style='display:none' type='checkbox' name='%s[connector]' value='or' id='%s' %s><label for='%s'>%s</label>",
332 esc_attr( $name ),
333 esc_attr( "advads-conditions-$index-connector-$rand" ),
334 checked( 'or', $value, false ),
335 esc_attr( "advads-conditions-$index-connector-$rand" ),
336 esc_html( $label )
337 );
338 }
339
340 /**
341 * Render type field
342 *
343 * @param string $type type of the current condition.
344 * @param string $name name of the form, falls back to class constant.
345 */
346 public static function render_type_field( $type, $name ) {
347 ?>
348 <input type="hidden" name="<?php echo esc_attr( $name ); ?>[type]" value="<?php echo esc_attr( $type ); ?>"/>
349 <?php
350 }
351
352 /**
353 * Helper function to the name of a form field.
354 * falls back to default
355 *
356 * @param string $form_name form name if submitted.
357 * @param int $index index of the condition.
358 *
359 * @return string
360 */
361 public static function get_form_name_with_index( $form_name = '', $index = 0 ) {
362 return ! empty( $form_name ) ? $form_name . '[' . $index . ']' : self::FORM_NAME . '[' . $index . ']';
363 }
364
365 /**
366 * Callback to display the metabox for the post type condition
367 *
368 * @param array $options options of the condition.
369 * @param int $index index of the condition.
370 * @param string $form_name name of the form, falls back to class constant.
371 */
372 public static function metabox_post_type( $options, $index = 0, $form_name = '' ) {
373 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
374 return;
375 }
376
377 $type_options = self::get_instance()->conditions;
378
379 if ( ! isset( $type_options[ $options['type'] ] ) ) {
380 return;
381 }
382
383 // get values and select operator based on previous settings.
384 $operator = isset( $options['operator'] ) && 'is_not' === $options['operator'] ? 'is_not' : 'is';
385 $values = isset( $options['value'] ) && is_array( $options['value'] ) ? $options['value'] : [];
386
387 // form name basis.
388 $name = self::get_form_name_with_index( $form_name, $index );
389 $rand = uniqid();
390
391 self::render_type_field( $options['type'], $name );
392
393 // load operator template.
394 include ADVADS_ABSPATH . 'admin/views/conditions/condition-operator.php';
395
396 // set defaults.
397 $post_types = get_post_types(
398 [
399 'public' => true,
400 'publicly_queryable' => true,
401 ],
402 'object',
403 'or'
404 );
405 ?>
406 <div class="advads-conditions-single advads-buttonset">
407 <?php
408 $type_label_counts = array_count_values( wp_list_pluck( $post_types, 'label' ) );
409
410 foreach ( $post_types as $_type_id => $_type ) {
411 if ( in_array( $_type_id, $values, true ) ) {
412 $_val = 1;
413 } else {
414 $_val = 0;
415 }
416
417 if ( $type_label_counts[ $_type->label ] < 2 ) {
418 $_label = $_type->label;
419 } else {
420 $_label = sprintf( '%s (%s)', $_type->label, $_type_id );
421 }
422 $field_id = "advads-conditions-$_type_id-$rand";
423 printf(
424 "<label class='button' for='%s'>%s</label><input type='checkbox' id='%s' name='%s' %s value='%s'>",
425 esc_attr( $field_id ),
426 esc_html( $_label ),
427 esc_attr( $field_id ),
428 esc_attr( "{$name}[value][]" ),
429 checked( $_val, 1, false ),
430 esc_attr( $_type_id )
431 );
432 }
433 include ADVADS_ABSPATH . 'admin/views/conditions/not-selected.php';
434 ?>
435 </div>
436 <?php
437 }
438
439 /**
440 * Callback to display the metabox for the author condition
441 *
442 * @param array $options options of the condition.
443 * @param int $index index of the condition.
444 * @param string $form_name name of the form, falls back to class constant.
445 */
446 public static function metabox_author( $options, $index = 0, $form_name = '' ) {
447
448 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
449 return;
450 }
451
452 $type_options = self::get_instance()->conditions;
453
454 if ( ! isset( $type_options[ $options['type'] ] ) ) {
455 return;
456 }
457
458 // get values and select operator based on previous settings.
459 $operator = isset( $options['operator'] ) && 'is_not' === $options['operator'] ? 'is_not' : 'is';
460 $values = isset( $options['value'] ) && is_array( $options['value'] ) ? $options['value'] : [];
461
462 // form name basis.
463 $name = self::get_form_name_with_index( $form_name, $index );
464 $rand = uniqid();
465
466 self::render_type_field( $options['type'], $name );
467
468 // load operator template.
469 include ADVADS_ABSPATH . 'admin/views/conditions/condition-operator.php';
470
471 // set defaults.
472 $max_authors = absint( apply_filters( 'advanced-ads-admin-max-terms', 50 ) );
473 $args = [
474 'orderby' => 'nicename',
475 ];
476 if ( version_compare( get_bloginfo( 'version' ), '5.9' ) > -1 ) {
477 $args['capability'] = [ 'edit_posts' ];
478 } else {
479 $args['who'] = 'authors';
480 }
481 $authors = get_users( $args );
482
483 include ADVADS_ABSPATH . 'admin/views/conditions/condition-author.php';
484 }
485
486 /**
487 * Callback to display the metabox for the taxonomy archive pages
488 *
489 * @param array $options options of the condition.
490 * @param int $index index of the condition.
491 * @param string $form_name name of the form, falls back to class constant.
492 */
493 public static function metabox_taxonomy_terms( $options, $index = 0, $form_name = '' ) {
494
495 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
496 return;
497 }
498
499 $type_options = self::get_instance()->conditions;
500
501 // don’t use if this is not a taxonomy.
502 if ( ! isset( $type_options[ $options['type'] ] ) || ! isset( $type_options[ $options['type'] ]['taxonomy'] ) ) {
503 return;
504 }
505
506 $taxonomy = get_taxonomy( $type_options[ $options['type'] ]['taxonomy'] );
507 if ( false === $taxonomy ) {
508 return;
509 }
510
511 // get values and select operator based on previous settings.
512 $operator = ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) ? 'is_not' : 'is';
513 $values = ( isset( $options['value'] ) && is_array( $options['value'] ) ) ? $options['value'] : [];
514
515 // limit the number of terms so many terms don’t break the admin page.
516 $max_terms = absint( apply_filters( 'advanced-ads-admin-max-terms', 50 ) );
517
518 // form name basis.
519 $name = self::get_form_name_with_index( $form_name, $index );
520
521 self::render_type_field( $options['type'], $name );
522
523 // load operator template.
524 include ADVADS_ABSPATH . 'admin/views/conditions/condition-operator.php';
525
526 /**
527 * Allow adding markup on the condition table
528 *
529 * @param array $options options of the current condition being rendered.
530 */
531 do_action( 'advads-conditions-operator-after', $options );
532
533 ?>
534 <div class="advads-conditions-single advads-buttonset">
535 <?php
536 $terms = self::display_term_list( $taxonomy, $values, $name . '[value][]', $max_terms, $index );
537 if ( empty( $terms ) ) {
538 include ADVADS_ABSPATH . 'admin/views/conditions/no-option.php';
539 }
540 ?>
541 </div>
542 <?php
543 }
544
545 /**
546 * Callback to display the metabox for the taxonomies
547 *
548 * @param array $options options of the condition.
549 * @param int $index index of the condition.
550 * @param string $form_name name of the form, falls back to class constant.
551 */
552 public static function metabox_taxonomies( $options, $index = 0, $form_name = '' ) {
553
554 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
555 return;
556 }
557
558 $taxonomies = get_taxonomies( [ 'public' => 1 ], 'objects' );
559
560 $name = self::get_form_name_with_index( $form_name, $index );
561 $rand = uniqid();
562
563 // get values and select operator based on previous settings.
564 $operator = ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) ? 'is_not' : 'is';
565 $values = ( isset( $options['value'] ) && is_array( $options['value'] ) ) ? $options['value'] : [];
566
567 self::render_type_field( $options['type'], $name );
568
569 ?>
570 <div class="advads-conditions-single advads-buttonset">
571 <?php
572 $tax_label_counts = array_count_values( wp_list_pluck( $taxonomies, 'label' ) );
573
574 foreach ( $taxonomies as $_taxonomy_id => $_taxonomy ) :
575 $_val = in_array( $_taxonomy_id, $values, true ) ? 1 : 0;
576
577 if ( $tax_label_counts[ $_taxonomy->label ] < 2 ) {
578 $_label = $_taxonomy->label;
579 } else {
580 $_label = sprintf( '%s (%s)', $_taxonomy->label, $_taxonomy_id );
581 }
582
583 $field_id = "advads-conditions-$_taxonomy_id-$rand";
584 printf(
585 "<label class='button' for='%s'>%s</label><input type ='checkbox' id='%s' name='%s' %s value='%s'>",
586 esc_attr( $field_id ),
587 esc_html( $_label ),
588 esc_attr( $field_id ),
589 esc_attr( "{$name}[value][]" ),
590 checked( $_val, 1, false ),
591 esc_attr( $_taxonomy_id )
592 );
593 endforeach;
594 include ADVADS_ABSPATH . 'admin/views/conditions/not-selected.php';
595 ?>
596 </div>
597 <?php
598 }
599
600 /**
601 * Display terms of a taxonomy for choice
602 *
603 * @param object $taxonomy taxonomy object.
604 * @param array $checked ids of checked terms.
605 * @param string $inputname name of the input field.
606 * @param int $max_terms maximum number of terms to show.
607 * @param int $index index of the conditions group.
608 *
609 * @return array|int|WP_Error
610 */
611 public static function display_term_list( $taxonomy, $checked = [], $inputname = '', $max_terms = 50, $index = 0 ) { // phpcs:ignore
612 $terms = get_terms(
613 [
614 'taxonomy' => $taxonomy->name,
615 'hide_empty' => false,
616 'number' => $max_terms,
617 ]
618 );
619 $rand = uniqid();
620
621 if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) :
622 // display search field if the term limit is reached.
623 if ( count( $terms ) === $max_terms ) :
624
625 // query active terms.
626 if ( is_array( $checked ) && count( $checked ) ) {
627 $checked_terms = get_terms(
628 [
629 'hide_empty' => false,
630 'include' => $checked,
631 'taxonomy' => $taxonomy->name,
632 ]
633 );
634 // phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen, Squiz.PHP.EmbeddedPhp.ContentAfterOpen, Squiz.PHP.EmbeddedPhp.ContentBeforeEnd, Squiz.PHP.EmbeddedPhp.ContentAfterEnd -- Prevent whitespaces between labels
635 ?>
636 <div class="advads-conditions-terms-buttons dynamic-search"><?php
637 foreach ( $checked_terms as $_checked_term ) :
638 ?><label class="button advads-button advads-ui-state-active"><span class="advads-button-text"><?php
639 echo esc_html( $_checked_term->name ); ?><input type="hidden" name="<?php echo esc_attr( $inputname ); ?>"
640 value="<?php echo esc_attr( $_checked_term->term_id ); ?>"></span></label><?php
641 endforeach;
642 ?></div><?php
643 // phpcs:enable
644 } else {
645 ?>
646 <div class="advads-conditions-terms-buttons dynamic-search"></div>
647 <?php
648 }
649
650 printf(
651 "<span class='advads-conditions-terms-show-search button' title='%s'>+</span><br>",
652 esc_attr_x( 'add more terms', 'display the terms search field on ad edit page', 'advanced-ads' )
653 );
654 printf(
655 "<input type='text' class='advads-conditions-terms-search' data-tag-name='%s' data-input-name='%s' placeholder='%s'>",
656 esc_attr( $taxonomy->name ),
657 esc_attr( $inputname ),
658 esc_attr__( 'term name or id', 'advanced-ads' )
659 );
660 else :
661 foreach ( $terms as $_term ) {
662 $field_id = "advads-conditions-$_term->term_id-$rand";
663 printf(
664 "<input type='checkbox' id='%s' name='%s' value='%s' %s><label for='%s'>%s</label>",
665 esc_attr( $field_id ),
666 esc_attr( $inputname ),
667 esc_attr( $_term->term_id ),
668 checked( self::in_array( $_term->term_id, $checked ), true, false ),
669 esc_attr( $field_id ),
670 esc_html( $_term->name )
671 );
672 }
673 include ADVADS_ABSPATH . 'admin/views/conditions/not-selected.php';
674 endif;
675 endif;
676
677 return $terms;
678 }
679
680 /**
681 * Callback to display the metabox for the taxonomy archive pages
682 *
683 * @param array $options options of the condition.
684 * @param int $index index of the condition.
685 * @param string $form_name name of the form, falls back to class constant.
686 */
687 public static function metabox_post_ids( $options, $index = 0, $form_name = '' ) {
688
689 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
690 return;
691 }
692
693 // get values and select operator based on previous settings.
694 $operator = ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) ? 'is_not' : 'is';
695 $values = ( isset( $options['value'] ) && is_array( $options['value'] ) ) ? $options['value'] : [];
696
697 // form name basis.
698 $name = self::get_form_name_with_index( $form_name, $index );
699
700 self::render_type_field( $options['type'], $name );
701
702 // load operator template.
703 include ADVADS_ABSPATH . 'admin/views/conditions/condition-operator.php';
704
705 ?>
706 <div class="advads-conditions-single advads-buttonset advads-conditions-postid-buttons">
707 <?php
708 // Query active post ids.
709 // phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen, Squiz.PHP.EmbeddedPhp.ContentAfterOpen, Squiz.PHP.EmbeddedPhp.ContentBeforeEnd, Squiz.PHP.EmbeddedPhp.ContentAfterEnd -- Prevent whitespaces between labels
710 if ( [] !== $values ) {
711 $args = [
712 'post_type' => 'any',
713 'post__in' => $values,
714 'posts_per_page' => - 1,
715 'order' => 'ASC',
716 'order_by' => 'title',
717
718 ];
719
720 $the_query = new WP_Query( $args );
721 $titles_types = [];
722 $identical_data = [];
723
724 foreach ( $the_query->posts as $post ) {
725 // Check if post_title and post_type is already in the $titles_types array.
726 $combined_data = [ $post->post_title, $post->post_type ];
727 if ( in_array( $combined_data, $titles_types, true ) ) {
728 $identical_data[] = $combined_data;
729 } else {
730 $titles_types[] = $combined_data;
731 }
732 }
733
734 while ( $the_query->have_posts() ) {
735 $the_query->next_post();
736 $combined_data = [ $the_query->post->post_title, $the_query->post->post_type ];
737 $display_text = sprintf( '%s (%s)', $combined_data[0], $combined_data[1] );
738 // add advads-tooltip if same title & type found.
739 if ( in_array( $combined_data, $identical_data, true ) ) {
740 $tooltip = __( 'ID', 'advanced-ads' ) . ': ' . $the_query->post->ID . '<br>' . __( 'Status', 'advanced-ads' ) . ': ' . $the_query->post->post_status . '<br>';
741 if ( 'publish' === $the_query->post->post_status ) {
742 $tooltip .= __( 'Published', 'advanced-ads' ) . ': ' . $the_query->post->post_date;
743 } else {
744 $tooltip .= __( 'Last Modified', 'advanced-ads' ) . ': ' . $the_query->post->post_modified;
745 }
746 $display_text .= '&nbsp;<div class="advads-help advads-help-info"><div class="advads-tooltip advads-text-left">' . $tooltip . '</div></div>';
747 }
748 ?>
749 <label class="button advads-button advads-ui-state-active">
750 <span class="advads-button-text">
751 <?php echo wp_kses_post( $display_text ); ?>
752 </span>
753 <input type="hidden" name="<?php echo esc_attr( $name ); ?>[value][]" value="<?php echo esc_attr( $the_query->post->ID ); ?>">
754 </label>
755 <?php
756 }
757 }
758 printf(
759 "<span class='advads-conditions-postids-show-search button' style='%s'>+</span>",
760 empty( $values ) ? 'display:none;' : ''
761 );
762
763 printf(
764 "<p class='advads-conditions-postids-search-line'><input type='text' class='advads-display-conditions-individual-post' style='%s' placeholder='%s' data-field-name='%s' />%s</p></div>",
765 ! empty( $values ) ? 'display:none;' : '',
766 esc_attr__( 'title or id', 'advanced-ads' ),
767 esc_attr( $name ),
768 wp_kses(
769 wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false, false ),
770 [
771 'input' => [
772 'type' => true,
773 'id' => true,
774 'name' => true,
775 'class' => true,
776 'value' => true,
777 ],
778 ]
779 )
780 );
781 // phpcs:enable
782 }
783
784 /**
785 * Callback to display the metabox for the general display conditions
786 *
787 * @param array $options options of the condition.
788 * @param int $index index of the condition.
789 * @param string $form_name name of the form, falls back to class constant.
790 */
791 public static function metabox_general( $options, $index = 0, $form_name = '' ) {
792
793 // general conditions array.
794 $conditions = self::get_instance()->general_conditions();
795 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
796 return;
797 }
798
799 $name = self::get_form_name_with_index( $form_name, $index );
800 $values = isset( $options['value'] ) ? $options['value'] : [];
801 ?>
802 <div class="advads-conditions-single advads-buttonset">
803 <?php
804
805 self::render_type_field( $options['type'], $name );
806
807 $rand = uniqid();
808 foreach ( $conditions as $_key => $_condition ) {
809 // activate by default.
810 $value = ( [] === $values || in_array( $_key, $values, true ) ) ? 1 : 0;
811 $field_id = "advads-conditions-$_key-$rand";
812 printf(
813 "<input type='checkbox' id='%s' name='%s' %s value='%s'>",
814 esc_attr( $field_id ),
815 esc_attr( "{$name}[value][]" ),
816 checked( 1, $value, false ),
817 esc_attr( $_key )
818 );
819 printf(
820 "<label for='%s'>%s</label>",
821 esc_attr( $field_id ),
822 esc_html( $_condition['label'] )
823 );
824
825 }
826 include ADVADS_ABSPATH . 'admin/views/conditions/not-selected.php';
827 echo '</div>';
828 }
829
830 /**
831 * Retrieve the array with general conditions
832 *
833 * @return array $conditions
834 */
835 public static function general_conditions() {
836 return apply_filters(
837 'advanced-ads-display-conditions-general',
838 [
839 'is_front_page' => [
840 'label' => __( 'Home Page', 'advanced-ads' ),
841 'description' => __( 'show on Home page', 'advanced-ads' ),
842 'type' => 'radio',
843 ],
844 'is_singular' => [
845 'label' => __( 'Singular Pages', 'advanced-ads' ),
846 'description' => __( 'show on singular pages/posts', 'advanced-ads' ),
847 'type' => 'radio',
848 ],
849 'is_archive' => [
850 'label' => __( 'Archive Pages', 'advanced-ads' ),
851 'description' => __( 'show on any type of archive page (category, tag, author and date)', 'advanced-ads' ),
852 'type' => 'radio',
853 ],
854 'is_search' => [
855 'label' => __( 'Search Results', 'advanced-ads' ),
856 'description' => __( 'show on search result pages', 'advanced-ads' ),
857 'type' => 'radio',
858 ],
859 'is_404' => [
860 'label' => __( '404 Page', 'advanced-ads' ),
861 'description' => __( 'show on 404 error page', 'advanced-ads' ),
862 'type' => 'radio',
863 ],
864 'is_attachment' => [
865 'label' => __( 'Attachment Pages', 'advanced-ads' ),
866 'description' => __( 'show on attachment pages', 'advanced-ads' ),
867 'type' => 'radio',
868 ],
869 'is_main_query' => [
870 'label' => __( 'Secondary Queries', 'advanced-ads' ),
871 'description' => __( 'allow ads in secondary queries', 'advanced-ads' ),
872 'type' => 'radio',
873 ],
874 'is_feed' => [
875 'label' => __( 'RSS Feed', 'advanced-ads' ),
876 'description' => __( 'allow ads in RSS Feed', 'advanced-ads' ),
877 'type' => 'radio',
878 ],
879 'is_rest_api' => [
880 'label' => __( 'REST API', 'advanced-ads' ),
881 'description' => __( 'allow ads in REST API', 'advanced-ads' ),
882 'type' => 'radio',
883 ],
884 ]
885 );
886 }
887
888 /**
889 * Callback to display the 'content age' condition
890 *
891 * @param array $options options of the condition.
892 * @param int $index index of the condition.
893 * @param string $form_name name of the form, falls back to class constant.
894 */
895 public static function metabox_content_age( $options, $index = 0, $form_name = '' ) {
896 if ( ! isset( $options['type'] ) || '' === $options['type'] ) {
897 return;
898 }
899
900 $type_options = self::get_instance()->conditions;
901
902 if ( ! isset( $type_options[ $options['type'] ] ) ) {
903 return;
904 }
905
906 // form name basis.
907 $name = self::get_form_name_with_index( $form_name, $index );
908
909 $operator = isset( $options['operator'] ) ? $options['operator'] : 'older_than';
910 $value = ( isset( $options['value'] ) && is_numeric( $options['value'] ) ) ? (float) $options['value'] : 0;
911
912 self::render_type_field( $options['type'], $name );
913
914 ?>
915 <select name="<?php echo esc_attr( $name ); ?>[operator]">
916 <option value="older_than" <?php selected( 'older_than', $operator ); ?>><?php esc_html_e( 'older than', 'advanced-ads' ); ?></option>
917 <option value="younger_than" <?php selected( 'younger_than', $operator ); ?>><?php esc_html_e( 'younger than', 'advanced-ads' ); ?></option>
918 </select>
919
920 <input type="text" name="<?php echo esc_attr( $name ); ?>[value]" value="<?php echo esc_attr( $value ); ?>"/>
921
922 <?php esc_html_e( 'days', 'advanced-ads' ); ?>
923
924 <p class="description">
925 <?php esc_html_e( 'Display ads based on the age of a page or post.', 'advanced-ads' ); ?>
926 <a href="https://wpadvancedads.com/manual/display-ads-by-content-age/?utm_source=advanced-ads&utm_medium=link&utm_campaign=condition-content-age" class="advads-manual-link" target="_blank">
927 <?php esc_html_e( 'Manual', 'advanced-ads' ); ?>
928 </a>
929 </p>
930 <?php
931 }
932
933 /**
934 * Check post type display condition in frontend
935 *
936 * @param array $options Options of the condition.
937 * @param Ad $ad Ad instance.
938 *
939 * @return bool true if can be displayed
940 */
941 public static function check_post_type( $options, $ad ) {
942 if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) ) {
943 return false;
944 }
945
946 if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
947 $operator = 'is_not';
948 } else {
949 $operator = 'is';
950 }
951
952 $post = $ad->get_prop( 'ad_args.post' ) ?? null;
953 $post_type = $post['post_type'] ?? false;
954
955 if ( ! self::can_display_ids( $post_type, $options['value'], $operator ) ) {
956 return false;
957 }
958
959 return true;
960 }
961
962 /**
963 * Check author display condition in frontend
964 *
965 * @param array $options Options of the condition.
966 * @param Ad $ad Ad instance.
967 *
968 * @return bool true if can be displayed
969 */
970 public static function check_author( $options, $ad ) {
971 if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) ) {
972 return false;
973 }
974
975 if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
976 $operator = 'is_not';
977 } else {
978 $operator = 'is';
979 }
980
981 $post = $ad->get_prop( 'ad_args.post' ) ?? null;
982 $post_author = $post['author'] ?? false;
983
984 if ( ! self::can_display_ids( $post_author, $options['value'], $operator ) ) {
985 return false;
986 }
987
988 return true;
989 }
990
991 /**
992 * Check taxonomies display condition in frontend
993 *
994 * @param array $options Options of the condition.
995 * @param Ad $ad Ad instance.
996 *
997 * @return bool true if can be displayed
998 */
999 public static function check_taxonomies( $options, $ad ) {
1000 if ( ! isset( $options['value'] ) ) {
1001 return false;
1002 }
1003
1004 if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
1005 $operator = 'is_not';
1006 } else {
1007 $operator = 'is';
1008 }
1009
1010 $query = $ad->get_prop( 'ad_args.wp_the_query' );
1011 $post_id = $ad->get_prop( 'ad_args.post.id' );
1012
1013 // get terms of the current taxonomy.
1014 $type_options = self::get_instance()->conditions;
1015 if ( ! isset( $options['type'] ) || ! isset( $type_options[ $options['type'] ]['taxonomy'] ) ) {
1016 return true;
1017 }
1018 $taxonomy = $type_options[ $options['type'] ]['taxonomy'];
1019
1020 $terms = get_the_terms( $post_id, $taxonomy );
1021
1022 if ( is_array( $terms ) ) {
1023 foreach ( $terms as $term ) {
1024 $term_ids[] = $term->term_id;
1025 }
1026 } elseif ( false === $terms && 'is' === $operator ) {
1027 // don’t show if should show only for a specific tag.
1028 return false;
1029 } else {
1030 return true;
1031 }
1032
1033 if ( 'is' === $operator && ( ! isset( $query['is_singular'] ) || ! $query['is_singular'] ) ) {
1034 return false;
1035 } elseif ( isset( $query['is_singular'] ) && $query['is_singular'] && ! self::can_display_ids( $options['value'], $term_ids, $operator ) ) {
1036 return false;
1037 }
1038
1039 return true;
1040 }
1041
1042 /**
1043 * Check taxonomy archive display condition in frontend
1044 *
1045 * @param array $options Options of the condition.
1046 * @param Ad $ad Ad instance.
1047 *
1048 * @return bool true if can be displayed
1049 */
1050 public static function check_taxonomy_archive( $options, $ad ) {
1051 if ( ! isset( $options['value'] ) ) {
1052 return false;
1053 }
1054
1055 if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
1056 $operator = 'is_not';
1057 } else {
1058 $operator = 'is';
1059 }
1060
1061 $query = $ad->get_prop( 'ad_args.wp_the_query' );
1062
1063 // return false if operator is "is", but important query vars are not given.
1064 if ( 'is' === $operator && ( empty( $query['term_id'] ) || empty( $query['is_archive'] ) ) ) {
1065 return false;
1066 } elseif ( isset( $query['term_id'] ) && isset( $query['is_archive'] ) && $query['is_archive'] && ! self::can_display_ids( $query['term_id'], $options['value'], $operator ) ) {
1067 return false;
1068 }
1069
1070 return true;
1071 }
1072
1073 /**
1074 * Check if a specific archive belongs to a taxonomy in general (not a specific term)
1075 *
1076 * @param array $options Options of the condition.
1077 * @param Ad $ad Ad instance.
1078 *
1079 * @return bool true if can be displayed
1080 */
1081 public static function check_taxonomy( $options, $ad ) {
1082 if ( ! isset( $options['value'] ) ) {
1083 return false;
1084 }
1085
1086 if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
1087 $operator = 'is_not';
1088 } else {
1089 $operator = 'is';
1090 }
1091
1092 $query = $ad->get_prop( 'ad_args.wp_the_query' );
1093
1094 // return false if operator is "is", but important query vars are not given.
1095 if ( 'is' === $operator && ( empty( $query['taxonomy'] ) || empty( $query['is_archive'] ) ) ) {
1096 return false;
1097 } elseif ( isset( $query['taxonomy'] ) && isset( $query['is_archive'] ) && $query['is_archive'] && ! self::can_display_ids( $query['taxonomy'], $options['value'], $operator ) ) {
1098 return false;
1099 }
1100
1101 return true;
1102 }
1103
1104 /**
1105 * Check post ids display condition in frontend
1106 *
1107 * @param array $options Options of the condition.
1108 * @param Ad $ad Ad instance.
1109 *
1110 * @return bool true if can be displayed
1111 */
1112 public static function check_post_ids( $options, $ad ) {
1113 $operator = 'is';
1114 if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
1115 $operator = 'is_not';
1116 }
1117
1118 $post = $ad->get_prop( 'ad_args.post' ) ?? null;
1119 $post_id = $post['id'] ?? 0;
1120
1121 // fixes page id on BuddyPress pages.
1122 if ( 0 === $post_id && class_exists( 'BuddyPress' ) && function_exists( 'bp_current_component' ) ) {
1123 $component = bp_current_component();
1124 $bp_pages = get_option( 'bp-pages' );
1125 if ( isset( $bp_pages[ $component ] ) ) {
1126 $post_id = $bp_pages[ $component ];
1127 }
1128 }
1129
1130 /**
1131 * WooCommerce Store page fix
1132 * since WooCommerce changes the post ID of the static page selected to be the product overview page, we need to get the original page id from the WC options
1133 */
1134 if ( function_exists( 'is_shop' ) && is_shop() && isset( $options['value'] ) && is_array( $options['value'] ) ) {
1135 $post_id = wc_get_page_id( 'shop' );
1136
1137 return self::can_display_ids( $post_id, $options['value'], $operator );
1138 }
1139
1140 if ( empty( $ad->get_prop( 'ad_args.wp_the_query.is_singular' ) ) ) {
1141 return 'is_not' === $operator;
1142 }
1143
1144 if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) || ! $post_id ) {
1145 return true;
1146 }
1147
1148 return self::can_display_ids( $post_id, $options['value'], $operator );
1149 }
1150
1151 /**
1152 * Check general display conditions in frontend
1153 *
1154 * @param array $options Options of the condition.
1155 * @param Ad $ad Ad instance.
1156 *
1157 * @return bool true if can be displayed
1158 */
1159 public static function check_general( $options, $ad ) {
1160 // display by default.
1161 if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) || ! count( $options['value'] ) ) {
1162 return true;
1163 }
1164
1165 // check general conditions added by other add-ons.
1166 $result = apply_filters( 'advanced-ads-display-conditions-check-general', null, $options['value'] );
1167 if ( null !== ( $result ) ) {
1168 return $result;
1169 }
1170
1171 // skip checks, if general conditions are unchanged.
1172 if ( self::$default_general_keys === $options['value'] ) {
1173 return true;
1174 }
1175
1176 // get plugin options.
1177 $query = $ad->get_prop( 'ad_args.wp_the_query' );
1178
1179 // check main query.
1180 if ( isset( $query['is_main_query'] ) && ! $query['is_main_query'] && ! in_array( 'is_main_query', $options['value'], true ) ) {
1181 return false;
1182 }
1183
1184 if ( isset( $query['is_rest_api'] ) && $query['is_rest_api'] && ! in_array( 'is_rest_api', $options['value'], true ) ) {
1185 return false;
1186 }
1187
1188 // check home page.
1189 if (
1190 ( ( isset( $query['is_front_page'] ) && $query['is_front_page'] ) || ( isset( $query['is_home'] ) && $query['is_home'] ) )
1191 && in_array( 'is_front_page', $options['value'], true )
1192 ) {
1193 return true;
1194 } elseif ( isset( $query['is_front_page'] ) && $query['is_front_page'] && ( ! in_array( 'is_front_page', $options['value'], true ) ) ) {
1195 return false;
1196 }
1197
1198 // check common tests.
1199 foreach ( self::$query_var_keys as $_type ) {
1200 if ( 'is_main_query' !== $_type && isset( $query[ $_type ] ) && $query[ $_type ] &&
1201 in_array( $_type, $options['value'], true ) ) {
1202 return true;
1203 }
1204 }
1205
1206 return false;
1207 }
1208
1209 /**
1210 * Check 'content age' condition in frontend.
1211 *
1212 * @param array $options Options of the condition.
1213 * @param Ad $ad Ad instance.
1214 *
1215 * @return bool true if can be displayed
1216 */
1217 public static function check_content_age( $options, $ad ) { // phpcs:ignore
1218 $post = get_post();
1219 $the_id = Params::request( 'theId', 0, FILTER_VALIDATE_INT );
1220
1221 if ( ! $post && wp_doing_ajax() && $the_id &&
1222 Params::request( 'action' ) === 'advads_ad_select' &&
1223 Params::request( 'isSingular' )
1224 ) {
1225 $post = get_post( $the_id );
1226 }
1227
1228 $operator = ( isset( $options['operator'] ) && 'younger_than' === $options['operator'] ) ? 'younger_than' : 'older_than';
1229 $value = isset( $options['value'] ) ? $options['value'] : '';
1230
1231 if ( empty( $post->ID ) || empty( $value ) ) {
1232 return true;
1233 }
1234
1235 // get post publish date in unix timestamp.
1236 $publish_time = get_the_time( 'U', $post->ID );
1237
1238 // get difference from now.
1239 $diff_from_now = time() - $publish_time;
1240
1241 // check against entered age.
1242 $value_in_seconds = DAY_IN_SECONDS * $value;
1243
1244 if ( 'younger_than' === $operator ) {
1245 return $diff_from_now < $value_in_seconds;
1246 } else {
1247 return $diff_from_now > $value_in_seconds;
1248 }
1249 }
1250
1251 /**
1252 * Helper function to check for in array values
1253 *
1254 * @param mixed $id scalar (key) or array of keys as needle.
1255 * @param array $ids haystack.
1256 * @param string $type type to use for comparison. accepted values: integer|string.
1257 *
1258 * @return boolean|void void if either argument is empty
1259 */
1260 public static function in_array( $id, $ids, $type = 'integer' ) {
1261 // empty?
1262 if ( ! isset( $id ) || [] === $id ) {
1263 return;
1264 }
1265
1266 // invalid?
1267 if ( ! is_array( $ids ) ) {
1268 return;
1269 }
1270
1271 if ( ! is_array( $id ) ) {
1272 $id = 'integer' === $type ? (int) $id : (string) $id;
1273 } else {
1274 $id = array_map( 'integer' === $type ? 'intval' : 'strval', $id );
1275 }
1276
1277 $ids = array_map( 'integer' === $type ? 'intval' : 'strval', $ids );
1278
1279 return is_array( $id ) ? [] !== array_intersect( $id, $ids ) : in_array( $id, $ids, true );
1280 }
1281
1282 /**
1283 * Helper to compare ids.
1284 *
1285 * @param array $needle ids that should be searched for in haystack.
1286 * @param array $haystack reference ids.
1287 * @param string $operator whether it should be included or not.
1288 *
1289 * @return boolean
1290 */
1291 public static function can_display_ids( $needle, $haystack, $operator = 'is' ) {
1292 if ( 'is' === $operator && self::in_array( $needle, $haystack, 'string' ) === false ) {
1293 return false;
1294 }
1295
1296 if ( 'is_not' === $operator && self::in_array( $needle, $haystack, 'string' ) === true ) {
1297 return false;
1298 }
1299
1300 return true;
1301 }
1302
1303 /**
1304 * Check display conditions
1305 *
1306 * @param bool $can_display Whether the current ad can be displayed based on the checks that ran by now.
1307 * @param Ad $ad Ad instance.
1308 *
1309 * @return bool $can_display true if can be displayed in frontend
1310 * @since 1.1.0 moved here from can_display()
1311 *
1312 * @since 1.7.0 moved here from display-by-query module
1313 */
1314 public function can_display( $can_display, $ad ) {
1315 if ( ! $can_display ) {
1316 return false;
1317 }
1318
1319 $conditions = $ad->get_display_conditions();
1320 $query = $ad->get_prop( 'ad_args.wp_the_query' );
1321 if (
1322 // test if anything is to be limited at all.
1323 ! $conditions || ! is_array( $conditions )
1324 // query arguments required.
1325 || ! $query
1326 ) {
1327 return true;
1328 }
1329 // get conditions with rebased index keys.
1330 $conditions = array_values( $conditions );
1331 $last_result = false;
1332 $length = count( $conditions );
1333
1334 for ( $i = 0; $i < $length; ++$i ) {
1335 $_condition = current( $conditions );
1336 $next = next( $conditions );
1337 $next_key = key( $conditions );
1338
1339 /**
1340 * Force next condition’s connector to OR if
1341 * not set to OR already
1342 * this condition and the next are from the same taxonomy
1343 * the conditions don’t have the same condition type
1344 * they are both set to SHOW
1345 */
1346 $tax = ( isset( $_condition['type'] ) && isset( $this->conditions[ $_condition['type'] ]['taxonomy'] ) ) ? $this->conditions[ $_condition['type'] ]['taxonomy'] : false;
1347 $next_tax = ( isset( $next['type'] ) && isset( $this->conditions[ $next['type'] ]['taxonomy'] ) ) ? $this->conditions[ $next['type'] ]['taxonomy'] : false;
1348 if ( $tax && $next_tax && $next_key
1349 && $next_tax === $tax
1350 && ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] )
1351 && 'is' === $_condition['operator'] && 'is' === $next['operator']
1352 && $_condition['type'] !== $next['type']
1353 ) {
1354 $next['connector'] = 'or';
1355 $conditions[ $next_key ]['connector'] = 'or';
1356 }
1357
1358 // ignore OR if last result was true.
1359 if ( $last_result && isset( $_condition['connector'] ) && 'or' === $_condition['connector'] ) {
1360 continue;
1361 }
1362
1363 $result = self::frontend_check( $_condition, $ad );
1364 $last_result = $result;
1365 if ( ! $result ) {
1366 // return false only, if the next condition doesn’t have an OR operator.
1367 if ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] ) {
1368 return false;
1369 }
1370 }
1371 }
1372
1373 return true;
1374 }
1375
1376 /**
1377 * On demand provide current query arguments to ads.
1378 *
1379 * Existing arguments must not be overridden.
1380 * Some arguments might be cachable.
1381 *
1382 * @param array $args arguments.
1383 *
1384 * @return array
1385 */
1386 public function ad_select_args_callback( $args ) {
1387 global $post, $wp_the_query, $wp_query, $numpages;
1388
1389 if ( $post instanceof WP_Post ) {
1390 if ( ! isset( $args['post'] ) ) {
1391 $args['post'] = [];
1392 }
1393 if ( ! isset( $args['post']['id'] ) ) {
1394
1395 // if currently on a single site, use the main query information just in case a custom query is broken.
1396 if ( isset( $wp_the_query->post->ID ) && $wp_the_query->is_single() ) {
1397 $args['post']['id'] = $wp_the_query->post->ID;
1398 } else {
1399 $args['post']['id'] = $post->ID;
1400 }
1401 }
1402 if ( ! isset( $args['post']['author'] ) ) {
1403 // if currently on a single site, use the main query information just in case a custom query is broken.
1404 if ( isset( $wp_the_query->post->post_author ) && $wp_the_query->is_single() ) {
1405 $args['post']['author'] = $wp_the_query->post->post_author;
1406 } else {
1407 // a user reported that the missing $post_author property issue appeared so let’s check if it exists.
1408 $args['post']['author'] = isset( $post->post_author ) ? $post->post_author : '';
1409 }
1410 }
1411 if ( ! isset( $args['post']['post_type'] ) ) {
1412 // if currently on a single site, use the main query information just in case a custom query is broken.
1413 if ( isset( $wp_the_query->post->post_type ) && $wp_the_query->is_single() ) {
1414 $args['post']['post_type'] = $wp_the_query->post->post_type;
1415 } else {
1416 // a user reported that the missing $post_type property issue appeared so let’s check if it exists.
1417 $args['post']['post_type'] = isset( $post->post_type ) ? $post->post_type : '';
1418 }
1419 }
1420 }
1421
1422 // pass query arguments.
1423 if ( isset( $wp_the_query ) ) {
1424 if ( ! isset( $args['wp_the_query'] ) ) {
1425 $args['wp_the_query'] = [];
1426 }
1427 $query = $wp_the_query->get_queried_object();
1428 // term_id exists only for taxonomy archive pages.
1429 if ( ! isset( $args['wp_the_query']['term_id'] ) && $query ) {
1430 $args['wp_the_query']['term_id'] = isset( $query->term_id ) ? $query->term_id : '';
1431 }
1432 // taxonomy.
1433 if ( ! isset( $args['wp_the_query']['taxonomy'] ) && $query ) {
1434 $args['wp_the_query']['taxonomy'] = isset( $query->taxonomy ) ? $query->taxonomy : '';
1435 }
1436
1437 // query type/ context.
1438 if ( ! isset( $args['wp_the_query']['is_main_query'] ) ) {
1439 $args['wp_the_query']['is_main_query'] = Advanced_Ads::get_instance()->is_main_query();
1440 }
1441
1442 // REST API.
1443 if ( ! isset( $args['wp_the_query']['is_rest_api'] ) ) {
1444 $args['wp_the_query']['is_rest_api'] = defined( 'REST_REQUEST' ) && REST_REQUEST;
1445 }
1446
1447 // `<!-- nextpage -->` tags.
1448 if ( ! isset( $args['wp_the_query']['page'] ) ) {
1449 $args['wp_the_query']['page'] = isset( $wp_the_query->query_vars['page'] ) && $wp_the_query->query_vars['page'] ? $wp_the_query->query_vars['page'] : 1;
1450 $args['wp_the_query']['numpages'] = isset( $numpages ) ? $numpages : 1;
1451 }
1452
1453 // query vars.
1454 foreach ( self::$query_var_keys as $key ) {
1455 if ( ! isset( $args['wp_the_query'][ $key ] ) ) {
1456 $args['wp_the_query'][ $key ] = $wp_the_query->$key();
1457 }
1458 }
1459 }
1460
1461 return $args;
1462 }
1463
1464 /**
1465 * ;odify post search query to search by post_title or ID
1466 *
1467 * @param array $query post search query.
1468 *
1469 * @return array
1470 */
1471 public static function modify_post_search( $query ) {
1472
1473 // use ID and not search field if ID given.
1474 if ( 0 !== absint( $query['s'] ) && strlen( $query['s'] ) === strlen( absint( $query['s'] ) ) ) {
1475 $query['post__in'] = [ absint( $query['s'] ) ];
1476 unset( $query['s'] );
1477 }
1478
1479 $query['suppress_filters'] = false;
1480 $query['orderby'] = 'post_title';
1481 $query['post_status'] = [ 'publish', 'pending', 'draft', 'future' ];
1482
1483 return $query;
1484 }
1485
1486 /**
1487 * Modify post search SQL to search only in post title
1488 *
1489 * @param string $sql SQL statement.
1490 *
1491 * @return string
1492 */
1493 public static function modify_post_search_sql( $sql ) {
1494 global $wpdb;
1495 // removes the search in content and excerpt columns.
1496 $sql = preg_replace( "/OR \({$wpdb->posts}.post_(content|excerpt)( NOT)? LIKE '(.*?)'\)/", '', $sql );
1497
1498 return $sql;
1499 }
1500
1501 /**
1502 * Preg_replace callback used in modify_post_search_sql()
1503 *
1504 * @param array $matches results for post search.
1505 *
1506 * @return string
1507 * @deprecated since version 1.8.16
1508 */
1509 public static function modify_post_search_sql_callback( $matches ) {
1510 global $wpdb;
1511 if ( 'content' === $matches[1] && preg_match( '@^([0-9]+)$@', $matches[3], $matches_id ) ) {
1512 $equals_op = ' NOT' === $matches[2] ? '!=' : '=';
1513
1514 return "{$wpdb->posts}.ID$equals_op$matches_id[1]";
1515 } elseif ( ' NOT' === $matches[2] ) {
1516 return '1=1';
1517 } else {
1518 return '1=0';
1519 }
1520 }
1521 }
1522