current_ads += $ad_ids; } $defered_ads = isset( $_REQUEST['deferedAds'] ) ? $_REQUEST['deferedAds'] : null; if ( $defered_ads ) { // Load all ajax ads with a single request. $response = array(); $requests_by_blog = array(); foreach ( (array) $defered_ads as $request ) { $blog_id = isset( $request['blog_id'] ) ? $request['blog_id'] : get_current_blog_id(); $requests_by_blog[ $blog_id ][] = $request; } foreach ( $requests_by_blog as $blog_id => $requests ) { if ( get_current_blog_id() !== $blog_id ) { Advanced_Ads::get_instance()->switch_to_blog( $blog_id ); } foreach ( $requests as $request ) { $result = $this->select_one( $request ); $result['elementId'] = ! empty( $request['elementId'] ) ? $request['elementId'] : null; $response[] = $result; } if ( get_current_blog_id() !== $blog_id ) { Advanced_Ads::get_instance()->restore_current_blog(); } } echo wp_json_encode( $response ); die(); } $response = $this->select_one( $_REQUEST ); echo wp_json_encode( $response ); die(); } /** * Provides a single ad (ad, group, placement) given ID and selection method. * * @param array $request request. * * @return array */ private function select_one( $request ) { // Init handlers. $selector = Advanced_Ads_Select::get_instance(); $methods = $selector->get_methods(); $method = isset( $request['ad_method'] ) ? (string) $request['ad_method'] : null; $id = isset( $request['ad_id'] ) ? (string) $request['ad_id'] : null; $arguments = isset( $request['ad_args'] ) ? $request['ad_args'] : array(); if ( is_string( $arguments ) ) { $arguments = stripslashes( $arguments ); $arguments = json_decode( $arguments, true ); } if ( ! empty( $request['elementId'] ) ) { $arguments['cache_busting_elementid'] = $request['elementId']; } if ( ! array_key_exists( $method, $methods ) || empty( $id ) ) { // Report error. return array( 'status' => 'error', 'message' => 'No valid ID or METHOD found.', ); } /** * Filters the received arguments before passing them to to ads/groups/placements. * * @param array $arguments Existing arguments. * @param array $request Request data. */ $arguments = apply_filters( 'advanced-ads-ajax-ad-select-arguments', $arguments, $request ); $advads = Advanced_Ads::get_instance(); $previous_ads = $advads->current_ads; add_filter( 'advanced-ads-can-display', array( $this, 'can_display_by_consent' ), 10, 2 ); $content = $selector->get_ad_by_method( $id, $method, $arguments ); if ( empty( $content ) ) { return array( 'status' => 'error', 'message' => 'No displayable ad found for privacy settings.', ); } $response = array( 'status' => 'success', 'item' => $content, 'id' => $id, 'method' => $method, 'ads' => array_slice( $advads->current_ads, count( $previous_ads ) ), 'blog_id' => get_current_blog_id(), ); return apply_filters( 'advanced-ads-cache-busting-item', $response, array( 'id' => $id, 'method' => $method, 'args' => $arguments, ) ); } /** * Push an Ad Health notice to the queue in the backend */ public function ad_health_notice_push() { check_ajax_referer( 'advanced-ads-ad-health-ajax-nonce', 'nonce' ); if ( ! current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_edit_ads' ) ) ) { return; } $key = ( ! empty( $_REQUEST['key'] ) ) ? esc_attr( $_REQUEST['key'] ) : false; $attr = ( ! empty( $_REQUEST['attr'] ) && is_array( $_REQUEST['attr'] ) ) ? $_REQUEST['attr'] : array(); // Update or new entry? if ( isset( $attr['mode'] ) && 'update' === $attr['mode'] ) { Advanced_Ads_Ad_Health_Notices::get_instance()->update( $key, $attr ); } else { Advanced_Ads_Ad_Health_Notices::get_instance()->add( $key, $attr ); } die(); } /** * Update frontend notice array */ public function frontend_notice_update() { check_ajax_referer( 'advanced-ads-frontend-notice-nonce', 'nonce' ); if ( ! current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_edit_ads' ) ) ) { return; } $key = ( ! empty( $_REQUEST['key'] ) ) ? esc_attr( $_REQUEST['key'] ) : false; $attr = ( ! empty( $_REQUEST['attr'] ) && is_array( $_REQUEST['attr'] ) ) ? $_REQUEST['attr'] : array(); // Update or new entry? if ( isset( $attr['mode'] ) && 'update' === $attr['mode'] ) { die(); // Advanced_Ads_Frontend_Notices::get_instance()->update( $key, $attr );. } else { Advanced_Ads_Frontend_Notices::get_instance()->update( $key, $attr ); } die(); } /** * Check if AJAX ad can be displayed, with consent information sent in request. * * @param bool $can_display Whether this ad can be displayed. * @param Advanced_Ads_Ad $ad The ad object. * * @return bool */ public function can_display_by_consent( $can_display, $ad ) { // already false, honor this. if ( ! $can_display ) { return $can_display; } // If consent is overridden for the ad. if ( ! empty( $ad->options()['privacy']['ignore-consent'] ) ) { return true; } // if privacy module is not active, we can display. $privacy = Advanced_Ads_Privacy::get_instance(); $privacy_options = $privacy->options(); if ( empty( $privacy_options['enabled'] ) ) { return true; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce should be verified in ajax handler. $consent_state = sanitize_text_field( $_REQUEST['consent'] ); // Consent is either given or not needed. if ( in_array( $consent_state, array( 'not_needed', 'accepted' ), true ) ) { return true; } // If there is custom code, don't display the ad (unless it's a group). if ( class_exists( 'Advanced_Ads_Pro' ) && ! empty( Advanced_Ads_Pro::get_instance()->get_custom_code( $ad ) ) && $ad->type !== 'group' ) { return false; } // See if this ad type needs consent. return ! $privacy->ad_type_needs_consent( $ad->type ); } }