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