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