Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1 @@
<?php // Silence is golden

View File

@@ -0,0 +1 @@
/* This stylesheet is used to style the public-facing components of the plugin. */

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1 @@
<?php // Silence is golden

View File

@@ -0,0 +1,674 @@
/*
* advanced ads functions to be used directly within ad codes
*/
/**
* Polyfills
*/
(function () {
if ( typeof window.CustomEvent !== "function" ) {
/**
* CustomEvent polyfill for IE11: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
*
* @param {string} event Event name.
* @param {object} params Event parameters.
* @returne {object} Custom event.
*/
function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: null };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
window.CustomEvent = CustomEvent;
}
/**
* ReplaceWith polyfill for IE11: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/replaceWith
*/
function ReplaceWithPolyfill() {
'use-strict'; // For safari, and IE > 10
var parent = this.parentNode, i = arguments.length, currentNode;
if ( ! parent) {
return;
}
if ( ! i ) {// if there are no arguments
parent.removeChild( this );
}
while ( i-- ) { // i-- decrements i and returns the value of i before the decrement
currentNode = arguments[i];
if ( typeof currentNode !== 'object' ) {
currentNode = this.ownerDocument.createTextNode( currentNode );
} else if ( currentNode.parentNode ) {
currentNode.parentNode.removeChild( currentNode );
}
// the value of "i" below is after the decrement
if ( ! i ) { // if currentNode is the first argument (currentNode === arguments[0])
parent.replaceChild( currentNode, this );
} else { // if currentNode isn't the first
parent.insertBefore( currentNode, this.nextSibling );
}
}
}
if ( ! Element.prototype.replaceWith ) {
Element.prototype.replaceWith = ReplaceWithPolyfill;
}
if ( ! CharacterData.prototype.replaceWith ) {
CharacterData.prototype.replaceWith = ReplaceWithPolyfill;
}
if ( ! DocumentType.prototype.replaceWith ) {
DocumentType.prototype.replaceWith = ReplaceWithPolyfill;
}
/**
* Polyfill for NodeList.foreach() because we need to support IE11: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
*/
if ( window.NodeList && ! NodeList.prototype.forEach ) {
NodeList.prototype.forEach = function( callback, thisArg ) {
var i;
var len = this.length;
thisArg = thisArg || window;
for ( i = 0; i < len; i++ ) {
callback.call( thisArg, this[ i ], i, this );
}
};
}
})();
advads = {
/**
* check if localstorage is supported/enabled by client
*/
supports_localstorage: function () {
"use strict";
try {
if ( ! window || window.localStorage === undefined ) {
return false;
}
// storage might be full or disabled
window.localStorage.setItem( "x", "x" );
window.localStorage.removeItem( "x" );
return true;
} catch ( e ) {
return false;
}
},
/**
* check if the ad is displayed more than {max} times per session
* every check increases the counter
*
* @param {string} name (no id needed, just any id-formated string)
* @param {type} max number of maximum times the ad can be displayed within the period
* @returns {bool} true if limit is reached
*/
max_per_session: function ( name, max ) {
var num = 1;
if ( max === undefined || parseInt( max ) === 0 ) {
max = 1;
}
// check if cookie exists and get the value
if ( this.cookie_exists( name ) ) {
if ( this.get_cookie( name ) >= max ) {
return true;
}
num = num + parseInt( this.get_cookie( name ) );
}
this.set_cookie( name, num );
return false;
},
/**
* increase a cookie with an integer value by 1
*
* @param {str} name of the cookie
* @param {int} exdays days until cookie expires
*/
count_up: function ( name, exdays ) {
var num = 1;
// check if cookie exists and get the value
if ( this.cookie_exists( name ) ) {
num = num + parseInt( this.get_cookie( name ) );
}
this.set_cookie( name, num );
},
/**
* return true, if cookie exists
* return false, if not
* if not exists, create it
* use case: to check if something already happened in this page impression
*
* @param {type} name
* @returns {unresolved}
*/
set_cookie_exists: function ( name ) {
if ( get_cookie( name ) ) {
return true;
}
set_cookie( name, '', 0 );
return false;
},
/**
* get a cookie value
*
* @param {string} name of the cookie
* @return {string} decoded cookie value
*/
get_cookie: function ( name ) {
var i, x, y, ADVcookies = document.cookie.split( ';' );
for ( i = 0; i < ADVcookies.length; i ++ ) {
x = ADVcookies[i].substr( 0, ADVcookies[i].indexOf( '=' ) );
y = ADVcookies[i].substr( ADVcookies[i].indexOf( '=' ) + 1 );
x = x.replace( /^\s+|\s+$/g, '' );
if ( x === name ) {
return decodeURIComponent( y );
}
}
},
/**
* set a cookie value
*
* @param {str} name of the cookie
* @param {str} value of the cookie
* @param {int} exdays days until cookie expires
* set 0 to expire cookie immidiatelly
* set null to expire cookie in the current session
*/
set_cookie: function ( name, value, exdays, path, domain, secure ) {
// days in seconds
var expiry = (
exdays == null
) ? null : exdays * 24 * 60 * 60;
this.set_cookie_sec( name, value, expiry, path, domain, secure );
},
/**
* set a cookie with expiry given in seconds
*
* @param {str} name of the cookie
* @param {str} value of the cookie
* @param {int} expiry seconds until cookie expires
* set 0 to expire cookie immidiatelly
* set null to expire cookie in the current session
*/
set_cookie_sec: function ( name, value, expiry, path, domain, secure ) {
var exdate = new Date();
exdate.setSeconds( exdate.getSeconds() + parseInt( expiry ) );
document.cookie = name + "=" + encodeURIComponent( value ) +
(
(
expiry == null
) ? "" : "; expires=" + exdate.toUTCString()
) +
(
(
path == null
) ? "; path=/" : "; path=" + path
) +
(
(
domain == null
) ? "" : "; domain=" + domain
) +
(
(
secure == null
) ? "" : "; secure"
);
},
/**
* check if a cookie is set and contains a value
*
* @param {str} name of the cookie
* @returns {bool} true, if cookie is set
*/
cookie_exists: function ( name ) {
var c_value = this.get_cookie( name );
if ( c_value !== null && c_value !== "" && c_value !== undefined ) {
return true;
}
return false;
},
/**
* move one element into another
*
* @param {str} element selector of the element that should be moved
* @param {str} target selector of the element where to move
* @param {arr} options
*/
move: function ( element, target, options ) {
var el = jQuery( element );
var target_string = target;
if ( typeof options === 'undefined' ) {
options = {};
}
if ( typeof options.css === 'undefined' ) {
options.css = {};
}
if ( typeof options.method === 'undefined' ) {
options.method = 'prependTo';
}
// search for abstract target element
if ( target === '' && typeof options.target !== 'undefined' ) {
switch ( options.target ) {
case 'wrapper' : // wrapper
var offset = 'left';
if ( typeof options.offset !== 'undefined' ) {
offset = options.offset;
}
target = this.find_wrapper( element, offset );
break;
}
}
// use only visible elements
if ( typeof options.moveintohidden === 'undefined' ) {
target = jQuery( target ).filter( ':visible' );
} else {
target = jQuery( target );
}
// print warning in console if the element appears multiple times
if ( target.length > 1 ) {
console.log( "Advanced Ads: element '" + target_string + "' found " + target.length + " times." );
}
// switch insert method
switch ( options.method ) {
case 'insertBefore' :
el.insertBefore( target );
break;
case 'insertAfter' :
el.insertAfter( target );
break;
case 'appendTo' :
el.appendTo( target );
break;
case 'prependTo' :
el.prependTo( target );
break;
default :
el.prependTo( target );
}
},
/**
* Set 'relative' position for a parent element.
*
* @param {str} element selector
*/
set_parent_relative: function ( element, options ) {
var options = typeof options !== 'undefined' ? options : {};
var el = jQuery( element );
// give "position" style to parent element, if missing
var parent = el.parent();
if ( options.use_grandparent ) {
parent = parent.parent();
}
if ( parent.css( 'position' ) === 'static' || parent.css( 'position' ) === '' ) {
parent.css( 'position', 'relative' );
}
},
/**
* make an absolute position element fixed at the current position
* hint: use only after DOM is fully loaded in order to fix a wrong position
*
* @param {str} element selector
* @param {obj} options
*/
fix_element: function ( element, options ) {
var options = typeof options !== 'undefined' ? options : {};
var el = jQuery( element );
if ( options.use_grandparent ) {
this.set_parent_relative( el.parent() );
} else {
this.set_parent_relative( el );
}
// fix element at current position
// get position for hidden elements by showing them for a very short time
if ( options.is_invisible ) {
el.show();
}
var topoffset = parseInt( el.offset().top );
var leftoffset = parseInt( el.offset().left );
if ( options.is_invisible ) {
el.hide();
}
if ( 'left' === options.offset ) {
// Allow to scale the nested image down when it has `max-width: 100%` and touches the left edge of the viewport.
var rightoffset = jQuery( window ).width() - leftoffset - el.outerWidth();
el.css( 'position', 'fixed' ).css( 'top', topoffset + 'px' ).css( 'right', rightoffset + 'px' ).css( 'left', '' );
} else {
// reset "right" to prevent conflicts
el.css( 'position', 'fixed' ).css( 'top', topoffset + 'px' ).css( 'left', leftoffset + 'px' ).css( 'right', '' );
}
},
/**
* find the main wrapper
* either id or first of its class
*
* @param {str} element selector
* @param {str} offset which position of the offset to check (left or right)
* @return {str} selector
*/
find_wrapper: function ( element, offset ) {
// first margin: auto element after body
var returnValue;
jQuery( 'body' ).children().not('script, .screen-reader-text, .skip-link, ' + element).each( function ( key, value ) {
// check offset value
var checkedelement = jQuery( value );
// check if there is space left or right of the element
if ( (
offset === 'right' && (
checkedelement.offset().left + jQuery( checkedelement ).width() < jQuery( window ).width()
)
) ||
(
offset === 'left' && checkedelement.offset().left > 0
) ) {
// fix element
if ( checkedelement.css( 'position' ) === 'static' || checkedelement.css( 'position' ) === '' ) {
checkedelement.css( 'position', 'relative' );
}
// set return value
returnValue = value;
return false;
}
} );
return returnValue;
},
/**
* center fixed element on the screen
*
* @param {str} element selector
*/
center_fixed_element: function ( element ) {
var el = jQuery( element );
// half window width minus half element width
var left = (
jQuery( window ).width() / 2
) - (
parseInt( el.css( 'width' ) ) / 2
);
el.css( 'left', left + 'px' );
},
/**
* center element vertically on the screen
*
* @param {str} element selector
*/
center_vertically: function ( element ) {
var el = jQuery( element );
// half window height minus half element height
var left = (
jQuery( window ).height() / 2
) - (
parseInt( el.css( 'height' ) ) / 2
);
// Center correctly when the ad is attached to the element that begins lower.
if ( el.css( 'position' ) !== 'fixed' ) {
left -= topoffset = parseInt( el.offset().top );
}
el.css( 'top', left + 'px' );
},
/**
* close an ad and add a cookie
*
* @param {str} element selector
*/
close: function ( element ) {
var wrapper = jQuery( element );
// remove the ad
wrapper.remove();
},
/**
* Wait until images are ready.
*
* @param {obj} $el jQuery object.
* @param {function} ready_callback Ready callback.
* derrived from https://github.com/alexanderdickson/waitForImages/blob/master/dist/jquery.waitforimages.js
*/
wait_for_images: function ( $el, ready_callback ) {
var loaded_count = 0;
var srcs = [];
$el.find( 'img[src][src!=""]' ).each( function () {
srcs.push( this.src );
} );
if ( srcs.length === 0 ) {
ready_callback.call( $el );
}
jQuery.each( srcs, function ( i, src ) {
var image = new Image();
image.src = src;
var events = 'load error';
jQuery( image ).one( events, function me( event ) {
// Remove remaining handler (either 'load' or 'error').
jQuery( this ).off( events, me );
loaded_count ++;
if ( loaded_count == srcs.length ) {
ready_callback.call( $el[0] );
return false;
}
} );
} );
},
privacy: {
state: 'unknown',
state_executed: false,
/**
* Get consent state.
* IIFE so the events fire only once per event.
*
* @return string
* 'not_needed' - consent is not needed.
* 'accepted' - consent was given.
* 'unknown' - consent was not given yet.
*/
get_state: (
function () {
return function () {
// if we already have a state, return that.
if ( window.advads_options.privacy.state !== 'unknown' ) {
// make sure this only gets executed once.
if ( ! advads.privacy.state_executed ) {
advads.privacy.state_executed = true;
advads.privacy.dispatch_event( window.advads_options.privacy.state, false );
}
return advads.privacy.state;
}
// If using the cookie method, fire an initial event, regardless if cookie set or not.
if ( window.advads_options.privacy['consent-method'] === 'custom' ) {
var cookie_regex = new RegExp( '.*?' + window.advads_options.privacy['custom-cookie-value'] + '[^;]*?' );
let cookie = advads.get_cookie( window.advads_options.privacy['custom-cookie-name'] ) || '';
// Force the event, if we haven't yet fired one.
if ( ! advads.privacy.state_executed ) {
advads.privacy.state_executed = true;
advads.privacy.dispatch_event( cookie.match( cookie_regex ) ? 'accepted' : 'unknown', true );
}
}
// make sure this only gets executed once.
advads.privacy.state_executed = true;
// Run this in an interval (every 0.3s) just in case we are still waiting for consent
var cnt = 0,
consentSetInterval = setInterval( function () {
// Bail if we have not gotten a consent response after 60 seconds.
if ( ++ cnt === 181 ) {
clearInterval( consentSetInterval );
}
switch ( window.advads_options.privacy['consent-method'] ) {
case 'custom' :
let cookie = advads.get_cookie( window.advads_options.privacy['custom-cookie-name'] ) || '';
// check if custom cookie is set and matches value.
if ( cookie.match( cookie_regex ) ) {
clearInterval( consentSetInterval );
if ( advads.privacy.state !== 'accepted' ) {
advads.privacy.dispatch_event( 'accepted', true );
}
}
break;
case 'iab_tcf_20' :
// Check if window.__tcfapi has been set.
if ( typeof window.__tcfapi === 'undefined' ) {
return;
}
clearInterval( consentSetInterval );
window.__tcfapi( 'addEventListener', 2, function ( TCData, listenerSuccess ) {
if ( ! listenerSuccess ) {
return;
}
if (
TCData.eventStatus === 'tcloaded'
|| TCData.eventStatus === 'useractioncomplete'
// if this is google funding choices, eventStatus is not set. Check if either gdpr doesn't apply or if there is a purpose object.
|| ( TCData.eventStatus === null && typeof window.googlefc !== 'undefined' && (
typeof TCData.purpose !== 'undefined' || ! TCData.gdprApplies
) )
) {
var userAction = TCData.eventStatus === 'useractioncomplete';
if ( ! TCData.gdprApplies ) {
if ( advads.privacy.state !== 'not_needed' ) {
advads.privacy.dispatch_event( 'not_needed', userAction );
}
return;
}
if ( TCData.purpose.consents[1] ) {
if ( advads.privacy.state !== 'accepted' ) {
advads.privacy.dispatch_event( 'accepted', userAction );
}
return;
}
// fire another event, in case the user revokes the previous consent.
if ( advads.privacy.state !== 'rejected' ) {
advads.privacy.dispatch_event( 'rejected', userAction );
}
}
}
);
break;
}
}, 333 );
return advads.privacy.state;
}
}
)(),
/**
* Check if the privacy_method is custom cookie, and non personalized ads are allowed.
*
* @returns {boolean}
*/
is_adsense_npa_enabled: function () {
if ( ! window.advads_options || ! window.advads_options.privacy ) {
return true;
}
return !! (
window.advads_options.privacy['show-non-personalized-adsense'] && window.advads_options.privacy['consent-method'] === 'custom'
);
},
/**
* Dispatch a custom event whenever the state changes.
*
* @param {String} state The current privacy state.
* @param {boolean} userAction This is result of action by user.
*/
dispatch_event: function ( state, userAction ) {
var previousState = advads.privacy.state,
fire_event = function () {
document.dispatchEvent( new CustomEvent( 'advanced_ads_privacy', {
detail: {
state: state,
previousState: previousState,
userAction: userAction
}
} ) );
};
advads.privacy.state = state;
console.log( {
state: state,
previousState: previousState,
userAction: userAction
} );
window.advanced_ads_ready_queue.push( fire_event );
},
/**
* Check if ad is decoded.
*
* @param {integer} id
*
* @returns {boolean}
*/
is_ad_decoded: function ( id ) {
return document.querySelector( 'script[data-tcf="waiting-for-consent"][data-id="' + id + '"]' ) === null;
},
/**
* Decode ad content.
*
* @param {Element} el
* @param {boolean} [inject=true]
*/
decode_ad: function ( el, inject ) {
// this can also be a number if used in a foreach.
inject = typeof inject === 'boolean' ? inject : true;
var string = decodeURIComponent( Array.prototype.map.call( atob( el.textContent ), function ( c ) {
return '%' + ( '00' + c.charCodeAt( 0 ).toString( 16 ) ).slice( - 2 );
} ).join( '' ) );
if ( ! inject ) {
return string;
}
el.replaceWith( document.createRange().createContextualFragment( string ) );
}
}
};
window.advanced_ads_ready_queue.push( advads.privacy.get_state );
document.addEventListener( 'advanced_ads_privacy', function ( event ) {
if (
(
event.detail.state !== 'accepted' && event.detail.state !== 'not_needed'
)
|| event.detail.userAction
|| document.readyState === 'loading'
) {
return;
}
// Find all scripts waiting for consent and decode them.
document.querySelectorAll( 'script[type="text/plain"][data-tcf="waiting-for-consent"]' ).forEach( advads.privacy.decode_ad );
} );

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,265 @@
// Highlight elements in frontend, if local storage variable is set.
jQuery( document ).ready( function () {
function is_enabled() {
if ( ! advads.supports_localstorage() || ! localStorage.getItem( 'advads_frontend_picker' ) ) {
return false;
}
// Check if the frontend picker was started on the current blog.
if ( window.advads_options.blog_id
&& localStorage.getItem( 'advads_frontend_blog_id' )
&& window.advads_options.blog_id !== localStorage.getItem( 'advads_frontend_blog_id' ) ) {
return false;
}
// Deactivate the frontend picker if it was started more than 45 minutes ago.
if ( localStorage.getItem( 'advads_frontend_starttime' )
&& parseInt( localStorage.getItem( 'advads_frontend_starttime' ), 10 ) < (
new Date().getTime()
) - 45 * 60 * 1000 ) {
localStorage.removeItem( 'advads_frontend_action' );
localStorage.removeItem( 'advads_frontend_element' );
localStorage.removeItem( 'advads_frontend_picker' );
localStorage.removeItem( 'advads_prev_url' );
localStorage.removeItem( 'advads_frontend_pathtype' );
localStorage.removeItem( 'advads_frontend_boundary' );
localStorage.removeItem( 'advads_frontend_blog_id' );
localStorage.removeItem( 'advads_frontend_starttime' );
advads.set_cookie( 'advads_frontend_picker', '', - 1 );
return false;
}
return true;
}
// only trigger if local storage is available
if ( is_enabled() ) {
var advads_picker_cur, advads_picker_overlay = jQuery( "<div id='advads-picker-overlay'>" ),
advads_picker_no = [document.body, document.documentElement, document];
advads_picker_overlay.css( {
position: 'absolute', border: 'solid 2px #428bca',
backgroundColor: 'rgba(66,139,202,0.5)', boxSizing: 'border-box',
zIndex: 1000000, pointerEvents: 'none'
} ).prependTo( 'body' );
if ( 'true' === localStorage.getItem( 'advads_frontend_boundary' ) ) {
jQuery( 'body' ).css( 'cursor', 'not-allowed' );
}
/**
* Check if we can traverse up the dom tree.
*
* We cannot use event delegation because:
* - the content can be loaded via AJAX dynamically
* - we cannot wrap the content in a `div` that represents post boundary
* because that may prevent css rules from working
*
* @param HTMLElement The current element.
* return bool
*/
window.advads.is_boundary_reached = function ( advads_picker_cur ) {
if ( 'true' !== localStorage.getItem( 'advads_frontend_boundary' ) ) {
return false;
}
$advads_picker_cur = jQuery( advads_picker_cur );
// A boundary helper is the `ins` element inside of the post content
// that is used to determine the post boundary (where the content starts and ends).
var $boundary_helpers = jQuery( '.advads-frontend-picker-boundary-helper' );
$boundaries = $boundary_helpers.parent();
$boundaries.css( 'cursor', 'pointer' );
return $advads_picker_cur.is( $boundaries ) || ! $advads_picker_cur.closest( $boundaries ).length;
}
if ( 'xpath' === localStorage.getItem( 'advads_frontend_pathtype' ) ) {
var fn = 'getXPath';
} else {
var fn = 'getPath';
}
jQuery( document ).mousemove( function ( e ) {
if ( e.target === advads_picker_cur ) {
return;
}
if ( ~ advads_picker_no.indexOf( e.target ) ) {
advads_picker_cur = null;
advads_picker_overlay.hide();
return;
}
var target = jQuery( e.target ),
offset = target.offset(),
width = target.outerWidth(),
height = target.outerHeight();
advads_picker_cur = e.target;
var path = jQuery( advads_picker_cur )[fn]();
if ( ! path ) {
// A click outside of the boundary.
// @see `is_boundary_reached`.
return;
}
// log path
console.log( path );
advads_picker_overlay.css( {
top: offset.top,
left: offset.left,
width: width,
height: height
} ).show();
} );
// save on click
jQuery( document ).click( function ( e ) {
var path = jQuery( advads_picker_cur )[fn]();
if ( advads.is_boundary_reached( advads_picker_cur ) ) {
return;
}
localStorage.setItem( 'advads_frontend_element', path );
window.location = localStorage.getItem( 'advads_prev_url' );
} );
};
} );
/*
Derrived from jQuery-GetPath v0.01, by Dave Cardwell. (2007-04-27)
http://davecardwell.co.uk/javascript/jquery/plugins/jquery-getpath/
Usage:
var path = $('#foo').getPath();
*/
jQuery.fn.extend( {
getPath: function ( path, depth ) {
// The first time this function is called, path won't be defined.
if ( typeof path === 'undefined' ) {
path = '';
}
if ( typeof depth === 'undefined' ) {
depth = 0;
}
// If this element is <html> we've reached the end of the path.
// also end after 2 elements
if ( this.is( 'html' ) ) {
return 'html > ' + path;
} else if ( 3 === depth ) {
return path;
}
// Add the element name.
var cur = this.get( 0 ).nodeName.toLowerCase();
// Determine the IDs and path.
var el_id = this.attr( 'id' ),
el_class = this.attr( 'class' );
depth = depth + 1;
// Add the #id if there is one. Ignore ID with number.
if ( typeof el_id !== 'undefined' && ! /\d/.test( el_id ) ) {
cur += '#' + el_id;
} else if ( typeof el_class !== 'undefined' ) {
// Add classes if there is no id.
el_class = el_class.split( /[\s\n]+/ );
// Skip classes with numbers.
el_class = jQuery.grep( el_class, function ( element, index ) {
return ! /\d/.test( element )
} );
// Add 2 classes.
if ( el_class.length ) {
cur += '.' + el_class.slice( 0, 2 ).join( '.' );
}
}
// add index if this element is not unique among its siblings
if ( this.siblings( cur ).length ) {
cur += ":eq(" + this.siblings( cur ).addBack().not( '#advads-picker-overlay' ).index( this ) + ")";
}
// Recurse up the DOM.
if ( path === '' ) {
return this.parent().getPath( cur, depth );
} else {
return this.parent().getPath( cur + ' > ' + path, depth );
}
},
/**
* Get XPath.
*/
getXPath: function ( path, depth ) {
// The first time this function is called, path won't be defined.
if ( typeof path === 'undefined' ) {
path = '';
}
if ( typeof depth === 'undefined' ) {
depth = 0;
}
// If this element is <html> we've reached the end of the path.
// also end after 2 elements
if ( this.is( 'body' ) || 3 === depth ) {
return path;
}
if ( advads.is_boundary_reached( this ) ) {
return path;
}
// Add the element name.
var tag = this.get( 0 ).nodeName.toLowerCase();
var cur = tag;
// Determine the IDs and path.
var el_id = this.attr( 'id' ),
el_class = this.attr( 'class' );
var classes = [];
// Add the #id if there is one. Ignore ID with number.
if ( typeof el_id !== 'undefined' && ! /\d/.test( el_id ) ) {
return cur + '[@id and id="' + el_id + '"]/' + path;
} else if ( typeof el_class !== 'undefined' ) {
// Add classes if there is no id.
el_class = el_class.split( /[\s\n]+/ );
// Skip classes with numbers.
el_class = jQuery.grep( el_class, function ( element, index ) {
return ! /\d/.test( element )
} );
// Add 2 classes.
if ( el_class.length ) {
depth = depth + 1;
var classes = el_class.slice( 0, 2 );
var xpath_classes = [];
for ( var i = 0, l = classes.length; i < l; i ++ ) {
xpath_classes.push( '(@class and contains(concat(" ", normalize-space(@class), " "), " ' + classes[i] + ' "))' );
}
cur += '[' + xpath_classes.join( ' and ' ) + ']';
}
}
// Add index if this element is not unique among its siblings.
if ( classes.length ) {
var $siblings = this.siblings( tag + '.' + classes.join( '.' ) );
} else {
var $siblings = this.siblings( tag );
}
if ( $siblings.length ) {
var index = $siblings.addBack().not( '#advads-picker-overlay' ).index( this );
cur += '[' + index + ']';
}
// Recurse up the DOM.
if ( path === '' ) {
return this.parent().getXPath( cur, depth );
} else {
return this.parent().getXPath( cur + '/' + path, depth );
}
}
} );

View File

@@ -0,0 +1 @@
jQuery(document).ready((function(){if(!(!advads.supports_localstorage()||!localStorage.getItem("advads_frontend_picker")||window.advads_options.blog_id&&localStorage.getItem("advads_frontend_blog_id")&&window.advads_options.blog_id!==localStorage.getItem("advads_frontend_blog_id")||localStorage.getItem("advads_frontend_starttime")&&parseInt(localStorage.getItem("advads_frontend_starttime"),10)<(new Date).getTime()-27e5&&(localStorage.removeItem("advads_frontend_action"),localStorage.removeItem("advads_frontend_element"),localStorage.removeItem("advads_frontend_picker"),localStorage.removeItem("advads_prev_url"),localStorage.removeItem("advads_frontend_pathtype"),localStorage.removeItem("advads_frontend_boundary"),localStorage.removeItem("advads_frontend_blog_id"),localStorage.removeItem("advads_frontend_starttime"),advads.set_cookie("advads_frontend_picker","",-1),1))){var e,t=jQuery("<div id='advads-picker-overlay'>"),a=[document.body,document.documentElement,document];if(t.css({position:"absolute",border:"solid 2px #428bca",backgroundColor:"rgba(66,139,202,0.5)",boxSizing:"border-box",zIndex:1e6,pointerEvents:"none"}).prependTo("body"),"true"===localStorage.getItem("advads_frontend_boundary")&&jQuery("body").css("cursor","not-allowed"),window.advads.is_boundary_reached=function(e){if("true"!==localStorage.getItem("advads_frontend_boundary"))return!1;$advads_picker_cur=jQuery(e);var t=jQuery(".advads-frontend-picker-boundary-helper");return $boundaries=t.parent(),$boundaries.css("cursor","pointer"),$advads_picker_cur.is($boundaries)||!$advads_picker_cur.closest($boundaries).length},"xpath"===localStorage.getItem("advads_frontend_pathtype"))var o="getXPath";else o="getPath";jQuery(document).mousemove((function(r){if(r.target!==e){if(~a.indexOf(r.target))return e=null,void t.hide();var d=jQuery(r.target),n=d.offset(),s=d.outerWidth(),i=d.outerHeight();e=r.target;var l=jQuery(e)[o]();l&&(console.log(l),t.css({top:n.top,left:n.left,width:s,height:i}).show())}})),jQuery(document).click((function(t){var a=jQuery(e)[o]();advads.is_boundary_reached(e)||(localStorage.setItem("advads_frontend_element",a),window.location=localStorage.getItem("advads_prev_url"))}))}})),jQuery.fn.extend({getPath:function(e,t){if(void 0===e&&(e=""),void 0===t&&(t=0),this.is("html"))return"html > "+e;if(3===t)return e;var a=this.get(0).nodeName.toLowerCase(),o=this.attr("id"),r=this.attr("class");return t+=1,void 0===o||/\d/.test(o)?void 0!==r&&(r=r.split(/[\s\n]+/),(r=jQuery.grep(r,(function(e,t){return!/\d/.test(e)}))).length&&(a+="."+r.slice(0,2).join("."))):a+="#"+o,this.siblings(a).length&&(a+=":eq("+this.siblings(a).addBack().not("#advads-picker-overlay").index(this)+")"),""===e?this.parent().getPath(a,t):this.parent().getPath(a+" > "+e,t)},getXPath:function(e,t){if(void 0===e&&(e=""),void 0===t&&(t=0),this.is("body")||3===t)return e;if(advads.is_boundary_reached(this))return e;var a=this.get(0).nodeName.toLowerCase(),o=a,r=this.attr("id"),d=this.attr("class"),n=[];if(void 0!==r&&!/\d/.test(r))return o+'[@id and id="'+r+'"]/'+e;if(void 0!==d&&(d=d.split(/[\s\n]+/),(d=jQuery.grep(d,(function(e,t){return!/\d/.test(e)}))).length)){t+=1;for(var s=[],i=0,l=(n=d.slice(0,2)).length;i<l;i++)s.push('(@class and contains(concat(" ", normalize-space(@class), " "), " '+n[i]+' "))');o+="["+s.join(" and ")+"]"}if(n.length)var c=this.siblings(a+"."+n.join("."));else c=this.siblings(a);return c.length&&(o+="["+c.addBack().not("#advads-picker-overlay").index(this)+"]"),""===e?this.parent().getXPath(o,t):this.parent().getXPath(o+"/"+e,t)}});

View File

@@ -0,0 +1 @@
<?php // Silence is golden

View File

@@ -0,0 +1,5 @@
jQuery( 'document' ).ready(function($) {
"use strict";
});

View File

@@ -0,0 +1,11 @@
( function () {
window.advanced_ads_ready_queue = window.advanced_ads_ready_queue || [];
// replace native push method with our advanced_ads_ready function; do this early to prevent race condition between pushing and the loop.
advanced_ads_ready_queue.push = window.advanced_ads_ready;
// handle all callbacks that have been added to the queue previously.
for ( var i = 0, length = advanced_ads_ready_queue.length; i < length; i ++ ) {
advanced_ads_ready( advanced_ads_ready_queue[i] );
}
} )();

View File

@@ -0,0 +1 @@
!function(){window.advanced_ads_ready_queue=window.advanced_ads_ready_queue||[],advanced_ads_ready_queue.push=window.advanced_ads_ready;for(var d=0,a=advanced_ads_ready_queue.length;d<a;d++)advanced_ads_ready(advanced_ads_ready_queue[d])}();

View File

@@ -0,0 +1,26 @@
/**
* Wait for the page to be ready before firing JS.
*
* @param {function} callback - A callable function to be executed.
* @param {string} [requestedState=complete] - document.readyState to wait for. Defaults to 'complete', can be 'interactive'.
*/
window.advanced_ads_ready = function ( callback, requestedState ) {
requestedState = requestedState || 'complete';
var checkState = function ( state ) {
return requestedState === 'interactive' ? state !== 'loading' : state === 'complete';
};
// If we have reached the correct state, fire the callback.
if ( checkState( document.readyState ) ) {
callback();
return;
}
// We are not yet in the correct state, attach an event handler, only fire once if the requested state is 'interactive'.
document.addEventListener( 'readystatechange', function ( event ) {
if ( checkState( event.target.readyState ) ) {
callback();
}
}, {once: requestedState === 'interactive'} );
};
window.advanced_ads_ready_queue = window.advanced_ads_ready_queue || [];

View File

@@ -0,0 +1 @@
window.advanced_ads_ready=function(e,a){a=a||"complete";var d=function(e){return"interactive"===a?"loading"!==e:"complete"===e};d(document.readyState)?e():document.addEventListener("readystatechange",(function(a){d(a.target.readyState)&&e()}),{once:"interactive"===a})},window.advanced_ads_ready_queue=window.advanced_ads_ready_queue||[];

View File

@@ -0,0 +1,802 @@
<?php
// phpcs:ignoreFile
/**
* Advanced Ads.
*
* @package AdvancedAds
* @author Thomas Maier <support@wpadvancedads.com>
* @license GPL-2.0+
* @link https://wpadvancedads.com
* @copyright 2013-2018 Thomas Maier, Advanced Ads GmbH
*/
use AdvancedAds\Constants;
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Abstracts\Group;
use AdvancedAds\Framework\Utilities\Params;
use AdvancedAds\Utilities\WordPress;
use AdvancedAds\Utilities\Conditional;
use AdvancedAds\Installation\Capabilities;
/**
* Plugin class. This class should ideally be used to work with the
* public-facing side of the WordPress site.
*
* @package Advanced_Ads
* @author Thomas Maier <support@wpadvancedads.com>
*/
class Advanced_Ads {
/**
* Instance of this class.
*
* @var object
*/
private static $instance = null;
/**
* Ad types
*
* @deprecated 1.48.2
*
* @var array Ad types
*/
public $ad_types = [];
/**
* Plugin options
*
* @var array $options
*/
protected $options;
/**
* Interal plugin options set by the plugin
*
* @var array $internal_options
*/
protected $internal_options;
/**
* Adblocker Plugin options
*
* @var array (if loaded)
*/
protected $adblocker_options = null;
/**
* Whether the loop started in an inner `the_content`.
*
* @var bool
*/
protected $was_in_the_loop = false;
/**
* Signifies Whether the loop has started and the caller is in the loop.
*
* We need it because Some the "Divi" theme calls the `loop_start/loop_end` hooks
* instead of calling `the_post()` to signify that the caller is in the loop.
*
* @var bool
*/
protected $in_the_loop = false;
/**
* Is the query the main query?, when WP_Query is used
*
* @var bool
*/
private $is_main_query;
/**
* Save number of ads
*
* @var array
*/
private $number_of_ads = [];
/**
* Initialize frontend features
*/
private function __construct() {
add_action( 'plugins_loaded', [ $this, 'wp_plugins_loaded' ] );
// allow add-ons to interact.
add_action( 'init', [ $this, 'advanced_ads_loaded' ], 9 );
add_filter( 'the_content', [ $this, 'set_was_in_the_loop' ], ~PHP_INT_MAX );
}
/**
* Return an instance of this class.
*
* @return Advanced_Ads A single instance of this class.
*/
public static function get_instance() {
// if the single instance hasn't been set, set it now.
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Initialize the plugin by setting localization and loading public scripts
* and styles.
*/
public function wp_plugins_loaded() {
// register hooks and filters for auto ad injection.
$this->init_injection();
// add meta robots noindex, nofollow to images, which are part of 'Image ad' ad type.
add_action( 'wp_head', [ $this, 'noindex_attachment_images' ] );
// use custom CSS or other custom header code.
add_action( 'wp_head', [ $this, 'custom_header_code' ] );
// check if ads are disabled in secondary queries.
add_action( 'the_post', [ $this, 'set_query_type' ], 10, 2 );
add_action( 'loop_start', [ $this, 'set_loop_start' ], 10, 0 );
add_action( 'loop_end', [ $this, 'set_loop_end' ], 10, 0 );
add_action( 'transition_post_status', [ $this, 'transition_ad_status' ], 10, 3 );
// register debug parameter
$this->debug_parameter();
Advanced_Ads_Display_Conditions::get_instance();
( new Advanced_Ads_Frontend_Checks() );
Advanced_Ads_Ad_Health_Notices::get_instance();
}
/**
* Allow add-ons to hook
*/
public function advanced_ads_loaded() {
do_action( 'advanced-ads-plugin-loaded' );
}
/**
* Load filters to inject ads into various sections of our site
*/
public function init_injection() {
add_filter( 'the_content', [ $this, 'inject_content' ], $this->get_content_injection_priority() );
}
/**
* Log error messages when debug is enabled
*
* @param string $message error message.
* @link http://www.smashingmagazine.com/2011/03/08/ten-things-every-wordpress-plugin-developer-should-know/
*/
public static function log( $message ) {
if ( true === WP_DEBUG ) {
if ( is_array( $message ) || is_object( $message ) ) {
error_log( __( 'Advanced Ads Error following:', 'advanced-ads' ) );
error_log( print_r( $message, true ) );
} else {
/* translators: %s is an error message generated by the plugin. */
$message = sprintf( __( 'Advanced Ads Error: %s', 'advanced-ads' ), $message );
error_log( $message );
}
}
}
/**
* Compat method
*
* @return array with plugin options
*/
public function options() {
// we cant store options if WPML String Translations is enabled, or it would not translate the "Ad Label" option.
if ( ! isset( $this->options ) || class_exists( 'WPML_ST_String' ) ) {
$this->options = get_option( ADVADS_SLUG, [] );
}
// allow to change options dynamically
$this->options = apply_filters( 'advanced-ads-options', $this->options );
return $this->options;
}
/**
* Compat method
*
* @return array with adblocker options
*/
public function get_adblocker_options() {
// we cant store options if WPML String Translations is enabled, or it would not translate the "Ad Label" option.
if ( ! isset( $this->adblocker_options ) || class_exists( 'WPML_ST_String' ) ) {
$this->adblocker_options = wp_parse_args(
get_option( ADVADS_SETTINGS_ADBLOCKER, [] ),
[
'method' => false,
]
);
}
return $this->adblocker_options;
}
/**
* Compat method
*
* @return array with internal plugin options
*/
public function internal_options() {
if ( ! isset( $this->internal_options ) ) {
$defaults = [
'version' => ADVADS_VERSION,
'installed' => time(), // when was this installed.
];
$this->internal_options = get_option( ADVADS_SLUG . '-internal', [] );
// save defaults.
if ( [] === $this->internal_options ) {
$this->internal_options = $defaults;
$this->update_internal_options( $this->internal_options );
( new Capabilities() )->create_capabilities();
}
// for versions installed prior to 1.5.3 set installed date for now.
if ( ! isset( $this->internal_options['installed'] ) ) {
$this->internal_options['installed'] = time();
$this->update_internal_options( $this->internal_options );
}
}
return $this->internal_options;
}
/**
* Injected ad into content (before and after)
* Displays ALL ads
*
* @param string $content post content.
*
* @return string
*/
public function inject_content( $content = '' ) {
$options = $this->options();
// do not inject in content when on a BuddyPress profile upload page (avatar & cover image).
if ( ( function_exists( 'bp_is_user_change_avatar' ) && \bp_is_user_change_avatar() ) || ( function_exists( 'bp_is_user_change_cover_image' ) && bp_is_user_change_cover_image() ) ) {
return $content;
}
// do not inject ads multiple times, e.g., when the_content is applied multiple times.
if ( $this->has_many_the_content() ) {
return $content;
}
// Check if ads are disabled in secondary queries.
if ( ! empty( $options['disabled-ads']['secondary'] ) ) {
// this function was called by ajax (in secondary query).
if ( wp_doing_ajax() ) {
return $content;
}
// get out of wp_router_page post type if ads are disabled in secondary queries.
if ( 'wp_router_page' === get_post_type() ) {
return $content;
}
}
// No need to inject ads because all tags are stripped from excepts.
if ( doing_filter( 'get_the_excerpt' ) ) {
return $content;
}
// make sure that no ad is injected into another ad.
if ( get_post_type() === Constants::POST_TYPE_AD ) {
return $content;
}
// Do not inject on admin pages.
if ( is_admin() && ! wp_doing_ajax() ) {
return $content;
}
// Do not inject in writing REST requests.
if ( Conditional::is_gutenberg_writing_request() && Conditional::is_rest_request() ) {
return $content;
}
if ( ! $this->can_inject_into_content() ) {
return $content;
}
$placements = wp_advads_get_all_placements();
if ( ! apply_filters( 'advanced-ads-can-inject-into-content', true, $content, $placements ) ) {
return $content;
}
foreach ( $placements as $placement_id => $placement ) {
$item = $placement->get_item();
$type_object_id = $placement->get_type_object()->get_id();
if (
empty( $item )
|| 'default' === $type_object_id
|| ! apply_filters( 'advanced-ads-can-inject-into-content-' . $placement_id, true, $content, $placement )
) {
continue;
}
$placement_options = $placement->get_data();
switch ( $type_object_id ) {
case 'post_top':
$placement_content = get_the_placement(
$placement_id,
'',
$placement_options
);
$content = $placement_content . $content;
break;
case 'post_bottom':
$content .= get_the_placement(
$placement_id,
'',
$placement_options
);
break;
case 'post_content':
$content = Advanced_Ads_In_Content_Injector::inject_in_content( $placement_id, $placement_options, $content );
break;
}
}
if ( ! empty( Params::cookie( 'advads_frontend_picker' ) ) ) {
// Make possible to know where the content starts and ends.
$content = '<ins style="display: none;" class="advads-frontend-picker-boundary-helper"></ins>
' . $content;
}
return $content;
}
/**
* Whether injection using `the_content` is allowed
*
* @return bool
*/
private function can_inject_into_content() {
global $wp_query;
if ( is_feed() || Conditional::is_rest_request() ) {
return true;
}
$options = $this->options();
/**
* Allows experienced user to control up to the nth post ads will be injected via post content placement in a post list.
*
* Post displaying an excerpt instead of the full content will still be skipped (mainly controlled by the active theme).
*
* @param int|string $archive_injection_count the string "true" when ads is injected into all posts.
*/
$archive_injection_count = apply_filters( 'advanced-ads-content-injection-index', $options['content-injection-everywhere'] ?? 1 );
// Run only within the loop on single pages of public post types.
$public_post_types = get_post_types(
[
'public' => true,
'publicly_queryable' => true,
],
'names',
'or'
);
// Check if admin allows injection in all places.
$injection_enabled = $options['content-injection-enabled'] ?? 'off';
if ( ( $injection_enabled === 'off' || 0 === $archive_injection_count ) && ( ! is_singular( $public_post_types ) || ( ! Conditional::is_amp() && ! $this->in_the_loop() && ! $this->was_in_the_loop ) ) ) {
return false;
}
if ( is_main_query() && ! empty( $options ) && 'true' !== $archive_injection_count && isset( $wp_query->current_post ) && $wp_query->current_post >= $archive_injection_count ) {
return false;
}
return true;
}
/**
* General check if ads can be displayed for the whole page impression
*
* @return bool true, if ads can be displayed.
* @todo move this to set_disabled_constant().
*/
public function can_display_ads() {
$options = $this->options();
/**
* Check if ads are disabled on the currently displayed page. Allow user to define their own rules if needed.
*
* @param bool $ads_disabled whether ads are disabled by the plugin options.
* @param array $options plugin options.
*
* @return bool `true` if ads are disabled
*/
$ads_disabled = apply_filters( 'advanced-ads-disabled-ads', Conditional::is_ad_disabled(), $options );
if ( $ads_disabled ) {
return false;
}
// check if ads are disabled in secondary queries.
// and this is not main query and this is not ajax (because main query does not exist in ajax but ad needs to be shown).
if ( ! empty( $options['disabled-ads']['secondary'] ) && ! $this->is_main_query() && ! wp_doing_ajax() ) {
return false;
}
return true;
}
/**
* Add meta robots noindex, nofollow to images, which are part of 'Image ad' ad type
*/
public function noindex_attachment_images() {
global $post;
if ( is_attachment() && is_object( $post ) && isset( $post->post_parent ) ) {
$post_parent = get_post( $post->post_parent );
$parent_is_ad = $post_parent && Constants::POST_TYPE_AD === $post_parent->post_type;
// if the image was not attached to any post and if at least one image ad contains the image. Needed for backward compatibility.
$parent_is_image_ad = ( empty( $post->post_parent ) && 0 < get_post_meta( get_the_ID(), '_advanced-ads_parent_id', true ) );
if ( $parent_is_ad || $parent_is_image_ad ) {
echo '<meta name="robots" content="noindex,nofollow" />';
}
}
}
/**
* Show custom CSS in the header
*/
public function custom_header_code(){
if ( ! defined( 'ADVANCED_ADS_DISABLE_EDIT_BAR' ) && Conditional::user_can( 'advanced_ads_edit_ads' ) ) {
?><style>
div.advads-edit-bar{position:absolute;height:0;display:none;z-index:10000;animation:advads-edit-appear 2s linear 1;}
@keyframes advads-edit-appear {
0% {opacity: 0.0;pointer-events: none;}
66% {opacity: 0.0;}
100% {opacity: 1.0;}
}
a.advads-edit-button{position:absolute;top:0;left:0;text-decoration:none !important;box-shadow:none;border-bottom:none;color:#0074a2;margin-top:-5px;}
a.advads-edit-button span{top:10px;line-height:25px;margin-left:-5px;width:26px;height:26px;border-radius:13px;border:solid 1px #0074a2;background:#fff}
<?php
printf(
'div[class^="%s"]:hover > div.advads-edit-bar {display: inline-block; vertical-align: top;}',
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
wp_advads()->get_frontend_prefix()
);
?>
</style>
<?php
}
}
/**
* Supports the "$this->is_main_query=true" while main query is being executed
*
* @param WP_Post $post The Post object (passed by reference).
* @param WP_Query $query The current Query object (passed by reference).
*/
public function set_query_type( $post, $query = null ) {
if ( $query instanceof WP_Query ) {
$this->is_main_query = $query->is_main_query();
}
}
/**
* Check if main query is being executed
*
* @return bool true while main query is being executed or not in the loop, false otherwise
*/
public function is_main_query() {
if ( ! $this->in_the_loop() ) {
// the secondary query check only designed for within post content.
return true;
}
return true === $this->is_main_query;
}
/**
* Sets whether the loop has started.
*/
public function set_loop_start() {
$this->in_the_loop = true;
}
/**
* Sets whether the loop has ended.
*/
public function set_loop_end() {
$this->in_the_loop = false;
}
/**
* Whether the loop has started and the caller is in the loop.
*
* @return bool
*/
public function in_the_loop() {
if ( in_the_loop() ) {
return true;
}
if ( $this->in_the_loop ) {
return true;
}
}
/**
* Find the calls to `the_content` inside functions hooked to `the_content`.
*
* @return bool
*/
public function has_many_the_content() {
global $wp_current_filter;
if ( count( array_keys( $wp_current_filter, 'the_content', true ) ) > 1 ) {
// More then one `the_content` in the stack.
return true;
}
return false;
}
/**
* Get an "Advertisement" label to use before single ad or before first ad in a group
*
* @param Ad|Group $item Ad or group.
* @param string $placement_state default/enabled/disabled.
*
* @return string label, empty string if label should not be displayed.
*/
public function get_label( $item, $placement_state = 'default' ) {
if ( 'disabled' === $placement_state ) {
return '';
}
$advads_options = self::get_instance()->options();
if ( 'enabled' !== $placement_state && empty( $advads_options['custom-label']['enabled'] ) ) {
return '';
}
$label = $advads_options['custom-label']['text'] ?? _x( 'Advertisements', 'label above ads', 'advanced-ads' );
$allowed_tags = [
'a' => [
'href' => true,
'title' => true,
],
'b' => [],
'blockquote' => [
'cite' => true,
],
'cite' => [],
'code' => [],
'del' => [
'datetime' => true,
],
'em' => [],
'i' => [],
'q' => [
'cite' => true,
],
's' => [],
'span' => [
'style' => true,
],
'strike' => [],
'br' => [],
'strong' => [],
];
// ad level label
if ( ! empty( $item->get_prop( 'ad_label' ) ) ) {
$label = $item->get_prop( 'ad_label' );
}
$label = ! empty( $advads_options['custom-label']['html_enabled'] ) ? wp_kses( $label, $allowed_tags ) : esc_html( $label );
$template = sprintf( '<div class="%s">%s</div>', wp_advads()->get_frontend_prefix() . 'adlabel', $label );
return apply_filters( 'advanced-ads-custom-label', $template, $label );
}
/**
* Retrieve the number of ads in any status
* excludes trash status by default
*
* @deprecated 1.48.2
*
* @param string|array $post_status default post status.
*
* @return int number of ads.
*/
public static function get_number_of_ads( $post_status = 'any' ) {
_deprecated_function( __METHOD__, '1.48.0', 'AdvancedAds\Utilities\WordPress::get_count_ads()' );
return WordPress::get_count_ads( $post_status );
}
/**
* Get the array with ad placements
*
* @deprecated 2.0.0 wp_advads_get_all_placements
*
* @return array $ad_placements
*/
public static function get_ad_placements_array() {
return wp_advads_get_all_placements();
}
/**
* Return the Advanced_Ads_Model responsible for loading ads, groups and placements into the frontend
*
* @deprecated 2.0.0 use new entity functions.
*
* @return mixed
*/
public function get_model() {
if ( ! isset( $this->model ) ) {
$this->model = new Advanced_Ads_Model();
}
return $this->model;
}
/**
* Store whether the loop started in an inner `the_content`.
*
* If so, let us assume that we are in the loop when we are in the outermost `the_content`.
* Makes sense only when a hooked to `the_content` function that produces an inner `the_content` has
* lesser priority then `$this->plugin->get_content_injection_priority()`.
*
* @param string $content Post content (unchanged).
*
* @return string
*/
public function set_was_in_the_loop( $content ) {
if ( self::get_instance()->has_many_the_content() ) {
$this->was_in_the_loop = $this->was_in_the_loop || $this->in_the_loop();
} else {
// Next top level `the_content`, forget that the loop started.
$this->was_in_the_loop = false;
}
return $content;
}
/**
* Listen to URL parameters for debugging
*/
private function debug_parameter() {
$referer = Params::server( 'HTTP_REFERER' );
if ( wp_doing_ajax() && $referer ) {
$query_string = wp_parse_url( $referer, PHP_URL_QUERY );
if ( $query_string ) {
parse_str( $query_string, $query );
}
if ( empty( $query['aa-debug'] ) ) {
return;
}
$debug_query = $query['aa-debug'];
} else {
$debug_query = Params::get( 'aa-debug' );
if ( empty( $debug_query ) ) {
return;
}
}
$parameters = explode( ',', sanitize_text_field( $debug_query ) );
foreach ( $parameters as $parameter ) {
switch ( trim( $parameter ) ) {
case 'dummy':
// switch all ads to "dummy"
add_filter( 'advanced-ads-ad-option-type', function() {
return 'dummy';
} );
break;
case 'vcoff':
// disable ad visitor conditions
add_filter( 'advanced-ads-ad-option-visitors', '__return_empty_array' );
break;
case 'cboff':
// disable cache-busting for all ads
add_filter( 'advanced-ads-ad-select-args', function( $args ) {
$args['cache-busting'] = 'ignore';
return $args;
} );
break;
}
}
}
/**
* Get priority used for injection inside content
*/
public function get_content_injection_priority() {
$options = $this->options();
return isset( $options['content-injection-priority'] ) ? (int) $options['content-injection-priority'] : 100;
}
/**
* Update internal plugin options
*
* @param array $options new internal options.
*/
public function update_internal_options( array $options ) {
// do not allow to clear options.
if ( [] === $options ) {
return;
}
$this->internal_options = $options;
update_option( ADVADS_SLUG . '-internal', $options );
}
/**
* Fires when a post is transitioned from one status to another.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
*/
public function transition_ad_status( $new_status, $old_status, $post ) {
if ( ! isset( $post->post_type ) || Constants::POST_TYPE_AD !== $post->post_type || ! isset( $post->ID ) ) {
return;
}
$ad = wp_advads_get_ad( $post->ID );
if ( $old_status !== $new_status ) {
/**
* Fires when an ad has transitioned from one status to another.
*
* @param Ad $ad Ad object.
*/
do_action( "advanced-ads-ad-status-{$old_status}-to-{$new_status}", $ad );
}
if ( 'publish' === $new_status && 'publish' !== $old_status ) {
/**
* Fires when an ad has transitioned from any other status to `publish`.
*
* @param Ad $ad Ad object.
*/
do_action( 'advanced-ads-ad-status-published', $ad );
}
if ( 'publish' === $old_status && 'publish' !== $new_status ) {
/**
* Fires when an ad has transitioned from `publish` to any other status.
*
* @param Ad $ad Ad object.
*/
do_action( 'advanced-ads-ad-status-unpublished', $ad );
}
if ( $old_status === 'publish' && $new_status === Constants::AD_STATUS_EXPIRED ) {
/**
* Fires when an ad is expired.
*
* @param int $id
* @param Ad $ad
*/
do_action( 'advanced-ads-ad-expired', $ad->get_id(), $ad );
}
}
}

View File

@@ -0,0 +1 @@
<?php // Silence is golden

View File

@@ -0,0 +1,27 @@
<?php
/**
* Ad debug output template.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.x.x
*
* @var string $wrapper_id Wrapper ID.
* @var string $style Wrapper style.
* @var array $content Debug content.
*/
use AdvancedAds\Utilities\Conditional;
if ( ! Conditional::is_amp() ) :
ob_start();
echo Advanced_Ads_Utils::get_inline_asset( ob_get_clean() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
endif;
?>
<div id="<?php echo esc_attr( $wrapper_id ); ?>" style="<?php echo esc_attr( $style ); ?>">
<strong><?php esc_html_e( 'Ad debug output', 'advanced-ads' ); ?></strong>
<br><br>
<?php echo implode( '<br><br>', $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<br><br>
<a style="color: green;" href="https://wpadvancedads.com/manual/ad-debug-mode/?utm_source=advanced-ads&utm_medium=link&utm_campaign=ad-debug-mode" target="_blank" rel="nofollow"><?php esc_html_e( 'Find solutions in the manual', 'advanced-ads' ); ?></a>
</div>

View File

@@ -0,0 +1,13 @@
<?php
/**
* Edit bar for ads.
*
* @package AdvanceAds
*
* @var Ad $this Ad instance.
*/
?>
<div class="advads-edit-bar advads-edit-appear">
<a href="<?php echo esc_url( $this->get_edit_link() ); ?>" class="advads-edit-button" title="<?php echo esc_attr( wp_strip_all_tags( $this->get_title() ) ); ?>" rel="nofollow"><span class="dashicons dashicons-edit"></span></a>
</div>

View File

@@ -0,0 +1 @@
<?php // Silence is golden

View File

@@ -0,0 +1,16 @@
<?php
/**
* Represents the view for the public-facing component of the plugin.
*
* This typically includes any information, if any, that is rendered to the
* frontend of the theme when the plugin is activated.
*
* @package Plugin_Name
* @author Your Name <email@example.com>
* @license GPL-2.0+
* @link http://example.com
* @copyright 2013 Your Name or Company Name
*/
?>
<!-- This file is used to markup the public facing aspect of the plugin. -->