: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
} elseif ( isset( $query['is_singular'] ) && $query['is_singular'] && ! self::can_display_ids( $options['value'], $term_ids, $operator )
* Check taxonomy archive display condition in frontend
* @param array $options options of the condition.
* @param Advanced_Ads_Ad $ad ad.
* @return bool true if can be displayed
public static function check_taxonomy_archive( $options, Advanced_Ads_Ad $ad ) {
if ( ! isset( $options['value'] ) ) {
if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
$ad_options = $ad->options();
$query = $ad_options['wp_the_query'];
// return false if operator is "is", but important query vars are not given.
if ( 'is' === $operator && ( empty( $query['term_id'] ) || empty( $query['is_archive'] ) ) ) {
} elseif ( isset( $query['term_id'] ) && isset( $query['is_archive'] ) && $query['is_archive'] && ! self::can_display_ids( $query['term_id'], $options['value'], $operator )
* Check if a specific archive belongs to a taxonomy in general (not a specific term)
* @param array $options options of the condition.
* @param Advanced_Ads_Ad $ad ad.
* @return bool true if can be displayed
public static function check_taxonomy( $options, Advanced_Ads_Ad $ad ) {
if ( ! isset( $options['value'] ) ) {
if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
$ad_options = $ad->options();
$query = $ad_options['wp_the_query'];
// return false if operator is "is", but important query vars are not given.
if ( 'is' === $operator && ( empty( $query['taxonomy'] ) || empty( $query['is_archive'] ) ) ) {
} elseif ( isset( $query['taxonomy'] ) && isset( $query['is_archive'] ) && $query['is_archive'] && ! self::can_display_ids( $query['taxonomy'], $options['value'], $operator )
* Check post ids display condition in frontend
* @param array $options options of the condition.
* @param Advanced_Ads_Ad $ad ad.
* @return bool true if can be displayed
public static function check_post_ids( $options, Advanced_Ads_Ad $ad ) {
if ( isset( $options['operator'] ) && 'is_not' === $options['operator'] ) {
$ad_options = $ad->options();
$query = $ad_options['wp_the_query'];
$post_id = isset( $ad_options['post']['id'] ) ? $ad_options['post']['id'] : null;
// fixes page id on BuddyPress pages.
if ( 0 === $post_id && class_exists( 'BuddyPress' ) && function_exists( 'bp_current_component' ) ) {
$component = bp_current_component();
$bp_pages = get_option( 'bp-pages' );
if ( isset( $bp_pages[ $component ] ) ) {
$post_id = $bp_pages[ $component ];
* WooCommerce Store page fix
* since WooCommerce changes the post ID of the static page selected to be the product overview page, we need to get the original page id from the WC options
if ( function_exists( 'is_shop' ) && is_shop() && isset( $options['value'] ) && is_array( $options['value'] ) ) {
$post_id = get_option( 'woocommerce_shop_page_id' );
return self::can_display_ids( $post_id, $options['value'], $operator );
if ( empty( $ad_options['wp_the_query']['is_singular'] ) ) {
if ( 'is_not' === $operator ) {
if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) || ! $post_id ) {
return self::can_display_ids( $post_id, $options['value'], $operator );
* Check general display conditions in frontend
* @param array $options options of the condition.
* @param Advanced_Ads_Ad $ad ad.
* @return bool true if can be displayed
public static function check_general( $options, Advanced_Ads_Ad $ad ) {
if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) || ! count( $options['value'] ) ) {
// check general conditions added by other add-ons.
$result = apply_filters( 'advanced-ads-display-conditions-check-general', null, $options['value'] );
if ( null !== ( $result ) ) {
// skip checks, if general conditions are unchanged.
if ( self::$default_general_keys === $options['value'] ) {
$ad_options = $ad->options();
$query = $ad_options['wp_the_query'];
if ( isset( $query['is_main_query'] ) && ! $query['is_main_query'] && ! in_array( 'is_main_query', $options['value'], true ) ) {
if ( isset( $query['is_rest_api'] ) && $query['is_rest_api'] && ! in_array( 'is_rest_api', $options['value'], true ) ) {
( ( isset( $query['is_front_page'] ) && $query['is_front_page'] ) || ( isset( $query['is_home'] ) && $query['is_home'] ) )
&& in_array( 'is_front_page', $options['value'], true )
} elseif ( isset( $query['is_front_page'] ) && $query['is_front_page'] && ( ! in_array( 'is_front_page', $options['value'], true ) ) ) {
foreach ( self::$query_var_keys as $_type ) {
if ( 'is_main_query' !== $_type && isset( $query[ $_type ] ) && $query[ $_type ] &&
in_array( $_type, $options['value'], true ) ) {
* Check 'content age' condition in frontend.
* @param array $options options of the condition.
* @param Advanced_Ads_Ad $ad ad.
* @return bool true if can be displayed
public static function check_content_age( $options, Advanced_Ads_Ad $ad ) {
&& isset( $_REQUEST['action'], $_REQUEST['theId'], $_REQUEST['isSingular'] )
&& sanitize_key( $_REQUEST['action'] ) === 'advads_ad_select'
&& ( $_REQUEST['isSingular'] )
$post = get_post( (int) $_REQUEST['theId'] );
$operator = ( isset( $options['operator'] ) && 'younger_than' === $options['operator'] ) ? 'younger_than' : 'older_than';
$value = isset( $options['value'] ) ? $options['value'] : '';
if ( empty( $post->ID ) || empty( $value ) ) {
// get post publish date in unix timestamp.
$publish_time = get_the_time( 'U', $post->ID );
// get difference from now.
$diff_from_now = time() - $publish_time;
// check against entered age.
$value_in_seconds = DAY_IN_SECONDS * $value;
if ( 'younger_than' === $operator ) {
return $diff_from_now < $value_in_seconds;
return $diff_from_now > $value_in_seconds;
* Helper function to check for in array values
* @param mixed $id scalar (key) or array of keys as needle.
* @param array $ids haystack.
* @return boolean void if either argument is empty
public static function in_array( $id, $ids ) {
if ( ! isset( $id ) || [] === $id ) {
if ( ! is_array( $ids ) ) {
return is_array( $id ) ? [] !== array_intersect( $id, $ids ) : in_array( $id, $ids );
* @param array $needle ids that should be searched for in haystack.
* @param array $haystack reference ids.
* @param string $operator whether it should be included or not.
public static function can_display_ids( $needle, $haystack, $operator = 'is' ) {
if ( 'is' === $operator && self::in_array( $needle, $haystack ) === false ) {
if ( 'is_not' === $operator && self::in_array( $needle, $haystack ) === true ) {
* Check display conditions
* @param bool $can_display whether the current ad can be displayed based on the checks that ran by now.
* @param Advanced_Ads_Ad $ad ad object.
* @return bool $can_display true if can be displayed in frontend
* @since 1.1.0 moved here from can_display()
* @since 1.7.0 moved here from display-by-query module
public function can_display( $can_display, $ad ) {
$options = $ad->options();
// test if anything is to be limited at all.
! isset( $options['conditions'] ) || ! is_array( $options['conditions'] )
// query arguments required.
|| ! isset( $options['wp_the_query'] )
// get conditions with rebased index keys.
$conditions = array_values( $options['conditions'] );
$query = $options['wp_the_query'];
$post = isset( $options['post'] ) ? $options['post'] : null;
$length = count( $conditions );
for ( $i = 0; $i < $length; ++$i ) {
$_condition = current( $conditions );
$next = next( $conditions );
$next_key = key( $conditions );
* Force next condition’s connector to OR if
* this condition and the next are from the same taxonomy
* the conditions don’t have the same condition type
* they are both set to SHOW
$tax = ( isset( $_condition['type'] ) && isset( $this->conditions[ $_condition['type'] ]['taxonomy'] ) ) ? $this->conditions[ $_condition['type'] ]['taxonomy'] : false;
$next_tax = ( isset( $next['type'] ) && isset( $this->conditions[ $next['type'] ]['taxonomy'] ) ) ? $this->conditions[ $next['type'] ]['taxonomy'] : false;
if ( $tax && $next_tax && $next_key
&& ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] )
&& 'is' === $_condition['operator'] && 'is' === $next['operator']
&& $_condition['type'] !== $next['type']
$next['connector'] = 'or';
$conditions[ $next_key ]['connector'] = 'or';
// ignore OR if last result was true.
if ( $last_result && isset( $_condition['connector'] ) && 'or' === $_condition['connector'] ) {
$result = self::frontend_check( $_condition, $ad );
// return false only, if the next condition doesn’t have an OR operator.
if ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] ) {
* On demand provide current query arguments to ads.
* Existing arguments must not be overridden.
* Some arguments might be cachable.
* @param array $args arguments.
public function ad_select_args_callback( $args ) {
global $post, $wp_the_query, $wp_query, $numpages;
if ( $post instanceof WP_Post ) {
if ( ! isset( $args['post'] ) ) {
if ( ! isset( $args['post']['id'] ) ) {
// if currently on a single site, use the main query information just in case a custom query is broken.
if ( isset( $wp_the_query->post->ID ) && $wp_the_query->is_single() ) {
$args['post']['id'] = $wp_the_query->post->ID;
$args['post']['id'] = $post->ID;
if ( ! isset( $args['post']['author'] ) ) {
// if currently on a single site, use the main query information just in case a custom query is broken.
if ( isset( $wp_the_query->post->post_author ) && $wp_the_query->is_single() ) {
$args['post']['author'] = $wp_the_query->post->post_author;
// a user reported that the missing $post_author property issue appeared so let’s check if it exists.
$args['post']['author'] = isset( $post->post_author ) ? $post->post_author : '';
if ( ! isset( $args['post']['post_type'] ) ) {
// if currently on a single site, use the main query information just in case a custom query is broken.
if ( isset( $wp_the_query->post->post_type ) && $wp_the_query->is_single() ) {
$args['post']['post_type'] = $wp_the_query->post->post_type;
// a user reported that the missing $post_type property issue appeared so let’s check if it exists.
$args['post']['post_type'] = isset( $post->post_type ) ? $post->post_type : '';
if ( isset( $wp_the_query ) ) {
if ( ! isset( $args['wp_the_query'] ) ) {
$args['wp_the_query'] = [];
$query = $wp_the_query->get_queried_object();
// term_id exists only for taxonomy archive pages.
if ( ! isset( $args['wp_the_query']['term_id'] ) && $query ) {
$args['wp_the_query']['term_id'] = isset( $query->term_id ) ? $query->term_id : '';
if ( ! isset( $args['wp_the_query']['taxonomy'] ) && $query ) {
$args['wp_the_query']['taxonomy'] = isset( $query->taxonomy ) ? $query->taxonomy : '';
if ( ! isset( $args['wp_the_query']['is_main_query'] ) ) {
$args['wp_the_query']['is_main_query'] = Advanced_Ads::get_instance()->is_main_query();
if ( ! isset( $args['wp_the_query']['is_rest_api'] ) ) {
$args['wp_the_query']['is_rest_api'] = defined( 'REST_REQUEST' ) && REST_REQUEST;
// `<!-- nextpage -->` tags.
if ( ! isset( $args['wp_the_query']['page'] ) ) {
$args['wp_the_query']['page'] = isset( $wp_the_query->query_vars['page'] ) && $wp_the_query->query_vars['page'] ? $wp_the_query->query_vars['page'] : 1;
$args['wp_the_query']['numpages'] = isset( $numpages ) ? $numpages : 1;
foreach ( self::$query_var_keys as $key ) {
if ( ! isset( $args['wp_the_query'][ $key ] ) ) {
$args['wp_the_query'][ $key ] = $wp_the_query->$key();
* ;odify post search query to search by post_title or ID
* @param array $query post search query.
public static function modify_post_search( $query ) {
// use ID and not search field if ID given.
if ( 0 !== absint( $query['s'] ) && strlen( $query['s'] ) === strlen( absint( $query['s'] ) ) ) {
$query['post__in'] = [ absint( $query['s'] ) ];
$query['suppress_filters'] = false;
$query['orderby'] = 'post_title';
$query['post_status'] = [ 'publish', 'pending', 'draft', 'future' ];
* Modify post search SQL to search only in post title
* @param string $sql SQL statement.
public static function modify_post_search_sql( $sql ) {
// removes the search in content and excerpt columns.
$sql = preg_replace( "/OR \({$wpdb->posts}.post_(content|excerpt)( NOT)? LIKE '(.*?)'\)/", '', $sql );
* Preg_replace callback used in modify_post_search_sql()
* @param array $matches results for post search.
* @deprecated since version 1.8.16
public static function modify_post_search_sql_callback( $matches ) {
if ( 'content' === $matches[1] && preg_match( '@^([0-9]+)$@', $matches[3], $matches_id ) ) {
$equals_op = ' NOT' === $matches[2] ? '!=' : '=';
return "{$wpdb->posts}.ID$equals_op$matches_id[1]";
} elseif ( ' NOT' === $matches[2] ) {