: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @package Advanced_Ads_Ad
* @author Thomas Maier <support@wpadvancedads.com>
* @link https://wpadvancedads.com
* @copyright 2013-2020 Thomas Maier, Advanced Ads GmbH
use AdvancedAds\Entities;
use AdvancedAds\Utilities\WordPress;
* @package Advanced_Ads_Ad
* @author Thomas Maier <support@wpadvancedads.com>
* @deprecated since version 1.5.3 (May 6th 2015)
* might still be needed if some old add-ons are running somewhere
if ( ! class_exists( 'Advads_Ad', false ) ) {
class Advads_Ad extends Advanced_Ads_Ad {
* @package Advanced_Ads_Ad
* @author Thomas Maier <support@wpadvancedads.com>
* Id of the post type for this ad
* True, if this is an Advanced Ads Ad post type
* @var string $type ad type.
public $type = 'content';
* Notes about the ad usage
* @var string $description
public $description = '';
* @var int $width width of the ad.
* @var string $url ad URL parameter.
* @var int $height height of the ad.
* Object of current ad type
* @var Advanced_Ads_Ad_Type_Abstract $type_obj object of the current ad type.
* Only needed for ad types using the post content field
* @var string $content content of the ad.
* Conditions of the ad display
* @var array $conditions display and visitor conditions.
* Status of the ad (e.g. publish, pending)
* @var string $status status of the ad.
* Array with meta field options aka parameters
* @var array $options ad options.
* Name of the meta field to save options to
* @var string $options_meta_field under which post meta key the ad options are stored.
public static $options_meta_field = 'advanced_ads_ad_options';
* Additional arguments set when ad is loaded, overwrites or extends options
* Multidimensional array contains information about the wrapper
* Each possible html attribute is an array with possible multiple elements
* @var array $wrapper options of the ad wrapper.
* Will the ad be tracked?
* @var mixed $global_output
* Displayed above the ad.
* @var string $label ad label.
* Inline CSS object, one instance per ad.
* @var Advanced_Ads_Inline_Css
* Timestamp if ad has an expiration date.
* The ad expiration object.
* @var Advanced_Ads_Ad_Expiration
* The saved output options.
* Whether the current ad is in a head placement.
public $is_head_placement;
* Advanced_Ads_Ad constructor.
* @param iterable $args Additional arguments.
public function __construct( int $id, iterable $args = [] ) {
$this->args = is_array( $args ) ? $args : [];
$post_data = get_post( $id );
if ( $post_data === null || $post_data->post_type !== Entities::POST_TYPE_AD ) {
$this->type = $this->options( 'type' );
$this->title = $post_data->post_title;
$this->type_obj = Advanced_Ads::get_instance()->ad_types[ $this->type ] ?? new Advanced_Ads_Ad_Type_Abstract();
// filter the positioning options.
new Advanced_Ads_Ad_Positioning( $this );
$this->url = $this->get_url();
$this->width = absint( $this->options( 'width' ) );
$this->height = absint( $this->options( 'height' ) );
$this->conditions = $this->options( 'conditions' );
$this->description = $this->options( 'description' );
$this->output = $this->options( 'output' );
$this->status = $post_data->post_status;
$this->expiry_date = (int) $this->options( 'expiry_date' );
$this->is_head_placement = isset( $this->args['placement_type'] ) && 'header' === $this->args['placement_type'];
$this->args['is_top_level'] = ! isset( $this->args['is_top_level'] );
// load content based on ad type.
$this->content = $this->type_obj->load_content( $post_data );
if ( ! $this->is_head_placement ) {
$this->maybe_create_label();
$this->wrapper = $this->load_wrapper_options();
// set wrapper conditions.
$this->wrapper = apply_filters( 'advanced-ads-set-wrapper', $this->wrapper, $this );
// add unique wrapper id.
if ( is_array( $this->wrapper )
&& ! isset( $this->wrapper['id'] ) ) {
// create unique id if not yet given.
$this->wrapper['id'] = $this->create_wrapper_id();
$this->ad_expiration = new Advanced_Ads_Ad_Expiration( $this );
// dynamically add sanitize filters for condition types.
$condition_types = array_unique( array_column( Advanced_Ads::get_instance()->get_model()->get_ad_conditions(), 'type' ) );
foreach ( $condition_types as $condition_type ) {
$method_name = 'sanitize_condition_' . $condition_type;
if ( method_exists( $this, $method_name ) ) {
add_filter( 'advanced-ads-sanitize-condition-' . $condition_type, [ $this, $method_name ], 10, 1 );
} elseif ( function_exists( 'advads_sanitize_condition_' . $condition_type ) ) {
// check for public function to sanitize this.
add_filter( 'advanced-ads-sanitize-condition-' . $condition_type, 'advads_sanitize_condition_' . $condition_type, 10, 1 );
// whether the ad will be tracked.
$this->global_output = ! isset( $this->args['global_output'] ) || (bool) $this->args['global_output'];
// Run constructor to check early if ajax cache busting already created inline css.
$this->inline_css = new Advanced_Ads_Inline_Css();
* Get options from meta field and return specific field
* @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.
* @param array $default default options.
* @return mixed meta field content
public function options( $field = '', $default = null ) {
// retrieve options, if not given yet
if ( is_null( $this->options ) ) {
$meta = get_post_meta( $this->id, self::$options_meta_field, true );
if ( $meta && is_array( $meta ) ) {
// merge meta with arguments given on ad load.
$this->options = Advanced_Ads_Utils::merge_deep_array( [ $meta, $this->args ] );
// load arguments given on ad load.
$this->options = $this->args;
if ( isset( $this->options['change-ad'] ) ) {
// some options was provided by the user.
$this->options = Advanced_Ads_Utils::merge_deep_array(
$this->options['change-ad'],
// return all options if no field given.
$field = preg_replace( '/\s/', '', $field );
foreach ( explode( '.', $field ) as $key ) {
if ( ! isset( $value[ $key ] ) ) {
if ( is_null( $value ) ) {
* Filter the option value retrieved for $field.
* `$field` parameter makes dynamic hook portion.
* @var mixed $value The option value (may be set to default).
* @var Advanced_Ads_Ad $this The current Advanced_Ads_Ad instance.
return apply_filters( "advanced-ads-ad-option-{$field}", $value, $this );
* Set an option of the ad
* @param string $option name of the option.
* @param mixed $value value of the option.
public function set_option( $option = '', $value = '' ) {
$options = $this->options();
$options[ $option ] = $value;
$this->options = $options;
* Return ad content for frontend output
* @param array $output_options output options.
* @return string $output ad output
public function output( $output_options = [] ) {
$this->global_output = isset( $output_options['global_output'] ) ? $output_options['global_output'] : $this->global_output;
$output_options['global_output'] = $this->global_output;
// switch between normal and debug mode.
// check if debug output should only be displayed to admins.
$user_can_manage_ads = WordPress::user_can( 'advanced_ads_manage_options' );
if ( $this->options( 'output.debugmode' )
&& ( $user_can_manage_ads || ( ! $user_can_manage_ads && ! defined( 'ADVANCED_ADS_AD_DEBUG_FOR_ADMIN_ONLY' ) ) ) ) {
$debug = new Advanced_Ads_Ad_Debug();
return $debug->prepare_debug_output( $this );
$output = $this->prepare_frontend_output();
// add the ad to the global output array.
$advads = Advanced_Ads::get_instance();
if ( $output_options['global_output'] ) {
// if ( method_exists( 'Advanced_Ads_Tracking_Plugin' , 'check_ad_tracking_enabled' ) ) {
// if ( class_exists( 'Advanced_Ads_Tracking_Plugin', false ) ) {
if ( defined( 'AAT_VERSION' ) && - 1 < version_compare( AAT_VERSION, '1.4.2' ) ) {
$new_ad['tracking_enabled'] = Advanced_Ads_Tracking_Plugin::get_instance()->check_ad_tracking_enabled( $this );
$tracking_options = Advanced_Ads_Tracking_Plugin::get_instance()->options();
if ( isset( $tracking_options['method'] ) && 'frontend' === $tracking_options['method'] && isset( $this->output['placement_id'] ) ) {
$new_ad['placement_id'] = $this->output['placement_id'];
$advads->current_ads[] = $new_ad;
// action when output is created.
do_action( 'advanced-ads-output', $this, $output, $output_options );
return apply_filters( 'advanced-ads-output-final', $output, $this, $output_options );
* Check if the ad can be displayed in frontend due to its own conditions
* @param array $check_options check options.
* @return bool $can_display true if can be displayed in frontend
public function can_display( $check_options = [] ) {
$check_options = wp_parse_args(
'passive_cache_busting' => false,
'ignore_debugmode' => false,
// prevent ad to show up through wp_head, if this is not a header placement.
if ( doing_action( 'wp_head' ) && isset( $this->options['placement_type'] ) && 'header' !== $this->options['placement_type']
&& ! Advanced_Ads_Compatibility::can_inject_during_wp_head() ) {
// Check If the current ad is requested using a shortcode placed in the content of the current ad.
if ( isset( $this->options['shortcode_ad_id'] ) && (int) $this->options['shortcode_ad_id'] === $this->id ) {
// force ad display if debug mode is enabled.
if ( isset( $this->output['debugmode'] ) && ! $check_options['ignore_debugmode'] ) {
if ( ! $check_options['passive_cache_busting'] ) {
// don’t display ads that are not published or private for users not logged in.
if ( 'publish' !== $this->status && ! ( 'private' === $this->status && is_user_logged_in() ) ) {
if ( ! $this->can_display_by_visitor() ) {
} elseif ( 'publish' !== $this->status ) {
if ( $this->ad_expiration->is_ad_expired() ) {
// add own conditions to flag output as possible or not.
return apply_filters( 'advanced-ads-can-display', true, $this, $check_options );
* Check visitor conditions
* @return bool $can_display true if can be displayed in frontend based on visitor settings
public function can_display_by_visitor() {
if ( ! empty( $this->options['wp_the_query']['is_feed'] ) ) {
$visitor_conditions = $this->options( 'visitors', [] );
if ( empty( $visitor_conditions ) ) {
$length = count( $visitor_conditions );
for ( $i = 0; $i < $length; ++ $i ) {
$_condition = current( $visitor_conditions );
// ignore OR if last result was true.
if ( $last_result && isset( $_condition['connector'] ) && 'or' === $_condition['connector'] ) {
next( $visitor_conditions );