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