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