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,236 @@
<?php // phpcs:ignoreFile
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Abstracts\Group;
use AdvancedAds\Utilities\WordPress;
use AdvancedAds\Utilities\Conditional;
use AdvancedAds\Framework\Utilities\Params;
/**
* Cache Busting admin user interface.
*/
class Advanced_Ads_Pro_Module_Cache_Busting_Admin_UI {
/**
* Constructor
*/
public function __construct() {
add_filter( 'advanced-ads-group-hints', [ $this, 'get_group_hints' ], 10, 2 );
if ( empty( Advanced_Ads_Pro::get_instance()->get_options()['cache-busting']['enabled'] ) ) {
return;
}
add_action( 'advanced-ads-placement-options-before-advanced', [ $this, 'admin_placement_options' ], 10, 2 );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
add_action( 'advanced-ads-ad-params-after', [ $this, 'check_ad' ], 9 );
add_filter( 'advanced-ads-ad-notices', [$this, 'ad_notices'], 10, 3 );
add_action( 'wp_ajax_advads-reset-vc-cache', [ $this, 'reset_vc_cache' ] );
add_action( 'wp_ajax_advads-placement-activate-cb', [ $this, 'ads_activate_placement_cb' ] );
}
/**
* Activate placement cache busting
*/
public function ads_activate_placement_cb() {
check_ajax_referer( 'advanced-ads-admin-ajax-nonce', 'nonce' );
if ( ! Conditional::user_can( 'advanced_ads_manage_options' ) && ! filter_has_var( INPUT_POST, 'placement' ) ) {
wp_send_json_error( esc_html__( 'You are not allowed to do this.', 'advanced-ads-pro' ), 400 );
}
$placement_slug = sanitize_text_field( Params::post( 'placement' ) );
$placement = wp_advads_get_placement_by_slug( $placement_slug );
if ( $placement ) {
$placement->set_prop( 'cache-busting', Advanced_Ads_Pro_Module_Cache_Busting::OPTION_AUTO );
$placement->save();
wp_send_json_success( esc_html__( 'Cache busting has been successfully enabled for the assigned placement.', 'advanced-ads-pro' ) );
}
wp_send_json_error( esc_html__( "Couldn't find the placement.", 'advanced-ads-pro' ), 400 );
}
/**
* Update visitor consitions cache.
*/
public function reset_vc_cache() {
if ( ! Conditional::user_can( 'advanced_ads_manage_options' ) ) {
return;
}
check_ajax_referer( 'advads-pro-reset-vc-cache-nonce', 'security' );
$time = time();
$options = get_option( 'advanced-ads-pro' );
$options['cache-busting']['vc_cache_reset'] = $time;
update_option( 'advanced-ads-pro', $options );
echo $time;
exit;
}
/**
* add placement options on placement page
*
* @param string $placement_slug Placement id.
* @param Placement $placement Placement instance.
*/
public function admin_placement_options( $placement_slug, $placement ) {
$type_options = $placement->get_type_object()->get_options();
if ( isset( $type_options['placement-cache-busting'] ) && ! $type_options['placement-cache-busting'] ) {
return;
}
// l10n
$values = [
Advanced_Ads_Pro_Module_Cache_Busting::OPTION_AUTO => esc_html__( 'auto','advanced-ads-pro' ),
Advanced_Ads_Pro_Module_Cache_Busting::OPTION_ON => esc_html__( 'AJAX','advanced-ads-pro' ),
Advanced_Ads_Pro_Module_Cache_Busting::OPTION_OFF => esc_html__( 'off','advanced-ads-pro' ),
];
// options
$value = $placement->get_prop( 'cache-busting' );
$value = $value === Advanced_Ads_Pro_Module_Cache_Busting::OPTION_ON
? Advanced_Ads_Pro_Module_Cache_Busting::OPTION_ON
: ( $value === Advanced_Ads_Pro_Module_Cache_Busting::OPTION_OFF ? Advanced_Ads_Pro_Module_Cache_Busting::OPTION_OFF : Advanced_Ads_Pro_Module_Cache_Busting::OPTION_AUTO );
ob_start();
foreach ( $values as $k => $l ) {
$selected = checked( $value, $k, false );
echo '<label><input' . $selected . ' type="radio" name="advads[placements][options][cache-busting]" value="'.$k.'" id="advads-placement-'.
$placement_slug.'-cache-busting-'.$k.'"/>'.$l.'</label>';
}
$option_content = ob_get_clean();
WordPress::render_option(
'placement-cache-busting',
_x( 'Cache-busting', 'placement admin label', 'advanced-ads-pro' ),
$option_content );
}
/**
* enqueue scripts for validation the ad
*/
public function enqueue_admin_scripts() {
$screen = get_current_screen();
$uriRelPath = plugin_dir_url( __FILE__ );
if ( isset( $screen->id ) && $screen->id === 'advanced_ads' ) { //ad edit page
wp_register_script( 'krux/prescribe', $uriRelPath . 'inc/prescribe.js', [ 'jquery' ], '1.1.3' );
wp_enqueue_script( 'advanced-ads-pro/cache-busting-admin', $uriRelPath . 'inc/admin.js', [ 'krux/prescribe' ], AAP_VERSION );
} elseif ( Conditional::is_screen_advanced_ads() ) {
wp_enqueue_script( 'advanced-ads-pro/cache-busting-admin', $uriRelPath . 'inc/admin.js', [], AAP_VERSION );
}
}
/**
* add validation for cache-busting
*
* @param Ad $ad Ad instance.
*/
public function check_ad( $ad ) {
include dirname( __FILE__ ) . '/views/settings_check_ad.php';
}
/**
* show cache-busting specific ad notices
*
* @since 1.13.1
*
* @param array $notices Notices.
* @param array $box Current meta box.
* @param Ad $ad Ad instance.
*
* @return array
*/
public function ad_notices( $notices, $box, $ad ): array {
// Show hint that for ad-group ad type, cache-busting method will only be AJAX or off
if ( 'ad-parameters-box' === $box['id'] && $ad->is_type( 'group' ) ) {
$notices[] = [
'text' => __( 'The <em>Ad Group</em> ad type can only use AJAX or no cache-busting, but not passive cache-busting.', 'advanced-ads-pro' ),
// 'class' => 'advads-ad-notice-pro-ad-group-cache-busting',
];
}
return $notices;
}
/**
* Get group hints.
*
* @param string[] $hints Group hints (escaped strings).
* @param Group $group The group object.
*
* @return string[]
*/
public function get_group_hints( $hints, Group $group ) {
// Pro is installed but cache busting is disabled.
if ( empty( Advanced_Ads_Pro::get_instance()->get_options()['cache-busting']['enabled'] ) ) {
$hints[] = sprintf(
wp_kses(
/* translators: %s is a URL. */
__( 'It seems that a caching plugin is activated. Your ads might not rotate properly while cache busting is disabled. <a href="%s" target="_blank">Activate cache busting.</a>', 'advanced-ads-pro' ),
[
'a' => [
'href' => [],
'target' => [],
],
]
),
esc_url( admin_url( 'admin.php?page=advanced-ads-settings#top#pro' ) )
);
return $hints;
}
$placements = wp_advads_placements_by_item_id( 'group_' . $group->get_id() );
// The group doesn't use a placement.
if (
! $placements
&& empty( Advanced_Ads_Pro::get_instance()->get_options()['cache-busting']['passive_all'] )
) {
$hints[] = sprintf(
wp_kses(
/* translators: %s is a URL. */
__( 'You need a placement to deliver this group using cache busting. <a href="%s" target="_blank">Create a placement now.</a>', 'advanced-ads-pro' ),
[
'a' => [
'href' => [],
'target' => [],
],
]
),
esc_url( admin_url( 'admin.php?page=advanced-ads-placements' ) )
);
return $hints;
}
// The Group uses a placement where cache busting is disabled.
foreach ( $placements as $slug => $placement ) {
$placement_data = $placement->get_data();
if ( isset( $placement_data['cache-busting'] )
&& $placement_data['cache-busting'] === Advanced_Ads_Pro_Module_Cache_Busting::OPTION_OFF
) {
$hints[] = sprintf(
wp_kses(
/* translators: %s is a URL. */
__( 'It seems that a caching plugin is activated. Your ads might not rotate properly, while cache busting is disabled for the placement your group is using. <a href="#" data-placement="%s" class="js-placement-activate-cb">Activate cache busting for this placement.</a>', 'advanced-ads-pro' ),
[
'a' => [
'href' => [],
'data-placement' => [],
'class' => [],
],
]
),
$slug
);
return $hints;
}
}
return $hints;
}
}

View File

@@ -0,0 +1,44 @@
<?php // phpcs:ignore WordPress.Files.FileName
/**
* Admin class for the Advanced Ads Pro Cache Busting module.
*
* @package AdvancedAds\Pro\Modules\Cache_Busting
* @author Advanced Ads <info@wpadvancedads.com>
*/
/**
* Class Cache_Busting
*/
class Advanced_Ads_Pro_Module_Cache_Busting_Admin {
/**
* The constructor
*/
public function __construct() {
add_action( 'advanced-ads-settings-init', [ $this, 'settings_init' ] );
}
/**
* Add settings for the module.
*
* @return void
*/
public function settings_init(): void {
add_settings_field(
'module-cache-busting',
__( 'Cache Busting', 'advanced-ads-pro' ),
[ $this, 'render_settings' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
Advanced_Ads_Pro::OPTION_KEY . '_modules-enable'
);
}
/**
* Render the settings.
*
* @return void
*/
public function render_settings() {
include_once __DIR__ . '/views/settings.php';
}
}

View File

@@ -0,0 +1,3 @@
<?php
new Advanced_Ads_Pro_Module_Cache_Busting_Admin;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
<?php
// module configuration
$path = dirname( __FILE__ );
return [
'classmap' => [
'Advanced_Ads_Pro_Cache_Busting_Server_Info' => $path . '/server-info.class.php',
],
'textdomain' => null,
];

View File

@@ -0,0 +1,120 @@
jQuery( document ).ready(function( $ ){
$( '.advads-option-group-refresh input:checkbox:checked' ).each( function() {
var number_option = $( this ).parents( '.advads-ad-group-form' ).find( '.advads-option-group-number' );
number_option.val( 'all' ).hide();
});
$( '.advads-option-group-refresh input:checkbox' ).on( 'click', function() {
var number_option = $( this ).parents( '.advads-ad-group-form' ).find( '.advads-option-group-number' );
if ( this.checked ) {
number_option.val( 'all' ).hide();
} else {
number_option.show();
}
});
jQuery( '.advads-option-placement-cache-busting input' ).on( 'change', function() {
var cb_state = jQuery( this ).val(),
$inputs = jQuery( this ).closest( '.advads-placements-table-options' ).find( '.advanced-ads-inputs-dependent-on-cb' );
if ( 'off' === cb_state ) {
// Hide UI elements that work only with cache-busting.
$inputs.hide().next().show();
}
else {
$inputs.show().next().hide();
}
});
$( '#advads-pro-vc-hash-change' ).on( 'click', function() {
var $button = $(this);
var $ok = jQuery( '#advads-pro-vc-hash-change-ok' );
var $error = jQuery( '#advads-pro-vc-hash-change-error' );
$( '<span class="spinner advads-spinner"></span>' ).insertAfter( $button );
$button.hide();
$ok.hide();
$error.hide();
jQuery.ajax( {
type: 'POST',
url: ajaxurl,
data: {
action: 'advads-reset-vc-cache',
security: $('#advads-pro-reset-vc-cache-nonce').val()
},
} ).done(function( data ) {
jQuery( '#advads-pro-vc-hash' ).val( data );
$ok.show();
} ).fail(function( jqXHR, textStatus ) {
$error.show();
} ).always( function() {
$( 'span.spinner' ).remove();
$button.show();
} );
});
$('.js-placement-activate-cb').on('click',function( e ){
e.preventDefault();
const button = $( this );
const placement = button.data('placement');
const loader = jQuery( '<span class="advads-loader"></span>' );
// Replace the dynamic field with the loader.
button.parent().replaceWith( loader );
$.post( ajaxurl, {
action: 'advads-placement-activate-cb',
placement: placement.toString(),
nonce: window.advads_geo_translation.nonce
} )
.done( function ( result ) {
if ( ! $.isPlainObject( result ) ) {
return;
}
loader.replaceWith( '<p class="advads-notice-inline advads-idea">' + result.data + '</p>' );
} )
.fail( function ( jqXHR, errormessage, errorThrown ) {
loader.replaceWith( '<p class="advads-notice-inline advads-error">' + jqXHR.responseJSON.data + '</p>' );
} )
});
});
function advads_cb_check_set_status( status, msg ) {
if ( status === true ) {
jQuery( '#advads-cache-busting-possibility' ).val( true );
} else {
jQuery( '#advads-cache-busting-possibility' ).val( false );
jQuery( '#advads-cache-busting-error-result' ).append( msg ? '<br />' + msg : '' ).show();
}
}
function advads_cb_check_ad_markup( ad_content ) {
if ( ! ad_content ) {
return;
}
// checks whether the ad contains the jQuery.document.ready() and document.write(ln) functions
if ( ( /\)\.ready\(/.test( ad_content ) || /(\$|jQuery)\(\s*?function\(\)/.test( ad_content ) ) && /document\.write/.test( ad_content ) ) {
advads_cb_check_set_status( false );
return;
}
var search_str = 'cache_busting_test';
var source = ad_content += search_str;
var parser = new Prescribe( source, { autoFix: true } );
var tok, result = '';
while ( ( tok = parser.readToken() ) ) {
if (tok) {
result += Prescribe.tokenToString(tok);
}
}
advads_cb_check_set_status( ( result.substr( - search_str.length ) === search_str ) ? true : false );
}

View File

@@ -0,0 +1,924 @@
/**
* @file prescribe
* @description Tiny, forgiving HTML parser
* @version v1.1.3
* @see {@link https://github.com/krux/prescribe/}
* @license MIT
* @author Derek Brans
* @copyright 2017 Krux Digital, Inc
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Prescribe"] = factory();
else
root["Prescribe"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _HtmlParser = __webpack_require__(1);
var _HtmlParser2 = _interopRequireDefault(_HtmlParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
module.exports = _HtmlParser2['default'];
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
var _supports = __webpack_require__(2);
var supports = _interopRequireWildcard(_supports);
var _streamReaders = __webpack_require__(3);
var streamReaders = _interopRequireWildcard(_streamReaders);
var _fixedReadTokenFactory = __webpack_require__(6);
var _fixedReadTokenFactory2 = _interopRequireDefault(_fixedReadTokenFactory);
var _utils = __webpack_require__(5);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Detection regular expressions.
*
* Order of detection matters: detection of one can only
* succeed if detection of previous didn't
* @type {Object}
*/
var detect = {
comment: /^<!--/,
endTag: /^<\//,
atomicTag: /^<\s*(script|style|noscript|iframe|textarea)[\s\/>]/i,
startTag: /^</,
chars: /^[^<]/
};
/**
* HtmlParser provides the capability to parse HTML and return tokens
* representing the tags and content.
*/
var HtmlParser = function () {
/**
* Constructor.
*
* @param {string} stream The initial parse stream contents.
* @param {Object} options The options
* @param {boolean} options.autoFix Set to true to automatically fix errors
*/
function HtmlParser() {
var _this = this;
var stream = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, HtmlParser);
this.stream = stream;
var fix = false;
var fixedTokenOptions = {};
for (var key in supports) {
if (supports.hasOwnProperty(key)) {
if (options.autoFix) {
fixedTokenOptions[key + 'Fix'] = true; // !supports[key];
}
fix = fix || fixedTokenOptions[key + 'Fix'];
}
}
if (fix) {
this._readToken = (0, _fixedReadTokenFactory2['default'])(this, fixedTokenOptions, function () {
return _this._readTokenImpl();
});
this._peekToken = (0, _fixedReadTokenFactory2['default'])(this, fixedTokenOptions, function () {
return _this._peekTokenImpl();
});
} else {
this._readToken = this._readTokenImpl;
this._peekToken = this._peekTokenImpl;
}
}
/**
* Appends the given string to the parse stream.
*
* @param {string} str The string to append
*/
HtmlParser.prototype.append = function append(str) {
this.stream += str;
};
/**
* Prepends the given string to the parse stream.
*
* @param {string} str The string to prepend
*/
HtmlParser.prototype.prepend = function prepend(str) {
this.stream = str + this.stream;
};
/**
* The implementation of the token reading.
*
* @private
* @returns {?Token}
*/
HtmlParser.prototype._readTokenImpl = function _readTokenImpl() {
var token = this._peekTokenImpl();
if (token) {
this.stream = this.stream.slice(token.length);
return token;
}
};
/**
* The implementation of token peeking.
*
* @returns {?Token}
*/
HtmlParser.prototype._peekTokenImpl = function _peekTokenImpl() {
for (var type in detect) {
if (detect.hasOwnProperty(type)) {
if (detect[type].test(this.stream)) {
var token = streamReaders[type](this.stream);
if (token) {
if (token.type === 'startTag' && /script|style/i.test(token.tagName)) {
return null;
} else {
token.text = this.stream.substr(0, token.length);
return token;
}
}
}
}
}
};
/**
* The public token peeking interface. Delegates to the basic token peeking
* or a version that performs fixups depending on the `autoFix` setting in
* options.
*
* @returns {object}
*/
HtmlParser.prototype.peekToken = function peekToken() {
return this._peekToken();
};
/**
* The public token reading interface. Delegates to the basic token reading
* or a version that performs fixups depending on the `autoFix` setting in
* options.
*
* @returns {object}
*/
HtmlParser.prototype.readToken = function readToken() {
return this._readToken();
};
/**
* Read tokens and hand to the given handlers.
*
* @param {Object} handlers The handlers to use for the different tokens.
*/
HtmlParser.prototype.readTokens = function readTokens(handlers) {
var tok = void 0;
while (tok = this.readToken()) {
// continue until we get an explicit "false" return
if (handlers[tok.type] && handlers[tok.type](tok) === false) {
return;
}
}
};
/**
* Clears the parse stream.
*
* @returns {string} The contents of the parse stream before clearing.
*/
HtmlParser.prototype.clear = function clear() {
var rest = this.stream;
this.stream = '';
return rest;
};
/**
* Returns the rest of the parse stream.
*
* @returns {string} The contents of the parse stream.
*/
HtmlParser.prototype.rest = function rest() {
return this.stream;
};
return HtmlParser;
}();
exports['default'] = HtmlParser;
HtmlParser.tokenToString = function (tok) {
return tok.toString();
};
HtmlParser.escapeAttributes = function (attrs) {
var escapedAttrs = {};
for (var name in attrs) {
if (attrs.hasOwnProperty(name)) {
escapedAttrs[name] = (0, _utils.escapeQuotes)(attrs[name], null);
}
}
return escapedAttrs;
};
HtmlParser.supports = supports;
for (var key in supports) {
if (supports.hasOwnProperty(key)) {
HtmlParser.browserHasFlaw = HtmlParser.browserHasFlaw || !supports[key] && key;
}
}
/***/ },
/* 2 */
/***/ function(module, exports) {
'use strict';
exports.__esModule = true;
var tagSoup = false;
var selfClose = false;
var work = window.document.createElement('div');
try {
var html = '<P><I></P></I>';
work.innerHTML = html;
exports.tagSoup = tagSoup = work.innerHTML !== html;
} catch (e) {
exports.tagSoup = tagSoup = false;
}
try {
work.innerHTML = '<P><i><P></P></i></P>';
exports.selfClose = selfClose = work.childNodes.length === 2;
} catch (e) {
exports.selfClose = selfClose = false;
}
work = null;
exports.tagSoup = tagSoup;
exports.selfClose = selfClose;
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports.comment = comment;
exports.chars = chars;
exports.startTag = startTag;
exports.atomicTag = atomicTag;
exports.endTag = endTag;
var _tokens = __webpack_require__(4);
/**
* Regular Expressions for parsing tags and attributes
*
* @type {Object}
*/
var REGEXES = {
startTag: /^<([\-A-Za-z0-9_!:]+)((?:\s+[\w\-]+(?:\s*=?\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
endTag: /^<\/([\-A-Za-z0-9_:]+)[^>]*>/,
attr: /(?:([\-A-Za-z0-9_]+)\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))|(?:([\-A-Za-z0-9_]+)(\s|$)+)/g,
fillAttr: /^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noresize|noshade|nowrap|readonly|selected)$/i
};
/**
* Reads a comment token
*
* @param {string} stream The input stream
* @returns {CommentToken}
*/
function comment(stream) {
var index = stream.indexOf('-->');
if (index >= 0) {
return new _tokens.CommentToken(stream.substr(4, index - 1), index + 3);
}
}
/**
* Reads non-tag characters.
*
* @param {string} stream The input stream
* @returns {CharsToken}
*/
function chars(stream) {
var index = stream.indexOf('<');
return new _tokens.CharsToken(index >= 0 ? index : stream.length);
}
/**
* Reads start tag token.
*
* @param {string} stream The input stream
* @returns {StartTagToken}
*/
function startTag(stream) {
var endTagIndex = stream.indexOf('>');
if (endTagIndex !== -1) {
var match = stream.match(REGEXES.startTag);
if (match) {
var attrs = {};
var booleanAttrs = {};
var rest = match[2];
match[2].replace(REGEXES.attr, function (match, name) {
if (!(arguments[2] || arguments[3] || arguments[4] || arguments[5])) {
attrs[name] = '';
} else if (arguments[5]) {
attrs[arguments[5]] = '';
booleanAttrs[arguments[5]] = true;
} else {
attrs[name] = arguments[2] || arguments[3] || arguments[4] || REGEXES.fillAttr.test(name) && name || '';
}
rest = rest.replace(match, '');
});
return new _tokens.StartTagToken(match[1], match[0].length, attrs, booleanAttrs, !!match[3], rest.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''));
}
}
}
/**
* Reads atomic tag token.
*
* @param {string} stream The input stream
* @returns {AtomicTagToken}
*/
function atomicTag(stream) {
var start = startTag(stream);
if (start) {
var rest = stream.slice(start.length);
// for optimization, we check first just for the end tag
if (rest.match(new RegExp('<\/\\s*' + start.tagName + '\\s*>', 'i'))) {
// capturing the content is inefficient, so we do it inside the if
var match = rest.match(new RegExp('([\\s\\S]*?)<\/\\s*' + start.tagName + '\\s*>', 'i'));
if (match) {
return new _tokens.AtomicTagToken(start.tagName, match[0].length + start.length, start.attrs, start.booleanAttrs, match[1]);
}
}
}
}
/**
* Reads an end tag token.
*
* @param {string} stream The input stream
* @returns {EndTagToken}
*/
function endTag(stream) {
var match = stream.match(REGEXES.endTag);
if (match) {
return new _tokens.EndTagToken(match[1], match[0].length);
}
}
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports.EndTagToken = exports.AtomicTagToken = exports.StartTagToken = exports.TagToken = exports.CharsToken = exports.CommentToken = exports.Token = undefined;
var _utils = __webpack_require__(5);
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Token is a base class for all token types parsed. Note we don't actually
* use intheritance due to IE8's non-existent ES5 support.
*/
var Token =
/**
* Constructor.
*
* @param {string} type The type of the Token.
* @param {Number} length The length of the Token text.
*/
exports.Token = function Token(type, length) {
_classCallCheck(this, Token);
this.type = type;
this.length = length;
this.text = '';
};
/**
* CommentToken represents comment tags.
*/
var CommentToken = exports.CommentToken = function () {
/**
* Constructor.
*
* @param {string} content The content of the comment
* @param {Number} length The length of the Token text.
*/
function CommentToken(content, length) {
_classCallCheck(this, CommentToken);
this.type = 'comment';
this.length = length || (content ? content.length : 0);
this.text = '';
this.content = content;
}
CommentToken.prototype.toString = function toString() {
return '<!--' + this.content;
};
return CommentToken;
}();
/**
* CharsToken represents non-tag characters.
*/
var CharsToken = exports.CharsToken = function () {
/**
* Constructor.
*
* @param {Number} length The length of the Token text.
*/
function CharsToken(length) {
_classCallCheck(this, CharsToken);
this.type = 'chars';
this.length = length;
this.text = '';
}
CharsToken.prototype.toString = function toString() {
return this.text;
};
return CharsToken;
}();
/**
* TagToken is a base class for all tag-based Tokens.
*/
var TagToken = exports.TagToken = function () {
/**
* Constructor.
*
* @param {string} type The type of the token.
* @param {string} tagName The tag name.
* @param {Number} length The length of the Token text.
* @param {Object} attrs The dictionary of attributes and values
* @param {Object} booleanAttrs If an entry has 'true' then the attribute
* is a boolean attribute
*/
function TagToken(type, tagName, length, attrs, booleanAttrs) {
_classCallCheck(this, TagToken);
this.type = type;
this.length = length;
this.text = '';
this.tagName = tagName;
this.attrs = attrs;
this.booleanAttrs = booleanAttrs;
this.unary = false;
this.html5Unary = false;
}
/**
* Formats the given token tag.
*
* @param {TagToken} tok The TagToken to format.
* @param {?string} [content=null] The content of the token.
* @returns {string} The formatted tag.
*/
TagToken.formatTag = function formatTag(tok) {
var content = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var str = '<' + tok.tagName;
for (var key in tok.attrs) {
if (tok.attrs.hasOwnProperty(key)) {
str += ' ' + key;
var val = tok.attrs[key];
if (typeof tok.booleanAttrs === 'undefined' || typeof tok.booleanAttrs[key] === 'undefined') {
str += '="' + (0, _utils.escapeQuotes)(val) + '"';
}
}
}
if (tok.rest) {
str += ' ' + tok.rest;
}
if (tok.unary && !tok.html5Unary) {
str += '/>';
} else {
str += '>';
}
if (content !== undefined && content !== null) {
str += content + '</' + tok.tagName + '>';
}
return str;
};
return TagToken;
}();
/**
* StartTagToken represents a start token.
*/
var StartTagToken = exports.StartTagToken = function () {
/**
* Constructor.
*
* @param {string} tagName The tag name.
* @param {Number} length The length of the Token text
* @param {Object} attrs The dictionary of attributes and values
* @param {Object} booleanAttrs If an entry has 'true' then the attribute
* is a boolean attribute
* @param {boolean} unary True if the tag is a unary tag
* @param {string} rest The rest of the content.
*/
function StartTagToken(tagName, length, attrs, booleanAttrs, unary, rest) {
_classCallCheck(this, StartTagToken);
this.type = 'startTag';
this.length = length;
this.text = '';
this.tagName = tagName;
this.attrs = attrs;
this.booleanAttrs = booleanAttrs;
this.html5Unary = false;
this.unary = unary;
this.rest = rest;
}
StartTagToken.prototype.toString = function toString() {
return TagToken.formatTag(this);
};
return StartTagToken;
}();
/**
* AtomicTagToken represents an atomic tag.
*/
var AtomicTagToken = exports.AtomicTagToken = function () {
/**
* Constructor.
*
* @param {string} tagName The name of the tag.
* @param {Number} length The length of the tag text.
* @param {Object} attrs The attributes.
* @param {Object} booleanAttrs If an entry has 'true' then the attribute
* is a boolean attribute
* @param {string} content The content of the tag.
*/
function AtomicTagToken(tagName, length, attrs, booleanAttrs, content) {
_classCallCheck(this, AtomicTagToken);
this.type = 'atomicTag';
this.length = length;
this.text = '';
this.tagName = tagName;
this.attrs = attrs;
this.booleanAttrs = booleanAttrs;
this.unary = false;
this.html5Unary = false;
this.content = content;
}
AtomicTagToken.prototype.toString = function toString() {
return TagToken.formatTag(this, this.content);
};
return AtomicTagToken;
}();
/**
* EndTagToken represents an end tag.
*/
var EndTagToken = exports.EndTagToken = function () {
/**
* Constructor.
*
* @param {string} tagName The name of the tag.
* @param {Number} length The length of the tag text.
*/
function EndTagToken(tagName, length) {
_classCallCheck(this, EndTagToken);
this.type = 'endTag';
this.length = length;
this.text = '';
this.tagName = tagName;
}
EndTagToken.prototype.toString = function toString() {
return '</' + this.tagName + '>';
};
return EndTagToken;
}();
/***/ },
/* 5 */
/***/ function(module, exports) {
'use strict';
exports.__esModule = true;
exports.escapeQuotes = escapeQuotes;
/**
* Escape quotes in the given value.
*
* @param {string} value The value to escape.
* @param {string} [defaultValue=''] The default value to return if value is falsy.
* @returns {string}
*/
function escapeQuotes(value) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
// There's no lookback in JS, so /(^|[^\\])"/ only matches the first of two `"`s.
// Instead, just match anything before a double-quote and escape if it's not already escaped.
return !value ? defaultValue : value.replace(/([^"]*)"/g, function (_, prefix) {
return (/\\/.test(prefix) ? prefix + '"' : prefix + '\\"'
);
});
}
/***/ },
/* 6 */
/***/ function(module, exports) {
'use strict';
exports.__esModule = true;
exports['default'] = fixedReadTokenFactory;
/**
* Empty Elements - HTML 4.01
*
* @type {RegExp}
*/
var EMPTY = /^(AREA|BASE|BASEFONT|BR|COL|FRAME|HR|IMG|INPUT|ISINDEX|LINK|META|PARAM|EMBED)$/i;
/**
* Elements that you can intentionally leave open (and which close themselves)
*
* @type {RegExp}
*/
var CLOSESELF = /^(COLGROUP|DD|DT|LI|OPTIONS|P|TD|TFOOT|TH|THEAD|TR)$/i;
/**
* Corrects a token.
*
* @param {Token} tok The token to correct
* @returns {Token} The corrected token
*/
function correct(tok) {
if (tok && tok.type === 'startTag') {
tok.unary = EMPTY.test(tok.tagName) || tok.unary;
tok.html5Unary = !/\/>$/.test(tok.text);
}
return tok;
}
/**
* Peeks at the next token in the parser.
*
* @param {HtmlParser} parser The parser
* @param {Function} readTokenImpl The underlying readToken implementation
* @returns {Token} The next token
*/
function peekToken(parser, readTokenImpl) {
var tmp = parser.stream;
var tok = correct(readTokenImpl());
parser.stream = tmp;
return tok;
}
/**
* Closes the last token.
*
* @param {HtmlParser} parser The parser
* @param {Array<Token>} stack The stack
*/
function closeLast(parser, stack) {
var tok = stack.pop();
// prepend close tag to stream.
parser.prepend('</' + tok.tagName + '>');
}
/**
* Create a new token stack.
*
* @returns {Array<Token>}
*/
function newStack() {
var stack = [];
stack.last = function () {
return this[this.length - 1];
};
stack.lastTagNameEq = function (tagName) {
var last = this.last();
return last && last.tagName && last.tagName.toUpperCase() === tagName.toUpperCase();
};
stack.containsTagName = function (tagName) {
for (var i = 0, tok; tok = this[i]; i++) {
if (tok.tagName === tagName) {
return true;
}
}
return false;
};
return stack;
}
/**
* Return a readToken implementation that fixes input.
*
* @param {HtmlParser} parser The parser
* @param {Object} options Options for fixing
* @param {boolean} options.tagSoupFix True to fix tag soup scenarios
* @param {boolean} options.selfCloseFix True to fix self-closing tags
* @param {Function} readTokenImpl The underlying readToken implementation
* @returns {Function}
*/
function fixedReadTokenFactory(parser, options, readTokenImpl) {
var stack = newStack();
var handlers = {
startTag: function startTag(tok) {
var tagName = tok.tagName;
if (tagName.toUpperCase() === 'TR' && stack.lastTagNameEq('TABLE')) {
parser.prepend('<TBODY>');
prepareNextToken();
} else if (options.selfCloseFix && CLOSESELF.test(tagName) && stack.containsTagName(tagName)) {
if (stack.lastTagNameEq(tagName)) {
closeLast(parser, stack);
} else {
parser.prepend('</' + tok.tagName + '>');
prepareNextToken();
}
} else if (!tok.unary) {
stack.push(tok);
}
},
endTag: function endTag(tok) {
var last = stack.last();
if (last) {
if (options.tagSoupFix && !stack.lastTagNameEq(tok.tagName)) {
// cleanup tag soup
closeLast(parser, stack);
} else {
stack.pop();
}
} else if (options.tagSoupFix) {
// cleanup tag soup part 2: skip this token
readTokenImpl();
prepareNextToken();
}
}
};
function prepareNextToken() {
var tok = peekToken(parser, readTokenImpl);
if (tok && handlers[tok.type]) {
handlers[tok.type](tok);
}
}
return function fixedReadToken() {
prepareNextToken();
return correct(readTokenImpl());
};
}
/***/ }
/******/ ])
});
;

View File

@@ -0,0 +1,2 @@
<?php
Advanced_Ads_Pro_Module_Cache_Busting::get_instance();

View File

@@ -0,0 +1,355 @@
<?php // phpcs:ignoreFile
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Framework\Utilities\Params;
/**
* Reduce the number of AJAX calls: during the first AJAX call, save the data (in cookies),
* that cannot be checked using only JS. Later, the passive cache-busting can check that data.
*
* There are 2 ways to update the data array:
* 1. Define the 'ADVANCED_ADS_PRO_USER_COOKIE_MAX_AGE' constant (in seconds).
* An ajax requests will be initiated from time to time to update the expired conditions of the ads on the page.
* 2. Use the "Update visitor conditions cache in the user's browsers" option (Settings > Pro > Cache Busting ) and update the page cache.
* An ajax request will be initiated to update all the conditions of the ads on the page.
*/
class Advanced_Ads_Pro_Cache_Busting_Server_Info {
/**
* Holds the Cache Busting class.
*
* @var Advanced_Ads_Pro_Module_Cache_Busting
*/
public $cache_busting;
/**
* The options array.
*
* @var array
*/
public $options;
/**
* How long the server info cookie will be stored maximum.
*
* @var int
*/
public $server_info_duration;
/**
* How long the server info cookie will be stored maximum.
*
* @var int
*/
public $vc_cache_reset;
/**
* If we are in a current AJAX call.
*
* @var bool
*/
public $is_ajax;
/**
* The constructor.
*
* @param Advanced_Ads_Pro_Module_Cache_Busting $cache_busting Cache Busting instance.
* @param array $options Option array.
*/
public function __construct( $cache_busting, $options ) {
$this->cache_busting = $cache_busting;
$this->options = $options;
$this->server_info_duration = defined( 'ADVANCED_ADS_PRO_USER_COOKIE_MAX_AGE' ) ? absint( ADVANCED_ADS_PRO_USER_COOKIE_MAX_AGE ) : MONTH_IN_SECONDS;
$this->vc_cache_reset = ! empty( $this->options['vc_cache_reset'] ) ? absint( $this->options['vc_cache_reset'] ) : 0;
$this->is_ajax = ! empty( $cache_busting->is_ajax );
new Advanced_Ads_Pro_Cache_Busting_Visitor_Info_Cookie( $this );
}
/**
* Get ajax request that will be used in case required cookies do not exist.
*
* @param array $ads An array of Ad objects.
* @param array $args Ad arguments.
*
* @return void|array
*/
public function get_ajax_for_passive_placement( $ads, $args, $elementid ) {
if ( ! $this->server_info_duration ) {
return;
}
if ( ! is_array( $ads ) ) {
$ads = [ $ads ];
}
$server_c = [];
foreach ( $ads as $ad ) {
$ad_server_c = $this->get_server_conditions( $ad );
if ( $ad_server_c ) {
$server_c = array_merge( $server_c, $ad_server_c );
}
}
if ( ! $server_c ) { return; }
$query = Advanced_Ads_Pro_Module_Cache_Busting::build_js_query( $args);
return [
'ajax_query' => Advanced_Ads_Pro_Module_Cache_Busting::get_instance()->get_ajax_query( array_merge( $query, [
'elementid' => $elementid,
'server_conditions' => $server_c
] ) ),
'server_info_duration' => $this->server_info_duration,
'server_conditions' => $server_c,
];
}
/**
* Get server conditions of the ad.
*
* @param $ad Ad
* @return array
*/
private function get_server_conditions( Ad $ad ) {
$visitors = $ad->get_visitor_conditions();
$visitors = ! empty( $visitors ) && is_array( $visitors ) ? array_values( $visitors ) : [];
$result = [];
foreach ( $visitors as $k => $visitor ) {
if ( $info = $this->get_server_condition_info( $visitor ) ) {
$visitor_to_add = array_intersect_key( $visitor, [ 'type' => true, $info['hash_fields'] => true ] );
$result[ $info['hash'] ] = $visitor_to_add;
}
}
return $result;
}
/**
* Get info about the server condition.
*
* @param array $visitor Visitor condition.
* @return array|void info about server condition.
*/
public function get_server_condition_info( $visitor ) {
if ( ! isset( $visitor['type'] ) ) {
return;
}
$conditions = $this->get_all_server_conditions();
if ( ! isset( $conditions[ $visitor['type'] ]['passive_info']['function'] ) ) {
// It's not a server condition.
return;
}
$info = $conditions[ $visitor['type'] ]['passive_info'];
$hash = $visitor['type'];
// Add unique fields set on the Ad edit page.
// This allows us to to have several conditions of the same type.
if ( isset( $info['hash_fields'] ) && isset( $visitor[ $info['hash_fields'] ] ) ) {
$hash .= '_' . $visitor[ $info['hash_fields'] ];
}
// Allow the administrator to remove all cookies in the user's browsers.
$hash .= '_' . $this->vc_cache_reset;
$hash = substr( md5( $hash ), 0, 10 );
return [ 'hash' => $hash, 'function' => $info['function'], 'hash_fields' => $info['hash_fields'] ];
}
/**
* Get all server conditions.
*/
public function get_all_server_conditions() {
if ( ! $this->server_info_duration ) {
return [];
}
if ( ! did_action( 'init' ) ) {
// All conditions should be ready.
trigger_error( sprintf( '%1$s was called incorrectly', 'Advanced_Ads_Pro_Cache_Busting_Server_Info::get_all_server_conditions' ) );
}
$r = [];
foreach ( Advanced_Ads_Visitor_Conditions::get_instance()->conditions as $name => $condition ) {
if ( isset( $condition['passive_info'] ) ) {
$r[ $name ] = $condition;
}
}
return $r;
}
}
/**
* Cache Bust: Visitor info cookie
*/
class Advanced_Ads_Pro_Cache_Busting_Visitor_Info_Cookie {
// Note: hard-coded in JS.
const VISITOR_INFO_COOKIE_NAME = 'advanced_ads_visitor';
/**
* Holds the server info class.
*
* @var Advanced_Ads_Pro_Cache_Busting_Server_Info
*/
private $server_info;
public function __construct( $server_info ) {
$this->server_info = $server_info;
if ( ! $this->can_set_cookie() ) {
// Remove cookie.
if ( $this->parse_existing_cookies() ) {
$this->set_cookie( false );
}
return;
}
if ( $this->server_info->is_ajax ) {
add_action( 'init', [ $this, 'add_server_info' ], 50 );
}
if ( ! empty( $this->server_info->options['vc_cache_reset_actions']['login'] ) ) {
add_action( 'wp_logout', [ $this, 'log_in_out' ] );
add_action( 'set_auth_cookie', [ $this, 'log_in_out' ] );
}
}
/**
* Create cookies during AJAX requests.
*/
public function add_server_info() {
$request = Params::request( 'deferedAds', [], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if ( empty( $request ) ) {
return;
}
$e_cookie = $n_cookie = $this->parse_existing_cookies();
// Parse ajax request.
foreach ( $request as $query ) {
if ( ! isset( $query['ad_method'] ) || $query['ad_method'] !== 'placement' || empty( $query['server_conditions'] ) ) {
// The query does not have server conditions.
continue;
}
// Prepare new cookies to save.
$n_cookie = $this->prepare_new_cookies( $query['server_conditions'], $n_cookie );
}
$n_cookie['vc_cache_reset'] = $this->server_info->vc_cache_reset;
if ( $n_cookie !== $e_cookie ) {
$this->set_cookie( $n_cookie );
}
}
/**
* Get correct and not obsolete conditions.
*/
private function parse_existing_cookies() {
$n_cookie = [];
if ( Params::cookie( self::VISITOR_INFO_COOKIE_NAME ) ) {
$n_cookie['vc_cache_reset'] = $this->server_info->vc_cache_reset;
$e_cookie = Params::cookie( self::VISITOR_INFO_COOKIE_NAME );
$e_cookie = wp_unslash( $e_cookie );
$e_cookie = json_decode( $e_cookie, true );
if ( isset( $e_cookie['browser_width'] ) ) {
$n_cookie['browser_width'] = $e_cookie['browser_width'];
}
if ( isset( $e_cookie['vc_cache_reset'] ) && absint( $e_cookie['vc_cache_reset'] ) < $this->server_info->vc_cache_reset ) {
// The cookie has been reset on the Settings page.
return $n_cookie;
}
if ( empty( $e_cookie['conditions'] ) || ! is_array( $e_cookie['conditions'] ) ) {
return $n_cookie;
}
foreach ( $e_cookie['conditions'] as $cond_name => $hashes ) {
foreach ( (array) $hashes as $hash => $item ) {
// Do not add outdated conditions.
if ( isset( $item['time'] ) && ( absint( $item['time'] ) + $this->server_info->server_info_duration ) > time() ) {
$n_cookie['conditions'][ $cond_name ][ $hash ] = $item;
}
}
}
}
return $n_cookie;
}
/**
* Prepare new conditions to save.
*
* @param array $visitors New visitor conditions to add to cookie.
* @param array $n_cookie Existing visitor conditions from cookie.
*
* @return array $n_cookie New cookie.
*/
public function prepare_new_cookies( $visitors, $n_cookie = [] ) {
foreach ( (array) $visitors as $visitor ) {
$info = $this->server_info->get_server_condition_info( $visitor );
if ( ! $info ) { continue; }
if ( isset( $n_cookie['conditions'][ $visitor['type'] ][ $info['hash'] ] ) ) { continue; }
$n_cookie['conditions'][ $visitor['type'] ][ $info['hash'] ] = [
'data' => call_user_func( $info['function'], $visitor ),
'time' => time(),
];
}
return $n_cookie;
}
/**
* Check if the cookie can be set.
*/
public function can_set_cookie() {
return $this->server_info->server_info_duration;
}
/**
* Set cookie.
*
* @param array|bool $cookie Cookie.
*/
public function set_cookie( $cookie ) {
if ( ! $cookie ) {
setrawcookie( self::VISITOR_INFO_COOKIE_NAME, '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN );
return;
}
$cookie = json_encode( $cookie );
$cookie = rawurlencode( $cookie );
if ( strlen( $cookie ) > 4096 ) {
Advanced_Ads::log( 'The cookie size is too large' );
return;
}
// Prevent spaces from being converted to '+'
setrawcookie( self::VISITOR_INFO_COOKIE_NAME, $cookie, time() + $this->server_info->server_info_duration, COOKIEPATH, COOKIE_DOMAIN );
}
/**
* Remove server info on log in/out.
*/
public function log_in_out() {
$server_conditions = $this->server_info->get_all_server_conditions();
$n_cookie = $this->parse_existing_cookies();
if ( isset( $n_cookie['conditions'] ) ) {
foreach ( (array) $n_cookie['conditions'] as $cond_name => $cond ) {
if ( isset( $server_conditions[ $cond_name ]['passive_info']['remove'] )
&& $server_conditions[ $cond_name ]['passive_info']['remove'] === 'login' ) {
unset ( $n_cookie['conditions'][ $cond_name ] );
}
}
}
$this->set_cookie( $n_cookie );
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* Render CB settings.
*
* @package AdvancedAds\Pro
* @author Advanced Ads <info@wpadvancedads.com>
*/
$options = Advanced_Ads_Pro::get_instance()->get_options();
$module_enabled = ! empty( $options['cache-busting']['enabled'] );
$method = ( isset( $options['cache-busting']['default_auto_method'] ) && 'ajax' === $options['cache-busting']['default_auto_method'] ) ? 'ajax' : 'passive';
$fallback_method = ( isset( $options['cache-busting']['default_fallback_method'] ) && 'disable' === $options['cache-busting']['default_fallback_method'] ) ? 'disable' : 'ajax';
$passive_all = ! empty( $options['cache-busting']['passive_all'] );
$vc_cache_reset = ! empty( $options['cache-busting']['vc_cache_reset'] ) ? (int) $options['cache-busting']['vc_cache_reset'] : 0;
$vc_cache_reset_on_login = ! empty( $options['cache-busting']['vc_cache_reset_actions']['login'] );
?>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][enabled]" id="advanced-ads-pro-cache-busting-enabled" type="checkbox" value="1" <?php checked( $module_enabled ); ?> class="advads-has-sub-settings" />
<label for="advanced-ads-pro-cache-busting-enabled" class="description">
<?php esc_html_e( 'Activate module.', 'advanced-ads-pro' ); ?>
</label>
<a href="https://wpadvancedads.com/manual/cache-busting/?utm_source=advanced-ads&utm_medium=link&utm_campaign=pro-cb-manual'; ?>" target="_blank" class="advads-manual-link"><?php esc_html_e( 'Manual', 'advanced-ads-pro' ); ?></a>
<div class="advads-sub-settings">
<h4><?php esc_html_e( 'Default option', 'advanced-ads-pro' ); ?></h4>
<p class="description"><?php esc_html_e( 'Choose which method to use when a placement needs cache busting and the option is set to “auto”.', 'advanced-ads-pro' ); ?></p>
<label>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][default_auto_method]" type="radio" value="passive"
<?php
checked( $method, 'passive' );
?>
/><?php esc_html_e( 'passive', 'advanced-ads-pro' ); ?>
</label>
<label>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][default_auto_method]" type="radio" value="ajax"
<?php
checked( $method, 'ajax' );
?>
/><?php esc_html_e( 'AJAX', 'advanced-ads-pro' ); ?>
</label>
<p><label>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][passive_all]" type="checkbox" value="1"
<?php
checked( $passive_all, 1 );
?>
/><?php esc_html_e( 'Force passive cache busting', 'advanced-ads-pro' ); ?>
</label></p>
<p class="description">
<?php
esc_html_e( 'By default, cache busting only works through placements.', 'advanced-ads-pro' );
echo '&nbsp;';
esc_html_e( 'Enable passive cache busting for all ads and groups which are not delivered through a placement, if possible.', 'advanced-ads-pro' );
?>
</p>
<?php if ( method_exists( wp_get_theme(), 'is_block_theme' ) && wp_get_theme()->is_block_theme() ) : ?>
<div class="notice advads-notice inline" style="margin:5px 1px 7px">
<p>
<?php
printf(
// translators: 1 opening link tag. 2 closing tag.
esc_html__( 'This option does not work with the current active theme and %1$sblock themes%2$s in general.', 'advanced-ads-pro' ),
'<a href="https://wordpress.org/documentation/article/block-themes/" target="_blank">',
'</a>'
);
?>
</p>
</div>
<?php endif; ?>
<h4><?php esc_html_e( 'Fallback option', 'advanced-ads-pro' ); ?></h4>
<p class="description"><?php esc_html_e( 'Choose the fallback if “passive“ cache busting is not possible.', 'advanced-ads-pro' ); ?></p>
<label>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][default_fallback_method]" type="radio" value="ajax"
<?php
checked( $fallback_method, 'ajax' );
?>
/><?php esc_html_e( 'AJAX', 'advanced-ads-pro' ); ?>
</label>
<label>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][default_fallback_method]" type="radio" value="disable"
<?php
checked( $fallback_method, 'disable' );
?>
/><?php esc_html_e( 'off', 'advanced-ads-pro' ); ?>
</label>
<input id="advads-pro-vc-hash" name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][vc_cache_reset]" type="hidden" value="
<?php
echo esc_attr( $vc_cache_reset );
?>
" />
<h4><?php esc_html_e( 'Visitor profile', 'advanced-ads-pro' ); ?></h4>
<p class="description">
<?php
esc_html_e( 'Advanced Ads stores some user information in the users browser to limit the number of AJAX requests for cache busting. Manual', 'advanced-ads-pro' );
?>
<a href="https://wpadvancedads.com/manual/cache-busting/?utm_source=advanced-ads&utm_medium=link&utm_campaign=visitor-profile#Visitor_profile'; ?>" target="_blank" class="dashicons dashicons-external"></a>
</p>
<br/><button type="button" id="advads-pro-vc-hash-change" class="button-secondary"><?php esc_html_e( 'Update visitor profile', 'advanced-ads-pro' ); ?></button>
<p id="advads-pro-vc-hash-change-ok" class="advads-success-message" style="display:none;">
<?php esc_html_e( 'Updated', 'advanced-ads-pro' ); ?>, <?php esc_html_e( 'You might need to update the page cache if you are using one.', 'advanced-ads-pro' ); ?></span>
</p>
<p id="advads-pro-vc-hash-change-error" class="advads-notice-inline advads-error" style="display:none;"><?php esc_html_e( 'An error occurred', 'advanced-ads-pro' ); ?></p>
<input type="hidden" id="advads-pro-reset-vc-cache-nonce" value="<?php echo esc_attr( wp_create_nonce( 'advads-pro-reset-vc-cache-nonce' ) ); ?>" />
<p><label>
<input name="<?php echo esc_attr( Advanced_Ads_Pro::OPTION_KEY ); ?>[cache-busting][vc_cache_reset_actions][login]" type="checkbox" value="1" <?php checked( $vc_cache_reset_on_login, 1 ); ?> />
<?php esc_html_e( 'Update visitor profile when user logs in or out', 'advanced-ads-pro' ); ?>
</label></p>
</div>

View File

@@ -0,0 +1,34 @@
<?php //phpcs:ignoreFile
/**
* Setting check ad template
*
* @package AdvancedAds\Pro
* @author Advanced Ads <info@wpadvancedads.com>
* @since 2.26.0
*/
?>
<div id="advads-cache-busting-check-wrap">
<span id="advads-cache-busting-error-result" class="advads-notice-inline advads-error" style="display:none;">
<?php
printf(
/* translators: %s link to manual */
__( 'The code of this ad might not work properly with activated cache-busting. <a href="%s" target="_blank">Manual</a>', 'advanced-ads-pro' ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'https://wpadvancedads.com/manual/cache-busting/#advads-passive-compatibility-warning'
);
?>
</span>
<input type="hidden" id="advads-cache-busting-possibility" name="advanced_ad[cache-busting][possible]" value="true" />
</div>
<?php if ( ! $ad->is_type( 'adsense' ) ) : ?>
<script>
jQuery( document ).ready(function() {
if ( typeof advads_cb_check_ad_markup !== 'undefined' ){
var ad_content = <?php echo json_encode( $ad->prepare_output( $ad ) ); ?>;
advads_cb_check_ad_markup( ad_content );
}
});
</script>
<?php
endif;