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