PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.42.1
Advanced Ads – Ad Manager & AdSense v1.42.1
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 / ad.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
ad.php
1018 lines
1 <?php
2 /**
3 * Advanced Ads Ad.
4 *
5 * @package Advanced_Ads_Ad
6 * @author Thomas Maier <support@wpadvancedads.com>
7 * @license GPL-2.0+
8 * @link https://wpadvancedads.com
9 * @copyright 2013-2020 Thomas Maier, Advanced Ads GmbH
10 */
11
12 /**
13 * An ad object
14 *
15 * @package Advanced_Ads_Ad
16 * @author Thomas Maier <support@wpadvancedads.com>
17 * @deprecated since version 1.5.3 (May 6th 2015)
18 * might still be needed if some old add-ons are running somewhere
19 */
20 if ( ! class_exists( 'Advads_Ad', false ) ) {
21 class Advads_Ad extends Advanced_Ads_Ad {
22
23 }
24 }
25
26 /**
27 * An ad object
28 *
29 * @package Advanced_Ads_Ad
30 * @author Thomas Maier <support@wpadvancedads.com>
31 */
32 class Advanced_Ads_Ad {
33
34 /**
35 * Id of the post type for this ad
36 *
37 * @var int $id
38 */
39 public $id = 0;
40
41 /**
42 * True, if this is an Advanced Ads Ad post type
43 *
44 * @var bool $is_ad
45 */
46 public $is_ad = false;
47
48 /**
49 * Ad type
50 *
51 * @var string $type ad type.
52 */
53 public $type = 'content';
54
55 /**
56 * Notes about the ad usage
57 *
58 * @var string $description
59 */
60 public $description = '';
61
62 /**
63 * Ad width
64 *
65 * @var int $width width of the ad.
66 */
67 public $width = 0;
68
69 /**
70 * Target url
71 *
72 * @var string $url ad URL parameter.
73 */
74 public $url = '';
75
76 /**
77 * Ad height
78 *
79 * @var int $height height of the ad.
80 */
81 public $height = 0;
82
83 /**
84 * Object of current ad type
85 *
86 * @var Advanced_Ads_Ad_Type_Abstract $type_obj object of the current ad type.
87 */
88 protected $type_obj;
89
90 /**
91 * Content of the ad
92 *
93 * Only needed for ad types using the post content field
94 *
95 * @var string $content content of the ad.
96 */
97 public $content = '';
98
99 /**
100 * Conditions of the ad display
101 *
102 * @var array $conditions display and visitor conditions.
103 */
104 public $conditions = [];
105
106 /**
107 * Status of the ad (e.g. publish, pending)
108 *
109 * @var string $status status of the ad.
110 */
111 public $status = '';
112
113 /**
114 * Array with meta field options aka parameters
115 *
116 * @var array $options ad options.
117 */
118 protected $options;
119
120 /**
121 * Name of the meta field to save options to
122 *
123 * @var string $options_meta_field under which post meta key the ad options are stored.
124 */
125 public static $options_meta_field = 'advanced_ads_ad_options';
126
127 /**
128 * Additional arguments set when ad is loaded, overwrites or extends options
129 *
130 * @var array $args
131 */
132 public $args = [];
133
134 /**
135 * Multidimensional array contains information about the wrapper
136 * Each possible html attribute is an array with possible multiple elements
137 *
138 * @var array $wrapper options of the ad wrapper.
139 */
140 public $wrapper = [];
141
142 /**
143 * Will the ad be tracked?
144 *
145 * @var mixed $global_output
146 */
147 public $global_output;
148
149 /**
150 * Title of the ad
151 *
152 * @var string $title
153 */
154 public $title = '';
155
156 /**
157 * Displayed above the ad.
158 *
159 * @var string $label ad label.
160 */
161 protected $label = '';
162
163 /**
164 * Inline CSS object, one instance per ad.
165 *
166 * @var Advanced_Ads_Inline_Css
167 */
168 private $inline_css;
169 /**
170 * Timestamp if ad has an expiration date.
171 *
172 * @var int
173 */
174 public $expiry_date = 0;
175
176 /**
177 * The ad expiration object.
178 *
179 * @var Advanced_Ads_Ad_Expiration
180 */
181 private $ad_expiration;
182
183 /**
184 * The saved output options.
185 *
186 * @var array
187 */
188 public $output;
189
190 /**
191 * Whether the current ad is in a head placement.
192 *
193 * @var bool
194 */
195 public $is_head_placement;
196
197 /**
198 * Advanced_Ads_Ad constructor.
199 *
200 * @param int $id Ad ID.
201 * @param iterable $args Additional arguments.
202 */
203 public function __construct( int $id, iterable $args = [] ) {
204 if ( empty( $id ) ) {
205 return;
206 }
207
208 $this->id = $id;
209 $this->args = is_array( $args ) ? $args : [];
210
211 $post_data = get_post( $id );
212 if ( $post_data === null || $post_data->post_type !== Advanced_Ads::POST_TYPE_SLUG ) {
213 return;
214 }
215
216 $this->is_ad = true;
217 $this->type = $this->options( 'type' );
218 $this->title = $post_data->post_title;
219 $this->type_obj = Advanced_Ads::get_instance()->ad_types[ $this->type ] ?? new Advanced_Ads_Ad_Type_Abstract();
220
221 // filter the positioning options.
222 new Advanced_Ads_Ad_Positioning( $this );
223
224 $this->url = $this->get_url();
225 $this->width = absint( $this->options( 'width' ) );
226 $this->height = absint( $this->options( 'height' ) );
227 $this->conditions = $this->options( 'conditions' );
228 $this->description = $this->options( 'description' );
229 $this->output = $this->options( 'output' );
230 $this->status = $post_data->post_status;
231 $this->expiry_date = (int) $this->options( 'expiry_date' );
232 $this->is_head_placement = isset( $this->args['placement_type'] ) && 'header' === $this->args['placement_type'];
233 $this->args['is_top_level'] = ! isset( $this->args['is_top_level'] );
234
235 // load content based on ad type.
236 $this->content = $this->type_obj->load_content( $post_data );
237
238 if ( ! $this->is_head_placement ) {
239 $this->maybe_create_label();
240 $this->wrapper = $this->load_wrapper_options();
241
242 // set wrapper conditions.
243 $this->wrapper = apply_filters( 'advanced-ads-set-wrapper', $this->wrapper, $this );
244 // add unique wrapper id.
245 if ( is_array( $this->wrapper )
246 && [] !== $this->wrapper
247 && ! isset( $this->wrapper['id'] ) ) {
248 // create unique id if not yet given.
249 $this->wrapper['id'] = $this->create_wrapper_id();
250 }
251 }
252
253 $this->ad_expiration = new Advanced_Ads_Ad_Expiration( $this );
254
255 // dynamically add sanitize filters for condition types.
256 $condition_types = array_unique( array_column( Advanced_Ads::get_instance()->get_model()->get_ad_conditions(), 'type' ) );
257 foreach ( $condition_types as $condition_type ) {
258 $method_name = 'sanitize_condition_' . $condition_type;
259 if ( method_exists( $this, $method_name ) ) {
260 add_filter( 'advanced-ads-sanitize-condition-' . $condition_type, [ $this, $method_name ], 10, 1 );
261 } elseif ( function_exists( 'advads_sanitize_condition_' . $condition_type ) ) {
262 // check for public function to sanitize this.
263 add_filter( 'advanced-ads-sanitize-condition-' . $condition_type, 'advads_sanitize_condition_' . $condition_type, 10, 1 );
264 }
265 }
266
267 // whether the ad will be tracked.
268 $this->global_output = ! isset( $this->args['global_output'] ) || (bool) $this->args['global_output'];
269
270 // Run constructor to check early if ajax cache busting already created inline css.
271 $this->inline_css = new Advanced_Ads_Inline_Css();
272 }
273
274 /**
275 * Get options from meta field and return specific field
276 *
277 * @param string $field post meta key to be returned. Can be passed as array keys separated with `.`, i.e. 'parent.child' to retrieve multidimensional array values.
278 * @param array $default default options.
279 *
280 * @return mixed meta field content
281 */
282 public function options( $field = '', $default = null ) {
283 // retrieve options, if not given yet
284 if ( is_null( $this->options ) ) {
285 // may return false.
286 $meta = get_post_meta( $this->id, self::$options_meta_field, true );
287 if ( $meta && is_array( $meta ) ) {
288 // merge meta with arguments given on ad load.
289 $this->options = Advanced_Ads_Utils::merge_deep_array( [ $meta, $this->args ] );
290 } else {
291 // load arguments given on ad load.
292 $this->options = $this->args;
293 }
294
295 if ( isset( $this->options['change-ad'] ) ) {
296 // some options was provided by the user.
297 $this->options = Advanced_Ads_Utils::merge_deep_array(
298 [
299 $this->options,
300 $this->options['change-ad'],
301 ]
302 );
303 }
304 }
305
306 // return all options if no field given.
307 if ( empty( $field ) ) {
308 return $this->options;
309 }
310
311 $field = preg_replace( '/\s/', '', $field );
312 $value = $this->options;
313 foreach ( explode( '.', $field ) as $key ) {
314 if ( ! isset( $value[ $key ] ) ) {
315 $value = $default;
316 break;
317 }
318 $value = $value[ $key ];
319 }
320
321 if ( is_null( $value ) ) {
322 $value = $default;
323 }
324
325 /**
326 * Filter the option value retrieved for $field.
327 * `$field` parameter makes dynamic hook portion.
328 *
329 * @var mixed $value The option value (may be set to default).
330 * @var Advanced_Ads_Ad $this The current Advanced_Ads_Ad instance.
331 */
332 return apply_filters( "advanced-ads-ad-option-{$field}", $value, $this );
333 }
334
335 /**
336 * Set an option of the ad
337 *
338 * @param string $option name of the option.
339 * @param mixed $value value of the option.
340 *
341 * @since 1.1.0
342 */
343 public function set_option( $option = '', $value = '' ) {
344 if ( '' === $option ) {
345 return;
346 }
347
348 // get current options.
349 $options = $this->options();
350
351 // set options.
352 $options[ $option ] = $value;
353
354 // save options.
355 $this->options = $options;
356
357 }
358
359
360 /**
361 * Return ad content for frontend output
362 *
363 * @param array $output_options output options.
364 *
365 * @return string $output ad output
366 * @since 1.0.0
367 */
368 public function output( $output_options = [] ) {
369 if ( ! $this->is_ad ) {
370 return '';
371 }
372
373 $this->global_output = isset( $output_options['global_output'] ) ? $output_options['global_output'] : $this->global_output;
374 $output_options['global_output'] = $this->global_output;
375
376 // switch between normal and debug mode.
377 // check if debug output should only be displayed to admins.
378 $user_can_manage_ads = current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_manage_options' ) );
379 if ( $this->options( 'output.debugmode' )
380 && ( $user_can_manage_ads || ( ! $user_can_manage_ads && ! defined( 'ADVANCED_ADS_AD_DEBUG_FOR_ADMIN_ONLY' ) ) ) ) {
381 $debug = new Advanced_Ads_Ad_Debug();
382
383 return $debug->prepare_debug_output( $this );
384 } else {
385 $output = $this->prepare_frontend_output();
386 }
387
388 // add the ad to the global output array.
389 $advads = Advanced_Ads::get_instance();
390 if ( $output_options['global_output'] ) {
391 $new_ad = [
392 'type' => 'ad',
393 'id' => $this->id,
394 'title' => $this->title,
395 'output' => $output,
396 ];
397 // if ( method_exists( 'Advanced_Ads_Tracking_Plugin' , 'check_ad_tracking_enabled' ) ) {
398 // if ( class_exists( 'Advanced_Ads_Tracking_Plugin', false ) ) {
399 if ( defined( 'AAT_VERSION' ) && - 1 < version_compare( AAT_VERSION, '1.4.2' ) ) {
400
401 $new_ad['tracking_enabled'] = Advanced_Ads_Tracking_Plugin::get_instance()->check_ad_tracking_enabled( $this );
402
403 $tracking_options = Advanced_Ads_Tracking_Plugin::get_instance()->options();
404 if ( isset( $tracking_options['method'] ) && 'frontend' === $tracking_options['method'] && isset( $this->output['placement_id'] ) ) {
405 $new_ad['placement_id'] = $this->output['placement_id'];
406 }
407 }
408
409 $advads->current_ads[] = $new_ad;
410 }
411
412 // action when output is created.
413 do_action( 'advanced-ads-output', $this, $output, $output_options );
414
415 return apply_filters( 'advanced-ads-output-final', $output, $this, $output_options );
416 }
417
418 /**
419 * Check if the ad can be displayed in frontend due to its own conditions
420 *
421 * @param array $check_options check options.
422 *
423 * @return bool $can_display true if can be displayed in frontend
424 * @since 1.0.0
425 */
426 public function can_display( $check_options = [] ) {
427 $check_options = wp_parse_args(
428 $check_options,
429 [
430 'passive_cache_busting' => false,
431 'ignore_debugmode' => false,
432 ]
433 );
434
435 // prevent ad to show up through wp_head, if this is not a header placement.
436 if ( doing_action( 'wp_head' ) && isset( $this->options['placement_type'] ) && 'header' !== $this->options['placement_type']
437 && ! Advanced_Ads_Compatibility::can_inject_during_wp_head() ) {
438 return false;
439 }
440
441 // Check If the current ad is requested using a shortcode placed in the content of the current ad.
442 if ( isset( $this->options['shortcode_ad_id'] ) && (int) $this->options['shortcode_ad_id'] === $this->id ) {
443 return false;
444 }
445
446 // force ad display if debug mode is enabled.
447 if ( isset( $this->output['debugmode'] ) && ! $check_options['ignore_debugmode'] ) {
448 return true;
449 }
450
451 if ( ! $check_options['passive_cache_busting'] ) {
452 // don’t display ads that are not published or private for users not logged in.
453 if ( 'publish' !== $this->status && ! ( 'private' === $this->status && is_user_logged_in() ) ) {
454 return false;
455 }
456
457 if ( ! $this->can_display_by_visitor() ) {
458 return false;
459 }
460 } elseif ( 'publish' !== $this->status ) {
461 return false;
462 }
463
464 if ( $this->ad_expiration->is_ad_expired() ) {
465 return false;
466 }
467
468 // add own conditions to flag output as possible or not.
469 return apply_filters( 'advanced-ads-can-display', true, $this, $check_options );
470 }
471
472 /**
473 * Check visitor conditions
474 *
475 * @return bool $can_display true if can be displayed in frontend based on visitor settings
476 * @since 1.1.0
477 */
478 public function can_display_by_visitor() {
479 if ( ! empty( $this->options['wp_the_query']['is_feed'] ) ) {
480 return true;
481 }
482
483 $visitor_conditions = $this->options( 'visitors', [] );
484 if ( empty( $visitor_conditions ) ) {
485 return true;
486 }
487
488 $last_result = false;
489 $length = count( $visitor_conditions );
490
491 for ( $i = 0; $i < $length; ++ $i ) {
492 $_condition = current( $visitor_conditions );
493 // ignore OR if last result was true.
494 if ( $last_result && isset( $_condition['connector'] ) && 'or' === $_condition['connector'] ) {
495 next( $visitor_conditions );
496 continue;
497 }
498 $result = Advanced_Ads_Visitor_Conditions::frontend_check( $_condition, $this );
499 $last_result = $result;
500 if ( ! $result ) {
501 // return false only, if the next condition doesn’t have an OR operator.
502 $next = next( $visitor_conditions );
503 if ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] ) {
504 return false;
505 }
506 } else {
507 next( $visitor_conditions );
508 }
509 }
510
511 // check mobile condition.
512 if ( isset( $visitor_conditions['mobile'] ) ) {
513 switch ( $visitor_conditions['mobile'] ) {
514 case 'only':
515 if ( ! wp_is_mobile() ) {
516 return false;
517 }
518 break;
519 case 'no':
520 if ( wp_is_mobile() ) {
521 return false;
522 }
523 break;
524 }
525 }
526
527 return true;
528 }
529
530 /**
531 * Check expiry date
532 *
533 * @return bool $can_display true if can be displayed in frontend based on expiry date
534 * @since 1.3.15
535 * @deprecated 1.31.0 This is an internal method and should not have been public.
536 */
537 public function can_display_by_expiry_date() {
538 return $this->ad_expiration->is_ad_expired();
539 }
540
541 /**
542 * Save an ad to the database
543 * takes values from the current state
544 */
545 public function save() {
546 global $wpdb;
547
548 // remove slashes from content.
549 $this->content = $this->prepare_content_to_save();
550
551 $where = [ 'ID' => $this->id ];
552 $wpdb->update( $wpdb->posts, [ 'post_content' => $this->content ], $where );
553
554 // clean post from object cache.
555 clean_post_cache( $this->id );
556
557 // sanitize conditions
558 // see sanitize_conditions function for example on using this filter.
559 $conditions = self::sanitize_conditions_on_save( $this->conditions );
560
561 // save other options to post meta field.
562 $options = $this->options();
563
564 $options['type'] = $this->type;
565 $options['url'] = $this->url;
566 // Inform the tracking add-on about the new url.
567 unset( $options['tracking']['link'] );
568 $options['width'] = $this->width;
569 $options['height'] = $this->height;
570 $options['conditions'] = $conditions;
571 $options['expiry_date'] = $this->expiry_date;
572 $options['description'] = $this->description;
573
574 // save the plugin version, with every ad save.
575 $options['last_save_version'] = ADVADS_VERSION;
576
577 // sanitize container ID option.
578 $options['output']['wrapper-id'] = isset( $options['output']['wrapper-id'] ) ? sanitize_key( $options['output']['wrapper-id'] ) : '';
579
580 // sanitize options before saving
581 $options = $this->prepare_options_to_save( $options );
582
583 // filter to manipulate options or add more to be saved.
584 $options = apply_filters( 'advanced-ads-save-options', $options, $this );
585
586 update_post_meta( $this->id, self::$options_meta_field, $options );
587 }
588
589 /**
590 * Save ad options.
591 * Meant to be used from the outside of an ad.
592 *
593 * @param int $ad_id post ID of the ad.
594 * @param array $options ad options.
595 */
596 public static function save_ad_options( $ad_id, array $options ) {
597
598 // don’t allow to clear options by accident.
599 if ( [] === $options ) {
600 return;
601 }
602
603 update_post_meta( $ad_id, self::$options_meta_field, $options );
604 }
605
606 /**
607 * Native filter for content field before being saved
608 *
609 * @return string $content ad content
610 */
611 public function prepare_content_to_save() {
612
613 $content = $this->content;
614
615 // load ad type specific parameter filter
616 // @todo this is just a hotfix for type_obj not set, yet the cause is still unknown. Likely when the ad is first saved
617 if ( is_object( $this->type_obj ) ) {
618 $content = $this->type_obj->sanitize_content( $content );
619 }
620 // apply a custom filter by ad type.
621 $content = apply_filters( 'advanced-ads-pre-ad-save-' . $this->type, $content );
622
623 return $content;
624 }
625
626 /**
627 * Sanitize ad options before being saved
628 * allows some ad types to sanitize certain values
629 *
630 * @param array $options ad options.
631 * @return array sanitized options.
632 */
633 public function prepare_options_to_save( $options ) {
634
635 // load ad type specific sanitize function.
636 // we need to load the ad type object if not set (e.g., when the ad is saved for the first time)
637 if ( ! is_object( $this->type_obj ) || ! $this->type_obj->ID ) {
638 $types = Advanced_Ads::get_instance()->ad_types;
639 if ( isset( $types[ $this->type ] ) ) {
640 $this->type_obj = $types[ $this->type ];
641 }
642 }
643
644 $options = $this->type_obj->sanitize_options( $options );
645
646 return $options;
647 }
648
649 /**
650 * Prepare ads output
651 *
652 * @return string.
653 */
654 public function prepare_frontend_output() {
655 $options = $this->options();
656
657 if ( isset( $options['change-ad']['content'] ) ) {
658 // output was provided by the user.
659 $output = $options['change-ad']['content'];
660 } else {
661 // load ad type specific content filter.
662 $output = $this->type_obj->prepare_output( $this );
663 }
664
665 // don’t deliver anything, if main ad content is empty.
666 if ( empty( $output ) ) {
667 return '';
668 }
669
670 if ( ! $this->is_head_placement ) {
671 // filter to manipulate the output before the wrapper is added
672 $output = apply_filters( 'advanced-ads-output-inside-wrapper', $output, $this );
673
674 // build wrapper around the ad.
675 $output = $this->add_wrapper( $output );
676
677 // add a clearfix, if set.
678 if (
679 ( ! empty( $this->args['is_top_level'] ) && ! empty( $this->args['placement_clearfix'] ) )
680 || $this->options( 'output.clearfix' )
681 ) {
682 $output .= '<br style="clear: both; display: block; float: none;"/>';
683 }
684 }
685
686 // apply a custom filter by ad type.
687 $output = apply_filters( 'advanced-ads-ad-output', $output, $this );
688
689 return $output;
690 }
691
692 /**
693 * Sanitize ad display conditions when saving the ad
694 *
695 * @param array $conditions conditions array send via the dashboard form for an ad.
696 *
697 * @return array with sanitized conditions
698 * @since 1.0.0
699 */
700 public function sanitize_conditions_on_save( $conditions = [] ) {
701
702 global $advanced_ads_ad_conditions;
703
704 if ( ! is_array( $conditions ) || [] === $conditions ) {
705 return [];
706 }
707
708 foreach ( $conditions as $_key => $_condition ) {
709 if ( 'postids' === $_key ) {
710 // sanitize single post conditions
711 if ( empty( $_condition['ids'] ) ) { // remove, if empty.
712 $_condition['include'] = [];
713 $_condition['exclude'] = [];
714 } elseif ( isset( $_condition['method'] ) ) {
715 switch ( $_condition['method'] ) {
716 case 'include':
717 $_condition['include'] = $_condition['ids'];
718 $_condition['exclude'] = [];
719 break;
720 case 'exclude':
721 $_condition['include'] = [];
722 $_condition['exclude'] = $_condition['ids'];
723 break;
724 }
725 }
726 } else {
727 if ( ! is_array( $_condition ) ) {
728 $_condition = trim( $_condition );
729 }
730 if ( $_condition == '' ) {
731 $conditions[ $_key ] = $_condition;
732 continue;
733 }
734 }
735 $type = ! empty( $advanced_ads_ad_conditions[ $_key ]['type'] ) ? $advanced_ads_ad_conditions[ $_key ]['type'] : 0;
736 if ( empty( $type ) ) {
737 continue;
738 }
739
740 // dynamically apply filters for each condition used.
741 $conditions[ $_key ] = apply_filters( 'advanced-ads-sanitize-condition-' . $type, $_condition );
742 }
743
744 return $conditions;
745 }
746
747 /**
748 * Sanitize id input field(s) for pattern /1,2,3,4/
749 *
750 * @param mixed $cond input string/array.
751 *
752 * @return array/string $cond sanitized string/array
753 */
754 public static function sanitize_condition_idfield( $cond = '' ) {
755 // strip anything that is not comma or number.
756
757 if ( is_array( $cond ) ) {
758 foreach ( $cond as $_key => $_cond ) {
759 $cond[ $_key ] = preg_replace( '#[^0-9,]#', '', $_cond );
760 }
761 } else {
762 $cond = preg_replace( '#[^0-9,]#', '', $cond );
763 }
764
765 return $cond;
766 }
767
768 /**
769 * Sanitize radio input field
770 *
771 * @param string $string input string.
772 *
773 * @return string $string sanitized string.
774 */
775 public static function sanitize_condition_radio( $string = '' ) {
776 // only allow 0, 1 and empty.
777 return preg_replace( '#[^01]#', '', $string );
778 }
779
780 /**
781 * Sanitize comma seperated text input field
782 *
783 * @param mixed $cond input string/array.
784 *
785 * @return array/string $cond sanitized string/array.
786 */
787 public static function sanitize_condition_textvalues( $cond = '' ) {
788 // strip anything that is not comma, alphanumeric, minus and underscore.
789 if ( is_array( $cond ) ) {
790 foreach ( $cond as $_key => $_cond ) {
791 $cond[ $_key ] = preg_replace( '#[^0-9,A-Za-z-_]#', '', $_cond );
792 }
793 } else {
794 $cond = preg_replace( '#[^0-9,A-Za-z-_]#', '', $cond );
795 }
796
797 return $cond;
798 }
799
800 /**
801 * Load wrapper options set with the ad
802 *
803 * @return array $wrapper options array ready to be use in add_wrapper() function.
804 * @since 1.3
805 */
806 protected function load_wrapper_options() {
807 $wrapper = [];
808
809 $position = $this->options( 'output.position', '' );
810 $use_placement_pos = false;
811
812 if ( $this->args['is_top_level'] ) {
813 if ( isset( $this->output['class'] ) && is_array( $this->output['class'] ) ) {
814 $wrapper['class'] = $this->output['class'];
815 }
816 if ( ! empty( $this->args['placement_position'] ) ) {
817 // If not group, Set placement position instead of ad position.
818 $use_placement_pos = true;
819 $position = $this->args['placement_position'];
820 }
821 }
822
823 switch ( $position ) {
824 case 'left':
825 case 'left_float':
826 case 'left_nofloat':
827 $wrapper['style']['float'] = 'left';
828 break;
829 case 'right':
830 case 'right_float':
831 case 'right_nofloat':
832 $wrapper['style']['float'] = 'right';
833 break;
834 case 'center':
835 case 'center_nofloat':
836 case 'center_float':
837 $wrapper['style']['margin-left'] = 'auto';
838 $wrapper['style']['margin-right'] = 'auto';
839
840 if (
841 ( ! $this->width || empty( $this->output['add_wrapper_sizes'] ) )
842 || $use_placement_pos
843 ) {
844 $wrapper['style']['text-align'] = 'center';
845 }
846
847 // add css rule after wrapper to center the ad.
848 break;
849 case 'clearfix':
850 $wrapper['style']['clear'] = 'both';
851 break;
852 }
853
854 // add manual classes.
855 if ( isset( $this->output['wrapper-class'] ) && '' !== $this->output['wrapper-class'] ) {
856 $classes = explode( ' ', $this->output['wrapper-class'] );
857
858 foreach ( $classes as $_class ) {
859 $wrapper['class'][] = sanitize_text_field( $_class );
860 }
861 }
862
863 if ( ! empty( $this->output['margin']['top'] ) ) {
864 $wrapper['style']['margin-top'] = (int) $this->output['margin']['top'] . 'px';
865 }
866 if ( empty( $wrapper['style']['margin-right'] ) && ! empty( $this->output['margin']['right'] ) ) {
867 $wrapper['style']['margin-right'] = (int) $this->output['margin']['right'] . 'px';
868 }
869 if ( ! empty( $this->output['margin']['bottom'] ) ) {
870 $wrapper['style']['margin-bottom'] = (int) $this->output['margin']['bottom'] . 'px';
871 }
872 if ( empty( $wrapper['style']['margin-left'] ) && ! empty( $this->output['margin']['left'] ) ) {
873 $wrapper['style']['margin-left'] = (int) $this->output['margin']['left'] . 'px';
874 }
875
876 if ( ! empty( $this->output['add_wrapper_sizes'] ) ) {
877 if ( ! empty( $this->width ) ) {
878 $wrapper['style']['width'] = $this->width . 'px';
879 }
880 if ( ! empty( $this->height ) ) {
881 $wrapper['style']['height'] = $this->height . 'px';
882 }
883 }
884
885 if ( ! empty( $this->output['clearfix_before'] ) ) {
886 $wrapper['style']['clear'] = 'both';
887 }
888
889 return $wrapper;
890 }
891
892 /**
893 * Add a wrapper arount the ad content if wrapper information are given
894 *
895 * @param string $ad_content content of the ad.
896 *
897 * @return string $wrapper ad within the wrapper
898 * @since 1.1.4
899 */
900 protected function add_wrapper( $ad_content = '' ) {
901 $wrapper_options = apply_filters( 'advanced-ads-output-wrapper-options', $this->wrapper, $this );
902
903 if ( $this->label && ! empty( $wrapper_options['style']['height'] ) ) {
904 // Create another wrapper so that the label does not reduce the height of the ad wrapper.
905 $height = [ 'style' => [ 'height' => $wrapper_options['style']['height'] ] ];
906 unset( $wrapper_options['style']['height'] );
907 $ad_content = '<div' . Advanced_Ads_Utils::build_html_attributes( $height ) . '>' . $ad_content . '</div>';
908 }
909
910 // Adds inline css to the wrapper.
911 if ( ! empty( $this->options['inline-css'] ) && $this->args['is_top_level'] ) {
912 $wrapper_options = $this->inline_css->add_css( $wrapper_options, $this->options['inline-css'], $this->global_output );
913 }
914
915 if (
916 ! defined( 'ADVANCED_ADS_DISABLE_EDIT_BAR' )
917 // Add edit button for users with the appropriate rights.
918 && current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_edit_ads' ) )
919 // We need a wrapper. Check if at least the placement wrapper exists.
920 && ! empty( $this->args['placement_type'] )
921 ) {
922 ob_start();
923 include ADVADS_BASE_PATH . 'public/views/ad-edit-bar.php';
924 $ad_content = trim( ob_get_clean() ) . $ad_content;
925 }
926
927 if ( ( ! isset( $this->output['wrapper-id'] ) || '' === $this->output['wrapper-id'] )
928 && [] === $wrapper_options || ! is_array( $wrapper_options ) ) {
929 return $this->label . $ad_content;
930 }
931
932 // create unique id if not yet given.
933 if ( empty( $wrapper_options['id'] ) ) {
934 $wrapper_options['id'] = $this->create_wrapper_id();
935 $this->wrapper['id'] = $wrapper_options['id'];
936 }
937
938 $wrapper_element = ! empty( $this->args['inline_wrapper_element'] ) ? 'span' : 'div';
939
940 // build the box
941 $wrapper = '<' . $wrapper_element . Advanced_Ads_Utils::build_html_attributes( array_merge(
942 $wrapper_options,
943 isset( $this->output['wrapper_attrs'] ) ? $this->output['wrapper_attrs'] : []
944 ) ) . '>';
945 $wrapper .= $this->label;
946 $wrapper .= apply_filters( 'advanced-ads-output-wrapper-before-content', '', $this );
947 $wrapper .= $ad_content;
948 $wrapper .= apply_filters( 'advanced-ads-output-wrapper-after-content', '', $this );
949 $wrapper .= '</' . $wrapper_element . '>';
950
951 return $wrapper;
952 }
953
954 /**
955 * Create a random wrapper id
956 *
957 * @return string $id random id string
958 * @since 1.1.4
959 */
960 private function create_wrapper_id() {
961
962 if ( isset( $this->output['wrapper-id'] ) ) {
963 $id = sanitize_key( $this->output['wrapper-id'] );
964 if ( '' !== $id ) {
965 return $id;
966 }
967 }
968
969 $prefix = Advanced_Ads_Plugin::get_instance()->get_frontend_prefix();
970
971 return $prefix . mt_rand();
972 }
973
974 /**
975 * Create an "Advertisement" label if conditions are met.
976 */
977 public function maybe_create_label() {
978 $placement_state = isset( $this->args['ad_label'] ) ? $this->args['ad_label'] : 'default';
979
980 $label = Advanced_Ads::get_instance()->get_label( $placement_state );
981
982 if ( $this->args['is_top_level'] && $label ) {
983 $this->label = $label;
984 }
985 }
986
987 /**
988 * Get the ad url.
989 *
990 * @return string
991 */
992 private function get_url() {
993 $this->url = $this->options( 'url' );
994
995 // If the tracking add-on is not active.
996 if ( ! defined( 'AAT_VERSION' ) ) {
997 global $pagenow;
998 // If this is not the ad edit page.
999 if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
1000 // Remove placeholders.
1001 $this->url = str_replace(
1002 [
1003 '[POST_ID]',
1004 '[POST_SLUG]',
1005 '[CAT_SLUG]',
1006 '[AD_ID]',
1007 ],
1008 '',
1009 $this->url
1010 );
1011 }
1012 }
1013
1014 return $this->url;
1015 }
1016
1017 }
1018