: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
'href' => admin_url( 'admin.php?page=advanced-ads' ),
'class' => $issues ? 'advads-adminbar-is-warnings' : '',
// show that there are backend notices.
'parent' => 'advanced_ads_ad_health',
'id' => 'advanced_ads_ad_health_more',
'title' => sprintf( __( 'Show %d more notifications', 'advanced-ads' ), absint( $notices ) ),
'href' => admin_url( 'admin.php?page=advanced-ads' ),
* @param obj $wp_admin_bar WP_Admin_Bar object.
* @param int $issues Number of all issues.
private function add_footer_nodes( $wp_admin_bar, $issues ) {
'parent' => 'advanced_ads_ad_health',
'id' => 'advanced_ads_ad_health_fine',
'title' => __( 'Everything is fine', 'advanced-ads' ),
'parent' => 'advanced_ads_ad_health',
'id' => 'advanced_ads_ad_health_support',
'title' => __( 'Get help', 'advanced-ads' ),
'href' => Advanced_Ads_Plugin::support_url( '?utm_source=advanced-ads&utm_medium=link&utm_campaign=health-support' ),
* Filter out nodes intended to AMP pages only.
* @param array $nodes Nodes to add.
* @return array $nodes Nodes to add.
private function filter_nodes( $nodes ) {
function sort_nodes( $a, $b ) {
if ( ! isset( $a['type'] ) || ! isset( $b['type'] ) ) {
if ( $a['type'] == $b['type'] ) {
return ( $a['type'] < $b['type'] ) ? -1 : 1;
* Set variable to 'true' when 'the_content' filter is invoked.
* @return string $content
public function set_did_the_content( $content ) {
if ( ! $this->did_the_content ) {
$this->did_the_content = true;
if ( Advanced_Ads::get_instance()->has_many_the_content() ) {
$this->has_many_the_content = true;
* Check conditions and display warning.
* jQuery is included in header
* AdSense Quick Start ads are running
public function footer_checks() {
?><!-- Advanced Ads: <?php esc_html_e( 'the following code is used for automatic error detection and only visible to admins', 'advanced-ads' ); ?>-->
<style>#wp-admin-bar-advanced_ads_ad_health .hidden { display: none; }
#wp-admin-bar-advanced_ads_ad_health-default a:after { content: "\25BA"; margin-left: .5em; font-size: smaller; }
#wp-admin-bar-advanced_ads_ad_health-default .advanced_ads_ad_health_highlight_ads div:before { content: "\f177"; margin-right: .2em; line-height: 1em; padding: 0.2em 0 0; color: inherit; }
#wp-admin-bar-advanced_ads_ad_health-default .advanced_ads_ad_health_highlight_ads div:hover { color: #00b9eb; cursor: pointer; }
#wpadminbar .advanced-ads-issue-counter { background-color: #d54e21; display: none; padding: 1px 7px 1px 6px!important; border-radius: 50%; color: #fff; }
#wpadminbar .advads-adminbar-is-warnings .advanced-ads-issue-counter { display: inline; }
.advanced-ads-highlight-ads { outline:4px solid #0474A2 !important; }
#wp-admin-bar-advanced_ads_ad_health .advanced_ads_ad_health_highlight_ads .arrows {display: none;}
#wp-admin-bar-advanced_ads_ad_health .arrows .dashicons {font-family: 'dashicons';}
#wp-admin-bar-advanced_ads_ad_health.hover .advanced_ads_ad_health_highlight_ads.active .arrows {display: inline-block;}
$adsense_options = Advanced_Ads_AdSense_Data::get_instance()->get_options();
<script type="text/javascript" src="<?php echo ADVADS_BASE_URL . 'admin/assets/js/advertisement.js' ?>"></script>
var advanced_ads_frontend_checks = {
// Count only warnings that have the 'advanced_ads_ad_health_warning' class.
var warning_count = document.querySelectorAll( '.advanced_ads_ad_health_warning:not(.hidden)' ).length;
var fine_item = document.getElementById( 'wp-admin-bar-advanced_ads_ad_health_fine' );
} catch ( e ) { return; }
var header = document.querySelector( '#wp-admin-bar-advanced_ads_ad_health > a' );
fine_item.className += ' hidden';
header.innerHTML = header.innerHTML.replace(/<span class="advanced-ads-issue-counter">\d*<\/span>/, '') + '<span class="advanced-ads-issue-counter">' + warning_count + '</span>';
header.className += ' advads-adminbar-is-warnings';
fine_item.classList.remove('hidden');
header.innerHTML = header.innerHTML.replace(/<span class="advanced-ads-issue-counter">\d*<\/span>/, '');
header.classList.remove('advads-adminbar-is-warnings');
array_unique: function( array ) {
for ( var i = 0; i < array.length; i++ ) {
if ( r.indexOf( array[ i ] ) === -1 ) {
* Add item to Ad Health node.
* @param string selector Selector of the node.
* @param string/array item item(s) to add.
add_item_to_node: function( selector, item ) {
if ( typeof item === 'string' ) {
var selector = document.querySelector( selector );
selector.className = selector.className.replace( 'hidden', '' );
selector.innerHTML = selector.innerHTML.replace( /(<i>)(.*?)(<\/i>)/, function( match, p1, p2, p3 ) {
p2 = ( p2 ) ? p2.split( ', ' ) : [];
p2 = advanced_ads_frontend_checks.array_unique( p2 );
return p1 + p2.join( ', ' ) + p3;
advanced_ads_frontend_checks.showCount();
* Add item to Ad Health notices in the backend
* @param key of the notice
add_item_to_notices: function( key, attr = '' ) {
var cookie = advads.get_cookie( 'advanced_ads_ad_health_notices' );
advads_cookie_notices = JSON.parse( cookie );
advads_cookie_notices = new Array();
// stop if notice was added less than 1 hour ago
if ( 0 <= advads_cookie_notices.indexOf( key ) ){
action: 'advads-ad-health-notice-push',
nonce: '<?php echo wp_create_nonce('advanced-ads-ad-health-ajax-nonce'); ?>'
// update notices and cookie
jQuery.post( advads_frontend_checks.ajax_url, query, function (r) {
advads_cookie_notices.push( key );
var notices_str = JSON.stringify( advads_cookie_notices );
advads.set_cookie_sec( 'advanced_ads_ad_health_notices', notices_str, 3600 ); // 1 hour
* Search for hidden AdSense.
* @param string context Context for search.
advads_highlight_hidden_adsense: function( context ) {
var responsive_zero_width = [];
jQuery( 'ins.adsbygoogle', context ).each( function() {
// Zero width, perhaps because a parent container is floated
if ( jQuery( this ).attr( 'data-ad-format' ) && 0 === jQuery( this ).width() ) {
responsive_zero_width.push( this.dataset.adSlot );
if ( responsive_zero_width.length ) {
advanced_ads_frontend_checks.add_item_to_node( '.advanced_ads_ad_health_floated_responsive_adsense', responsive_zero_width );
// highlight link as global
var highlightLink = d.getElementById( 'wp-admin-bar-advanced_ads_ad_health_highlight_ads' );
// update ad count in health tool admin bar
var addEvent = function( obj, type, fn ) {
if ( obj.addEventListener )
obj.addEventListener( type, fn, false );
else if ( obj.attachEvent )
obj.attachEvent( 'on' + type, function() { return fn.call( obj, window.event ); } );
function getAdWrappers() {
return document.querySelectorAll(".<?php echo Advanced_Ads_Plugin::get_instance()->get_frontend_prefix(); ?>highlight-wrapper, .google-auto-placed");
// highlight ads that use Advanced Ads placements or AdSense Auto ads
function highlightAds() {
* Placement container: ".<?php echo Advanced_Ads_Plugin::get_instance()->get_frontend_prefix(); ?>highlight-wrapper, .google-auto-placed"
* AdSense Auto ads: 'google-auto-placed'
<?php //phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
adWrappers = getAdWrappers();
} catch ( e ) { return; }
for ( i = 0; i < adWrappers.length; i++ ) {
// Check highlighted ads active
adWrappers[i].classList.toggle('advanced-ads-highlight-ads');
// show title only when highlight ads active.
if ( adWrappers[i].classList.contains('advanced-ads-highlight-ads') ) {
adWrappers[i].title = adWrappers[i].getAttribute('data-title');
adWrappers[i].title = '';
// add or remove active class from highlight link
highlightLink.classList.toggle('active');
function scrollToHighlightedAd() {
// If no ad wrappers are found, exit the function
if (adWrappers.length === 0) return;
// Initialize or update the index of the currently highlighted ad
if (typeof window.current_highlighted_ad === "undefined") {
window.current_highlighted_ad = 0;
} else if (this.classList.contains('next') && adWrappers.length - 1 > window.current_highlighted_ad) {
window.current_highlighted_ad++;
} else if (this.classList.contains('previous') && window.current_highlighted_ad > 0) {
window.current_highlighted_ad--;
// Get the offsetTop of the currently highlighted ad's wrapper
const scrollDiv = document.getElementById(adWrappers[window.current_highlighted_ad]?.id)?.offsetTop;
// If scrollDiv is defined, scroll to the ad wrapper's position
if (scrollDiv !== undefined) {
window.scrollTo({ top: scrollDiv, behavior: 'smooth' });
// Handle any errors that might occur
advanced_ads_ready( function() {
var adblock_item = d.getElementById( 'wp-admin-bar-advanced_ads_ad_health_adblocker_enabled' );
// handle click on the highlightAds link
var link = highlightLink.querySelector('.link');
addEvent( link, 'click', highlightAds );
var arrows = highlightLink.querySelector('.arrows').querySelectorAll('.dashicons');
for ( let i = 0; i < arrows.length; i++ ) {
arrows[i].addEventListener("click", scrollToHighlightedAd);
if ( adblock_item && typeof advanced_ads_adblocker_test === 'undefined' ) {
adblock_item.className = adblock_item.className.replace( /hidden/, '' );
<?php if ( ! $this->did_the_content ) : ?>
var the_content_item = d.getElementById( 'wp-admin-bar-advanced_ads_ad_health_the_content_not_invoked' );
if ( the_content_item ) {
the_content_item.className = the_content_item.className.replace( /hidden/, '' );
advanced_ads_frontend_checks.showCount();
<?php if ( ! isset( $adsense_options['violation-warnings-disable'] ) ) : ?>
// show warning if AdSense ad is hidden
// show hint if AdSense Auto ads are enabled
advanced_ads_ready( advanced_ads_frontend_checks.advads_highlight_hidden_adsense );
// highlight AdSense Auto Ads ads 3 seconds after site loaded
advanced_ads_ready( advads_highlight_adsense_autoads );
function advads_highlight_adsense_autoads(){
window.console && window.console.log( 'Advanced Ads: jQuery not found. Some Ad Health warnings will not be displayed.' );
var autoads_ads = document.querySelectorAll('.google-auto-placed');
// show Auto Ads warning in Ad Health bar if relevant
if ( autoads_ads.length ){
var advads_autoads_link = document.querySelector( '#wp-admin-bar-advanced_ads_autoads_displayed.hidden' );
if ( advads_autoads_link ) {
advads_autoads_link.className = advads_autoads_link.className.replace( 'hidden', '' );
advanced_ads_frontend_checks.showCount();
* Code to check if current user gave consent to show ads
$privacy = Advanced_Ads_Privacy::get_instance();
if ( 'not_needed' !== $privacy->get_state() ) :
document.addEventListener('advanced_ads_privacy', function (event) {
var advads_consent_link = document.querySelector('#wp-admin-bar-advanced_ads_ad_health_consent_missing');
if (!advads_consent_link) {
if (event.detail.state !== 'accepted' && event.detail.state !== 'not_needed') {
advads_consent_link.classList.remove('hidden');
advads_consent_link.classList.add('hidden');
advanced_ads_frontend_checks.showCount();
$privacy_options = $privacy->options();
( empty( $privacy_options['enabled'] ) || 'iab_tcf_20' !== $privacy_options['consent-method'] )
&& (bool) apply_filters( 'advanced-ads-ad-health-show-tcf-notice', true )
tcfapiInterval = setInterval(function () {
clearInterval(tcfapiInterval);
if (typeof window.__tcfapi === 'undefined') {
clearInterval(tcfapiInterval);
var advadsPrivacyLink = document.querySelector('#wp-admin-bar-advanced_ads_ad_health_privacy_disabled');
if (!advadsPrivacyLink) {
advadsPrivacyLink.classList.remove('hidden');
advanced_ads_frontend_checks.showCount();
* show Google Ad Manager debug link in Ad Health
* look for container with ID starting with `div-gpt-ad-`
* or `gpt-ad-` as used by our own Google Ad Manager integration
* we don’t look for the gpt header script because that is also used by other services that are based on Google Publisher Tags
function advadsGamShowDebugLink(){
var advadsGamDebugLink = document.querySelector( '.advanced_ads_ad_health_gam_debug_link.hidden' );
if ( ! advadsGamDebugLink ){
// Check for the `googletag` variable created in the page header or directly in the body alongside the ad slot definition.
if ( typeof window.googletag !== 'undefined' ) {
advadsGamDebugLink.className = advadsGamDebugLink.className.replace( 'hidden', '' );
// look for Google Ad Manager tags with a delay of 2 seconds
advanced_ads_ready( advadsGamShowDebugLink );
// Function to count visible ads with unique group IDs
// Get all elements with the specified class name
const adWrappers = getAdWrappers();
// Initialize a count for visible ads
// Loop through each ad wrapper element
for ( let i = 0; i < adWrappers.length; i++ ) {
// Check if the group ID is either null or not included in the array of seen group IDs.
if ( adWrappers[i].offsetHeight > 0 ) {
// Increment the ad count and add the group ID to the list.
// Return the total count of eligible ads
function updateAdsCount(d){
var highlightLink = d.getElementById( 'wp-admin-bar-advanced_ads_ad_health_highlight_ads' );
// update ad count in health tool admin bar
highlightLink.querySelector('.link').innerHTML += ' (<span class="highlighted_ads_count">' + getAdsCount() + '</span>) ';
// If any ads load by ajax its update count after ajax load
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
this.addEventListener('load', function() {
if ( this.status === 200 ) {
highlightLink.querySelector('.highlighted_ads_count').innerHTML = getAdsCount();
origOpen.apply(this, arguments);
<?php echo Advanced_Ads_Utils::get_inline_asset( ob_get_clean() );
* Inject JS after ad content.
* @param str $content ad content.
* @param obj $ad Advanced_Ads_Ad.
* @return str $content ad content
public function after_ad_output( $content, Advanced_Ads_Ad $ad ) {