: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Set the active tab and optionally scroll to the anchor.
function advads_set_tab( tab ) {
jQuery( '#advads-tabs' ).find( 'a' ).removeClass( 'nav-tab-active' );
jQuery( '.advads-tab' ).removeClass( 'active' );
jQuery( '#' + tab.tab ).addClass( 'active' );
jQuery( '#' + tab.tab + '-tab' ).addClass( 'nav-tab-active' );
var anchor_offset = document.getElementById( tab.anchor ).getBoundingClientRect().top;
window.scrollTo( 0, anchor_offset + window.scrollY - admin_bar );
// While user is already on the Settings page, find links (in admin menu,
// in the Checks at the top, in the notices at the top) to particular setting tabs and open them on click.
jQuery( document ).on( 'click', 'a[href*="page=advanced-ads-settings"]:not(.nav-tab)', function () {
// Already on the Settings page, so set the new tab.
// Extract the tab id from the url.
var url = jQuery( this ).attr( 'href' ).split( 'advanced-ads-settings' )[1];
var tab = advads_extract_tab( url );
* Handle the hashchange event, this enables back/forward navigation in the settings page.
window.addEventListener( 'hashchange', event => {
const hash = advads_extract_tab( new URL( event.newURL ).hash );
document.getElementById( hash.tab + '-tab' ).dispatchEvent( new Event( 'click' ) );
// fail silently if element does not exist.
// activate specific or first tab
var active_tab = advads_extract_tab( window.location.hash );
advads_set_tab( active_tab );
// dynamically generate the sub-menu
jQuery( '.advads-tab-sub-menu' ).each( function ( key, e ) {
// abort if scrollIntoView is not supported; we can’t use anchors because they are used for tabs already
if ( typeof e.scrollIntoView !== 'function' ) {
advads_settings_parent_tab = jQuery( e ).parent( '.advads-tab' );
var headlines = advads_settings_parent_tab.find( 'h2' );
if ( headlines.length > 1 ) {
advads_submenu_list = jQuery( '<ul>' );
headlines.each( function ( key, h ) {
// create anchor for this headline
var headline_id = 'advads-tab-headline-' + advads_settings_parent_tab.attr( 'id' ) + key;
jQuery( h ).attr( 'id', headline_id );
// place the link in the top menu
var text = text = h.textContent || h.innerText;
jQuery( '<li><a onclick="document.getElementById(\'' + headline_id + '\').scrollIntoView()">' + text + '</a></li>' ).appendTo( advads_submenu_list );
advads_submenu_list.appendTo( e );
// OVERVIEW LIST (Ads, Groups, Placements)
// toggle page filters, excluded from the Ads list since the search markup is not editable by us.
$( 'body:not(.post-type-advanced_ads ) #advads-show-filters' ).on( 'click', function() {
const disabled = $( this ).find( '.dashicons' ).hasClass( 'dashicons-arrow-up' );
$( '.advads-toggle-with-filters-button' ).toggleClass( 'hidden', disabled );
$( '#advads-show-filters .dashicons' ).toggleClass( 'dashicons-filter', disabled );
$( '#advads-show-filters .dashicons' ).toggleClass( 'dashicons-arrow-up', ! disabled );
// show the bulk actions sticky, when some lines are selected
$( '.post-type-advanced_ads .check-column input[type="checkbox"]' ).on( 'change', function() {
$( '.post-type-advanced_ads .tablenav.bottom .bulkactions' ).toggleClass( 'fixed', 0 < $( '.post-type-advanced_ads .check-column input[type="checkbox"]:checked' ).length );
// show screen options when clicking on our custom link or the Close button
$( '#advads-show-screen-options' ).on( 'click', function(){
$( '#show-settings-link' ).trigger( 'click' );
// Add a close button to the screen options
$( '<button type="button" class="button advads-button-secondary">' + advadstxt.close + '</button>' )
.appendTo( $( '.post-type-advanced_ads #adv-settings .submit' ) )
.on( 'click', function() { $( '#show-settings-link' ).trigger( 'click' ); } );
var set_touched_placement = function() {
var tr = $( this ).closest( 'tr.advanced-ads-placement-row' )
tr.data( 'touched', true )
// keep track of placements that were changed
$( 'form#advanced-ads-placements-form input, #advanced-ads-placements-form select' ).on( 'change', set_touched_placement )
$( 'form#advanced-ads-placements-form button' ).on( 'click', set_touched_placement )
// some special form elements overwrite the jquery listeners (or render them unusable in some strange way)
// to counter that and make it more robust in general, we now listen for mouseover events, that will
// only occur, when the settings of a placement are expanded (let's just assume this means editing)
$( 'form#advanced-ads-placements-form .advads-modal' ).on( 'mouseover', set_touched_placement )
// if the modal is canceled, remove the "touched" data again, since the user discarded any changes.
$( document ).on( 'advads-modal-canceled', event => {
const $placementRow = $( '#' + event.detail.modal_id ).parents( '.advanced-ads-placement-row' );
if ( ! $placementRow.length ) {
$placementRow.data( 'touched', false );
// on submit remove placements that were untouched
$( 'form#advanced-ads-placements-form' ).on( 'submit', function () {
var grouprows = jQuery( 'form#advanced-ads-placements-form tr.advanced-ads-placement-row' )
jQuery( 'form#advanced-ads-placements-form tr.advanced-ads-placement-row' ).each( function ( k, v ) {
if ( ! v.data( 'touched' ) ) {
v.find( 'input, select' ).each( function ( k2, v2 ) {
v2.prop( 'disabled', true )
// show input field for custom xpath rule when "custom" option is selected for Content placement
// iterate through all tag options of all placements
$( '.advads-placements-content-tag' ).each( function(){
advads_show_placement_content_xpath_field( this );
// update xpath field when tag option changes
$( '.advads-placements-content-tag' ).on( 'change', function () {
advads_show_placement_content_xpath_field( this );
* show / hide input field for xpath rule
function advads_show_placement_content_xpath_field( tag_field ){
// get the value of the content tag option
var tag = $( tag_field ).find( 'option:selected').val();
// show or hide the next following custom xpath option
$( tag_field ).next( '.advads-placements-content-custom-xpath' ).show();
$( tag_field ).next( '.advads-placements-content-custom-xpath' ).hide();
// show tooltips for group type or placement type in forms
$( '.advads-form-type' ).advads_tooltip( {
return jQuery( this ).find( '.advads-form-description' ).html()
const modal = $target.parents( '.advads-modal' );
return modal.length ? '#'+modal[0].id : 'body';
* On the placements and ad edit page, check if the form values have changed on beforeunload.
* On the settings page, additionally check for a tab change.
const advadsTermination = ( () => {
if ( window.advadstxt.admin_page === 'advanced-ads_page_advanced-ads-placements' ) {
form = document.getElementById( 'advanced-ads-placements-form' );
termination = new Advads_Termination( form );
if ( window.advadstxt.admin_page === 'advanced_ads' ) {
// prevent errors on back/forward navigation
form = document.getElementById( 'post' );
termination = new Advads_Termination( form );
if ( window.advadstxt.admin_page === 'advanced-ads_page_advanced-ads-settings' ) {
form = document.querySelector( '.advads-tab.active > form' );
termination = new Advads_Termination( form );
[...document.getElementsByClassName( 'nav-tab' )].forEach( tab => {
tab.addEventListener( 'click', event => {
if ( ! termination.terminationNotice() ) {
advads_set_tab( advads_extract_tab( new URL( event.target.href ).hash ) );
form = document.querySelector( '.advads-tab.active > form' );
termination = new Advads_Termination( form );
termination.collectValues();
// if the form is submitted, don't fire the beforeunload handler.
form.addEventListener( 'submit', () => {
if ( typeof termination !== 'undefined' ) {
termination.collectValues();
const beforeUnloadHandler = event => {
if ( ! submitted && ! termination.terminationNotice() ) {
event.returnValue = 'string';
window.addEventListener( 'beforeunload', beforeUnloadHandler );
// if the form is submitted, don't fire the beforeunload handler.
form.addEventListener( 'submit', () => {
$( 'body' ).on( 'click', '.advads_image_upload', function ( e ) {
// If the media frame already exists, reopen it.
// file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media( {
id: 'advads_type_image_wp_media',
title: button.data( 'uploaderTitle' ),
text: button.data( 'uploaderButtonText' )
multiple: false // only allow one file to be selected
// When an image is selected, run a callback.
file_frame.on( 'select', function () {
var selection = file_frame.state().get( 'selection' )
selection.each( function ( attachment, index ) {
attachment = attachment.toJSON()
// place first attachment in field
$( '#advads-image-id' ).val( attachment.id )
$( '#advanced-ads-ad-parameters-size input[name="advanced_ad[width]"]' ).val( attachment.width )
$( '#advanced-ads-ad-parameters-size input[name="advanced_ad[height]"]' ).val( attachment.height )
var new_image = '<img width="' + attachment.width + '" height="' + attachment.height +
'" title="' + attachment.title + '" alt="' + attachment.alt + '" src="' + attachment.url + '"/>'
$( '#advads-image-preview' ).html( new_image )
$( '#advads-image-edit-link' ).attr( 'href', attachment.editLink );
$( '#advads-image-edit-link' ).removeClass( 'hidden' );
// process "reserve this space" checkbox
$( '#advanced-ads-ad-parameters-size input[type=number]:first' ).trigger( 'change' );
// Finally, open the modal
// adblocker related code
$( '#advanced-ads-use-adblocker' ).on( 'change', function () {
advads_toggle_box( this, '#advads-adblocker-wrapper' )
// processing of the rebuild asset form and the FTP/SSH credentials form
var $advads_adblocker_wrapper = $( '#advads-adblocker-wrapper' ),
$advads_adblocker_rebuild_button = $( '#advads-adblocker-rebuild' );
$advads_adblocker_rebuild_button.prop( 'disabled', false );
$( document ).on( 'click', '#advads-adblocker-rebuild', function ( event ) {
var $form = $( '#advanced-ads-rebuild-assets-form' );
$form.prev( '.error' ).remove();
$advads_adblocker_rebuild_button.prop( 'disabled', true ).after( '<span class="spinner advads-spinner"></span>' );
action: 'advads-adblock-rebuild-assets',
nonce: advadsglobal.ajax_nonce
done: function ( data ) {
$advads_adblocker_wrapper.html( data );
$advads_adblocker_rebuild_button = $( '#advads-adblocker-rebuild' )
fail: function ( jqXHR, textStatus, errorThrown ) {
$form.before( '<div class="error"><p>' + textStatus + ': ' + errorThrown + '</p></div>' );
$advads_adblocker_rebuild_button.prop( 'disabled', false ).next( '.advads-spinner' ).remove();
on_modal_close: function () {
$advads_adblocker_rebuild_button.prop( 'disabled', false ).next( '.advads-spinner' ).remove();
if ( $( '[name="advads_ab_assign_new_folder"]' ).is( ':checked' ) ) {
args.data.advads_ab_assign_new_folder = true;
advanced_ads_admin.filesystem.ajax( args );
// process "reserve this space" checkbox
$( '#advanced-ads-ad-parameters' ).on( 'change', '#advanced-ads-ad-parameters-size input[type=number]', function () {
// Check if width and/or height is set.
if ( $( '#advanced-ads-ad-parameters-size input[type=number]' ).filter( function () {
return parseInt( this.value, 10 ) > 0
$( '#advads-wrapper-add-sizes' ).prop( 'disabled', false )
$( '#advads-wrapper-add-sizes' ).prop( 'disabled', true ).prop( 'checked', false )
// process "reserve this space" checkbox - ad type changed
$( '#advanced-ads-ad-parameters' ).on( 'paramloaded', function () {
$( '#advanced-ads-ad-parameters-size input[type=number]:first' ).trigger( 'change' );
// process "reserve this space" checkbox - on load
$( '#advanced-ads-ad-parameters-size input[type=number]:first' ).trigger( 'change' );
// move meta box markup to hndle headline
$( '.advads-hndlelinks' ).each( function () {
$( this ).appendTo( $( this ).parents('.postbox').find( 'h2.hndle' ) )
$( this ).removeClass( 'hidden' )
// Open tutorial link when clicked on it in targeting metabox.
$( '.advads-video-link' ).on( 'click', function (event) {
var parent = $( event.target ).closest( '.postbox' );
parent.removeClass( 'closed' );
var videoContainer = parent.find( '.advads-video-link-container' );
videoContainer.html( videoContainer.data( 'videolink' ) );
jQuery( '.advads_import_type' ).on( 'change', function () {
if ( this.value === 'xml_content' ) {
jQuery( '#advads_xml_file' ).hide()
jQuery( '#advads_xml_content' ).show()
jQuery( '#advads_xml_file' ).show()
jQuery( '#advads_xml_content' ).hide()
// Find Adsense Auto Ads inside ad content.
var ad_content = jQuery( 'textarea[name=advanced_ad\\[content\\]]' ).text() || '';
ad_content.indexOf( 'enable_page_level_ads' ) !== - 1
|| /script[^>]+(?:data-ad-client=|adsbygoogle\.js\?client=)/.test( ad_content )
advads_show_adsense_auto_ads_warning();
advads_ads_txt_find_issues()
jQuery( '.advanced-ads-adsense-dashboard' ).each( function ( key, elm ) {
if ( Advanced_Ads_Adsense_Report_Helper ) {
Advanced_Ads_Adsense_Report_Helper.init( elm );
function modal_submit_form( event, ID, modalID, validation = '' ) {
if ( validation !== '' && ! window[validation]( modalID ) ) {
document.getElementById( ID ).submit();
* Store the action hash in settings form action
* thanks for Yoast SEO for this idea
function advads_set_tab_hashes() {
jQuery( '#advads-tabs' ).find( 'a' ).each( function () {
var id = jQuery( this ).attr( 'id' ).replace( '-tab', '' );
var optiontab = jQuery( '#' + id );
var form = optiontab.children( '.advads-settings-tab-main-form' )
var currentUrl = form.attr( 'action' ).split( '#' )[ 0 ]
form.attr( 'action', currentUrl + jQuery( this ).attr( 'href' ) )
* Scroll to position in backend minus admin bar height
* @param selector jQuery selector
function advads_scroll_to_element ( selector ) {
var height_of_admin_bar = jQuery( '#wpadminbar' ).height()
jQuery( 'html, body' ).animate( {
scrollTop: jQuery( selector ).offset().top - height_of_admin_bar
* toggle content elements (hide/show)
* @param selector jquery selector
function advads_toggle ( selector ) {
jQuery( selector ).slideToggle()
* toggle content elements with a checkbox (hide/show)
* @param selector jquery selector
function advads_toggle_box ( e, selector ) {
if ( jQuery( e ).is( ':checked' ) ) {
jQuery( selector ).slideDown()
jQuery( selector ).slideUp()
* disable content of one box when selecting another
* only grey/disable it, don’t hide it
* @param selector jquery selector
function advads_toggle_box_enable ( e, selector ) {
if ( jQuery( e ).is( ':checked' ) ) {
jQuery( selector ).find( 'input' ).removeAttr( 'disabled', '' )
jQuery( selector ).find( 'input' ).attr( 'disabled', 'disabled' )
* Validate the form that creates a new group or placement.
function advads_validate_new_form (modalID) {
// Check if type was selected
if ( ! jQuery( '.advads-form-type input:checked' ).length ) {
jQuery( '.advads-form-type-error' ).show()
jQuery( '.advads-form-type-error' ).hide()
// Check if name was entered
if ( jQuery( '.advads-form-name' ).val() == '' ) {
jQuery( '.advads-form-name-error' ).show()
jQuery( '.advads-form-name-error' ).hide()