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