: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$result = Advanced_Ads_Visitor_Conditions::frontend_check( $_condition, $this );
// return false only, if the next condition doesn’t have an OR operator.
$next = next( $visitor_conditions );
if ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] ) {
next( $visitor_conditions );
// check mobile condition.
if ( isset( $visitor_conditions['mobile'] ) ) {
switch ( $visitor_conditions['mobile'] ) {
if ( ! wp_is_mobile() ) {
* @return bool $can_display true if can be displayed in frontend based on expiry date
* @deprecated 1.31.0 This is an internal method and should not have been public.
public function can_display_by_expiry_date() {
return $this->ad_expiration->is_ad_expired();
* Save an ad to the database
* takes values from the current state
// remove slashes from content.
$this->content = $this->prepare_content_to_save();
$where = [ 'ID' => $this->id ];
$wpdb->update( $wpdb->posts, [ 'post_content' => $this->content ], $where );
// clean post from object cache.
clean_post_cache( $this->id );
// see sanitize_conditions function for example on using this filter.
$conditions = self::sanitize_conditions_on_save( $this->conditions );
// save other options to post meta field.
$options = $this->options();
$options['type'] = $this->type;
$options['url'] = $this->url;
// Inform the tracking add-on about the new url.
unset( $options['tracking']['link'] );
$options['width'] = $this->width;
$options['height'] = $this->height;
$options['conditions'] = $conditions;
$options['expiry_date'] = $this->expiry_date;
$options['description'] = $this->description;
// save the plugin version, with every ad save.
$options['last_save_version'] = ADVADS_VERSION;
// sanitize container ID option.
$options['output']['wrapper-id'] = isset( $options['output']['wrapper-id'] ) ? sanitize_key( $options['output']['wrapper-id'] ) : '';
// sanitize options before saving
$options = $this->prepare_options_to_save( $options );
// filter to manipulate options or add more to be saved.
$options = apply_filters( 'advanced-ads-save-options', $options, $this );
update_post_meta( $this->id, self::$options_meta_field, $options );
* Meant to be used from the outside of an ad.
* @param int $ad_id post ID of the ad.
* @param array $options ad options.
public static function save_ad_options( $ad_id, array $options ) {
// don’t allow to clear options by accident.
update_post_meta( $ad_id, self::$options_meta_field, $options );
* Native filter for content field before being saved
* @return string $content ad content
public function prepare_content_to_save() {
$content = $this->content;
// load ad type specific parameter filter
// @todo this is just a hotfix for type_obj not set, yet the cause is still unknown. Likely when the ad is first saved
if ( is_object( $this->type_obj ) ) {
$content = $this->type_obj->sanitize_content( $content );
// apply a custom filter by ad type.
$content = apply_filters( 'advanced-ads-pre-ad-save-' . $this->type, $content );
* Sanitize ad options before being saved
* allows some ad types to sanitize certain values
* @param array $options ad options.
* @return array sanitized options.
public function prepare_options_to_save( $options ) {
// load ad type specific sanitize function.
// we need to load the ad type object if not set (e.g., when the ad is saved for the first time)
if ( ! is_object( $this->type_obj ) || ! $this->type_obj->ID ) {
$types = Advanced_Ads::get_instance()->ad_types;
if ( isset( $types[ $this->type ] ) ) {
$this->type_obj = $types[ $this->type ];
$options = $this->type_obj->sanitize_options( $options );
public function prepare_frontend_output() {
$options = $this->options();
if ( isset( $options['change-ad']['content'] ) ) {
// output was provided by the user.
$output = $options['change-ad']['content'];
// load ad type specific content filter.
$output = $this->type_obj->prepare_output( $this );
// don’t deliver anything, if main ad content is empty.
if ( empty( $output ) ) {
if ( ! $this->is_head_placement ) {
// filter to manipulate the output before the wrapper is added
$output = apply_filters( 'advanced-ads-output-inside-wrapper', $output, $this );
// build wrapper around the ad.
$output = $this->add_wrapper( $output );
// add a clearfix, if set.
( ! empty( $this->args['is_top_level'] ) && ! empty( $this->args['placement_clearfix'] ) )
|| $this->options( 'output.clearfix' )
$output .= '<br style="clear: both; display: block; float: none;"/>';
// apply a custom filter by ad type.
$output = apply_filters( 'advanced-ads-ad-output', $output, $this );
* Sanitize ad display conditions when saving the ad
* @param array $conditions conditions array send via the dashboard form for an ad.
* @return array with sanitized conditions
public function sanitize_conditions_on_save( $conditions = [] ) {
global $advanced_ads_ad_conditions;
if ( ! is_array( $conditions ) || [] === $conditions ) {
foreach ( $conditions as $_key => $_condition ) {
if ( 'postids' === $_key ) {
// sanitize single post conditions
if ( empty( $_condition['ids'] ) ) { // remove, if empty.
$_condition['include'] = [];
$_condition['exclude'] = [];
} elseif ( isset( $_condition['method'] ) ) {
switch ( $_condition['method'] ) {
$_condition['include'] = $_condition['ids'];
$_condition['exclude'] = [];
$_condition['include'] = [];
$_condition['exclude'] = $_condition['ids'];
if ( ! is_array( $_condition ) ) {
$_condition = trim( $_condition );
if ( $_condition == '' ) {
$conditions[ $_key ] = $_condition;
$type = ! empty( $advanced_ads_ad_conditions[ $_key ]['type'] ) ? $advanced_ads_ad_conditions[ $_key ]['type'] : 0;
// dynamically apply filters for each condition used.
$conditions[ $_key ] = apply_filters( 'advanced-ads-sanitize-condition-' . $type, $_condition );
* Sanitize id input field(s) for pattern /1,2,3,4/
* @param mixed $cond input string/array.
* @return array/string $cond sanitized string/array
public static function sanitize_condition_idfield( $cond = '' ) {
// strip anything that is not comma or number.
if ( is_array( $cond ) ) {
foreach ( $cond as $_key => $_cond ) {
$cond[ $_key ] = preg_replace( '#[^0-9,]#', '', $_cond );
$cond = preg_replace( '#[^0-9,]#', '', $cond );
* Sanitize radio input field
* @param string $string input string.
* @return string $string sanitized string.
public static function sanitize_condition_radio( $string = '' ) {
// only allow 0, 1 and empty.
return preg_replace( '#[^01]#', '', $string );
* Sanitize comma seperated text input field
* @param mixed $cond input string/array.
* @return array/string $cond sanitized string/array.
public static function sanitize_condition_textvalues( $cond = '' ) {
// strip anything that is not comma, alphanumeric, minus and underscore.
if ( is_array( $cond ) ) {
foreach ( $cond as $_key => $_cond ) {
$cond[ $_key ] = preg_replace( '#[^0-9,A-Za-z-_]#', '', $_cond );
$cond = preg_replace( '#[^0-9,A-Za-z-_]#', '', $cond );
* Load wrapper options set with the ad
* @return array $wrapper options array ready to be use in add_wrapper() function.
protected function load_wrapper_options() {
$position = $this->options( 'output.position', '' );
$use_placement_pos = false;
if ( $this->args['is_top_level'] ) {
if ( isset( $this->output['class'] ) && is_array( $this->output['class'] ) ) {
$wrapper['class'] = $this->output['class'];
if ( ! empty( $this->args['placement_position'] ) ) {
// If not group, Set placement position instead of ad position.
$use_placement_pos = true;
$position = $this->args['placement_position'];
$wrapper['style']['float'] = 'left';
$wrapper['style']['float'] = 'right';
$wrapper['style']['margin-left'] = 'auto';
$wrapper['style']['margin-right'] = 'auto';
( ! $this->width || empty( $this->output['add_wrapper_sizes'] ) )
$wrapper['style']['text-align'] = 'center';
// add css rule after wrapper to center the ad.
$wrapper['style']['clear'] = 'both';
if ( isset( $this->output['wrapper-class'] ) && '' !== $this->output['wrapper-class'] ) {
$classes = explode( ' ', $this->output['wrapper-class'] );
foreach ( $classes as $_class ) {
$wrapper['class'][] = sanitize_text_field( $_class );
if ( ! empty( $this->output['margin']['top'] ) ) {
$wrapper['style']['margin-top'] = (int) $this->output['margin']['top'] . 'px';
if ( empty( $wrapper['style']['margin-right'] ) && ! empty( $this->output['margin']['right'] ) ) {
$wrapper['style']['margin-right'] = (int) $this->output['margin']['right'] . 'px';
if ( ! empty( $this->output['margin']['bottom'] ) ) {
$wrapper['style']['margin-bottom'] = (int) $this->output['margin']['bottom'] . 'px';
if ( empty( $wrapper['style']['margin-left'] ) && ! empty( $this->output['margin']['left'] ) ) {
$wrapper['style']['margin-left'] = (int) $this->output['margin']['left'] . 'px';
if ( ! empty( $this->output['add_wrapper_sizes'] ) ) {
if ( ! empty( $this->width ) ) {
$wrapper['style']['width'] = $this->width . 'px';
if ( ! empty( $this->height ) ) {
$wrapper['style']['height'] = $this->height . 'px';
if ( ! empty( $this->output['clearfix_before'] ) ) {
$wrapper['style']['clear'] = 'both';
* Add a wrapper arount the ad content if wrapper information are given
* @param string $ad_content content of the ad.
* @return string $wrapper ad within the wrapper
protected function add_wrapper( $ad_content = '' ) {
$wrapper_options = apply_filters( 'advanced-ads-output-wrapper-options', $this->wrapper, $this );
if ( $this->label && ! empty( $wrapper_options['style']['height'] ) ) {
// Create another wrapper so that the label does not reduce the height of the ad wrapper.
$height = [ 'style' => [ 'height' => $wrapper_options['style']['height'] ] ];
unset( $wrapper_options['style']['height'] );
$ad_content = '<div' . Advanced_Ads_Utils::build_html_attributes( $height ) . '>' . $ad_content . '</div>';
// Adds inline css to the wrapper.
if ( ! empty( $this->options['inline-css'] ) && $this->args['is_top_level'] ) {
$wrapper_options = $this->inline_css->add_css( $wrapper_options, $this->options['inline-css'], $this->global_output );
! defined( 'ADVANCED_ADS_DISABLE_EDIT_BAR' )
// Add edit button for users with the appropriate rights.
&& WordPress::user_can( 'advanced_ads_edit_ads' )
// We need a wrapper. Check if at least the placement wrapper exists.
&& ! empty( $this->args['placement_type'] )
include ADVADS_ABSPATH . 'public/views/ad-edit-bar.php';
$ad_content = trim( ob_get_clean() ) . $ad_content;
// Include the tooltip title from get_tooltip_title() in the 'title' attribute.
$this->output['wrapper_attrs']['data-title'][] = $this->get_tooltip_title();
// ad Health Tool add class and attribute in to ads and group
if ( WordPress::user_can('advanced_ads_edit_ads') ) {
$has_group_info = isset($this->args['group_info']);
$frontend_prefix = Advanced_Ads_Plugin::get_instance()->get_frontend_prefix();
if ( ! $has_group_info ) {
// Add the 'highlight-wrapper' class to the ad wrapper
$wrapper_options['class'][] = $frontend_prefix . 'highlight-wrapper';
if ('' === ($this->output['wrapper-id'] ?? '')
&& ( [] === $wrapper_options || ! is_array($wrapper_options) )) {
return $this->label . $ad_content;
// create unique id if not yet given.
if ( empty( $wrapper_options['id'] ) ) {
$wrapper_options['id'] = $this->create_wrapper_id();
$this->wrapper['id'] = $wrapper_options['id'];
$wrapper_element = ! empty( $this->args['inline_wrapper_element'] ) ? 'span' : 'div';
$wrapper = '<' . $wrapper_element . Advanced_Ads_Utils::build_html_attributes( array_merge(
isset( $this->output['wrapper_attrs'] ) ? $this->output['wrapper_attrs'] : []
$wrapper .= $this->label;
$wrapper .= apply_filters( 'advanced-ads-output-wrapper-before-content', '', $this );
$wrapper .= apply_filters( 'advanced-ads-output-wrapper-after-content', '', $this );
$wrapper .= '</' . $wrapper_element . '>';
* Create a random wrapper id
* @return string $id random id string
private function create_wrapper_id() {
if ( isset( $this->output['wrapper-id'] ) ) {
$id = sanitize_key( $this->output['wrapper-id'] );
$prefix = Advanced_Ads_Plugin::get_instance()->get_frontend_prefix();
return $prefix . mt_rand();
* Create an "Advertisement" label if conditions are met.
public function maybe_create_label() {
$placement_state = isset( $this->args['ad_label'] ) ? $this->args['ad_label'] : 'default';
$label = Advanced_Ads::get_instance()->get_label( $placement_state );
if ( $this->args['is_top_level'] && $label ) {