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,20 @@
.advads-option-placement-parallax-height {
clear: both;
overflow: hidden;
}
.advads-option-placement-parallax-height label {
float: left;
}
.advads-option-placement-parallax h4 {
margin-bottom: 0;
}
.advads-option-placement-parallax-enabled ~ div {
display: none;
}
.advads-option-placement-parallax-enabled:checked ~ div {
display: block;
}

View File

@@ -0,0 +1,7 @@
( () => {
for ( const unitSelect of document.getElementsByClassName( 'advads-option-placement-parallax-unit' ) ) {
unitSelect.addEventListener( 'change', event => {
event.target.closest( '.advads-option-placement-parallax-height' ).querySelector( 'input' ).max = event.target.value === 'vh' ? '100' : '';
} );
}
} )();

View File

@@ -0,0 +1,272 @@
/* eslint-disable camelcase */
/**
* Placement definition.
*
* @typedef ParallaxPlacement
* @type {Object.<string, Object>}
*
* @property {boolean} enabled - Whether the placement is enabled.
* @property {Object} height - Height of the parallax placement.
* @property {number} height.value - Height value.
* @property {string} height.unit - Height unit.
*/
/**
* Associative array with parallax options.
*
* @typedef ParallaxOptions
* @type {Object}
*
* @property {ParallaxPlacement[]} placements - Parallax placements.
*
* @property {Array} classes - Parallax classes.
* @property {string} classes.prefix - Current frontend prefix.
* @property {string} classes.container - Parallax container class prefix.
* @property {string} classes.clip - Parallax clip div class.
* @property {string} classes.inner - Parallax inner div class.
*/
(
() => {
// The current viewport height. Re-assign on window.resize event.
let viewportHeight;
// Object to save placement keys that have been initialized.
const initializedPlacements = {};
// Object to save initialized image instances.
const imageInstances = {};
// Test via a getter in the options object to see if the passive property is accessed
let supportsPassive = false;
try {
const opts = Object.defineProperty({}, 'passive', {
get: () => {
supportsPassive = { passive: true };
},
});
window.addEventListener('testPassive', null, opts);
window.removeEventListener('testPassive', null, opts);
} catch (e) {}
/** @type {ParallaxOptions} see type definition at top of file */
const options = window.advads_parallax_placement_options;
/**
* Set styles on the inner container when the parallax placement gets initialized and on window.resize.
*
* @param {Element} placementContainer
* @param {Element} placementInner
*/
const onLoad = (placementContainer, placementInner) => {
placementInner.style.maxWidth =
placementContainer.offsetWidth + 'px';
placementInner.style.visibility = 'visible';
viewportHeight = window.innerHeight;
};
/**
* Iterate all parallax placements. If a placement is found, call the passed callback.
*
* @param {Function} callback
* @param {ParallaxPlacement[]} placements
*/
const calculate = (callback, placements) => {
for (const placementsKey in placements) {
const placementContainer = document.getElementById(
options.classes.prefix +
options.classes.container +
placementsKey
);
if (placementContainer === null) {
continue;
}
const placementInner =
placementContainer.getElementsByClassName(
options.classes.prefix + options.classes.inner
)[0];
if (placementContainer && placementInner) {
initializedPlacements[placementsKey] = true;
callback(
placementContainer,
placementInner,
options.placements[placementsKey]
);
}
}
};
/**
* Fit the parallax image into the container.
*
* @param {Element} placementContainer
* @param {Element} placementInner
* @param {string} event
*/
const fitImage = (placementContainer, placementInner, event = '') => {
const imgElement = placementInner.querySelector('img');
if (!imageInstances[imgElement.src]) {
imageInstances[imgElement.src] = {
// eslint-disable-next-line no-undef
image: new Image(),
isLoaded: false,
};
}
const containerRect = placementContainer.getBoundingClientRect();
const resizeCallback = (img) => {
if (
img.naturalHeight / img.naturalWidth >
viewportHeight / placementContainer.clientWidth
) {
imgElement.style.objectFit = 'contain';
}
placementInner.style.left =
containerRect.width / 2 + containerRect.left + 'px';
if (
img.naturalHeight >= viewportHeight &&
img.naturalWidth <= placementContainer.clientWidth
) {
imgElement.style.height = '100vh';
placementInner.style.transform = 'translateX(-50%)';
return;
}
if (
placementInner.getBoundingClientRect().height <
containerRect.height
) {
placementInner.style.height = containerRect.height + 'px';
imgElement.style.objectFit = 'cover';
}
};
const scrollCallback = () => {
let offsetY;
if (
containerRect.bottom >= viewportHeight &&
containerRect.top <= viewportHeight
) {
offsetY =
viewportHeight -
placementInner.getBoundingClientRect().height;
} else if (containerRect.top <= 0 && containerRect.bottom > 0) {
offsetY = 0;
} else {
offsetY = (
((viewportHeight -
placementInner.getBoundingClientRect().height) /
(viewportHeight - containerRect.height)) *
containerRect.top
).toFixed(2);
}
placementInner.style.transform =
'translate3d(-50%,' + offsetY + 'px, 0)';
};
if (imageInstances[imgElement.src].isLoaded) {
if (event !== 'scroll') {
resizeCallback(imageInstances[imgElement.src].image);
}
scrollCallback();
return;
}
imageInstances[imgElement.src].image.addEventListener(
'load',
(e) => {
imageInstances[imgElement.src].isLoaded =
e.target.complete && e.target.naturalHeight !== 0;
resizeCallback(e.target);
scrollCallback();
}
);
imageInstances[imgElement.src].image.src = imgElement.src;
};
/**
* Initialize Placements.
* Use this on page load and as a callback for deferred injection.
*/
const initializePlacements = () => {
const placements = Object.assign({}, options.placements);
for (const placementsKey in initializedPlacements) {
delete placements[placementsKey];
}
if (!Object.keys(placements).length) {
return;
}
calculate((placementContainer, placementInner) => {
placementContainer.style.visibility = 'hidden';
onLoad(placementContainer, placementInner);
fitImage(placementContainer, placementInner);
placementContainer.style.visibility = 'visible';
}, placements);
};
// register event listeners and initialize existing parallax placements.
initializePlacements();
document.addEventListener(
'DOMContentLoaded',
initializePlacements,
supportsPassive
);
window.addEventListener(
'resize',
() =>
calculate((placementContainer, placementInner) => {
onLoad(placementContainer, placementInner);
fitImage(placementContainer, placementInner, 'resize');
}, options.placements),
supportsPassive
);
const fitImageOnScroll = () =>
calculate((placementContainer, placementInner) => {
fitImage(placementContainer, placementInner, 'scroll');
}, options.placements);
let ticking = false;
const onScroll = () => {
if (!ticking) {
window.requestAnimationFrame(() => {
fitImageOnScroll();
ticking = false;
});
ticking = true;
}
};
window.addEventListener('scroll', onScroll, supportsPassive);
window.addEventListener('touchmove', onScroll, supportsPassive);
// add cache-busting event listeners.
if (
typeof advanced_ads_pro !== 'undefined' &&
typeof advanced_ads_pro.observers !== 'undefined'
) {
advanced_ads_pro.observers.add((event) => {
if (
['inject_passive_ads', 'inject_ajax_ads'].indexOf(
event.event
) === -1 ||
(event.ad_ids && !Object.keys(event.ad_ids).length)
) {
return;
}
initializePlacements();
});
}
}
)();

View File

@@ -0,0 +1 @@
(()=>{let e;const t={},s={};let i=!1;try{const e=Object.defineProperty({},"passive",{get:()=>{i={passive:!0}}});window.addEventListener("testPassive",null,e),window.removeEventListener("testPassive",null,e)}catch(e){}const n=window.advads_parallax_placement_options,a=(t,s)=>{s.style.maxWidth=t.offsetWidth+"px",s.style.visibility="visible",e=window.innerHeight},d=(e,s)=>{for(const i in s){const s=document.getElementById(n.classes.prefix+n.classes.container+i);if(null===s)continue;const a=s.getElementsByClassName(n.classes.prefix+n.classes.inner)[0];s&&a&&(t[i]=!0,e(s,a,n.placements[i]))}},o=(t,i,n="")=>{const a=i.querySelector("img");s[a.src]||(s[a.src]={image:new Image,isLoaded:!1});const d=t.getBoundingClientRect(),o=s=>{if(s.naturalHeight/s.naturalWidth>e/t.clientWidth&&(a.style.objectFit="contain"),i.style.left=d.width/2+d.left+"px",s.naturalHeight>=e&&s.naturalWidth<=t.clientWidth)return a.style.height="100vh",void(i.style.transform="translateX(-50%)");i.getBoundingClientRect().height<d.height&&(i.style.height=d.height+"px",a.style.objectFit="cover")},l=()=>{let t;t=d.bottom>=e&&d.top<=e?e-i.getBoundingClientRect().height:d.top<=0&&d.bottom>0?0:((e-i.getBoundingClientRect().height)/(e-d.height)*d.top).toFixed(2),i.style.transform="translate3d(-50%,"+t+"px, 0)"};if(s[a.src].isLoaded)return"scroll"!==n&&o(s[a.src].image),void l();s[a.src].image.addEventListener("load",(e=>{s[a.src].isLoaded=e.target.complete&&0!==e.target.naturalHeight,o(e.target),l()})),s[a.src].image.src=a.src},l=()=>{const e=Object.assign({},n.placements);for(const s in t)delete e[s];Object.keys(e).length&&d(((e,t)=>{e.style.visibility="hidden",a(e,t),o(e,t),e.style.visibility="visible"}),e)};l(),document.addEventListener("DOMContentLoaded",l,i),window.addEventListener("resize",(()=>d(((e,t)=>{a(e,t),o(e,t,"resize")}),n.placements)),i);const r=()=>d(((e,t)=>{o(e,t,"scroll")}),n.placements);window.addEventListener("scroll",r,i),window.addEventListener("touchmove",r,i),"undefined"!=typeof advanced_ads_pro&&void 0!==advanced_ads_pro.observers&&advanced_ads_pro.observers.add((e=>{-1===["inject_passive_ads","inject_ajax_ads"].indexOf(e.event)||e.ad_ids&&!Object.keys(e.ad_ids).length||l()}))})();

View File

@@ -0,0 +1,134 @@
<?php //phpcs:ignoreFile
/**
* Parallax class.
*/
class Advanced_Ads_Pro_Module_Parallax {
/**
* Default values for options.
*
* @const array
*/
private const DEFAULT_VALUES = [
'enabled' => null,
'height' => [
'value' => 200,
'unit' => 'px',
],
];
/**
* Allow parallax ads on placement types.
* Filterable, and then cached in this property.
*
* @var string[]
*/
private $allowed_placement_types;
/**
* Constructor.
*/
public function __construct() {
add_action( 'init', [ $this, 'set_show_options_on_placement' ] );
add_action( 'init', [ $this, 'start_module' ], 30 );
}
public function start_module() {
if ( ! $this->enabled_placement_exists() ) {
return;
}
if ( is_admin() && ! wp_doing_ajax() ) {
new Advanced_Ads_Pro_Module_Parallax_Admin_UI( $this );
return;
}
new Advanced_Ads_Pro_Module_Parallax_Frontend( $this );
}
/**
* Add filter to set placement option for parallax
*
* @return void
*/
public function set_show_options_on_placement() {
foreach ( $this->get_allowed_placement_types() as $type_id ) {
add_filter( 'advanced-ads-placement-' . $type_id . '-options', [ $this, 'set_show_parallax_option' ] );
}
}
/**
* Add parallax options to allowed placements.
*
* @param array $options Array of placement options.
*
* @return array
*/
public function set_show_parallax_option( $options ): array {
$options['show_parallax'] = true;
return $options;
}
/**
* Iterate through all placements to see if there is one that can have the parallax effect.
* If found return as early as possible.
*
* @return bool
*/
public function enabled_placement_exists(): bool {
foreach ( wp_advads_get_placements() as $placement ) {
if ( $placement->is_type( $this->get_allowed_placement_types() ) ) {
return true;
}
}
return false;
}
/**
* Whether parallax is allowed on a specific placement type.
*
* @param string $placement_type The placement type to check against.
*
* @return bool
*/
public function allowed_on_placement( string $placement_type ): bool {
return in_array( $placement_type, $this->get_allowed_placement_types(), true );
}
/**
* Return the default values for the parallax option.
*
* @return array
*/
public function get_default_option_values(): array {
return self::DEFAULT_VALUES;
}
/**
* Get and filter the allowed placement types for the parallax option.
*
* @return array
*/
public function get_allowed_placement_types(): array {
if ( ! isset( $this->allowed_placement_types ) ) {
$allowed_placement_types = [
'post_content',
];
/**
* Filter the allowed placement types, to allow the parallax option there.
*
* @param string[] $allowed_placement_types Array of placement type identifiers.
*/
$this->allowed_placement_types = apply_filters( 'advanced-ads-pro-parallax-allowed-placement-types', $allowed_placement_types );
if ( ! is_array( $this->allowed_placement_types ) ) {
$this->allowed_placement_types = [];
}
}
return $this->allowed_placement_types;
}
}

View File

@@ -0,0 +1,75 @@
<?php // phpcs:ignore WordPress.Files.FileName
use AdvancedAds\Abstracts\Placement;
use AdvancedAds\Utilities\WordPress;
/**
* Admin UI for the parallax option.
*/
class Advanced_Ads_Pro_Module_Parallax_Admin_UI {
/**
* The injected parallax class.
*
* @var Advanced_Ads_Pro_Module_Parallax
*/
private $parallax;
/**
* Constructor.
*
* @param Advanced_Ads_Pro_Module_Parallax $parallax The injected parallax class.
*/
public function __construct( Advanced_Ads_Pro_Module_Parallax $parallax ) {
add_action( 'advanced-ads-placement-options-after-advanced', [ $this, 'render_option' ], 9, 2 );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
$this->parallax = $parallax;
}
/**
* Enqueue admin stylesheet.
*
* @return void
*/
public function enqueue_assets(): void {
wp_enqueue_style( 'advads-pro-parallax-admin-style', plugins_url( 'assets/css/admin-parallax-ads.css', __DIR__ ), [ 'advanced-ads-pro-admin-styles' ], AAP_VERSION );
wp_enqueue_script( 'advads-pro-parallax-admin-script', plugins_url( 'assets/js/admin-parallax-ads.js', __DIR__ ), [], AAP_VERSION, true );
}
/**
* Render parallax option in modal.
*
* @param string $placement_slug Placement ID.
* @param Placement $placement Placement array.
*/
public function render_option( string $placement_slug, $placement ): void {
if ( empty( $placement->get_type_object()->get_options()['show_parallax'] ) ) {
return;
}
// Options are not defined on a new placement.
$parallax_options = wp_parse_args(
$placement->get_prop( 'parallax' ) ?? [],
$this->parallax->get_default_option_values()
);
$option_prefix = 'advads[placements][options][parallax]';
$parallax_enabled = isset( $parallax_options['enabled'] );
$parallax_enabled_id = 'advads-option-placement-parallax-enabled-' . $placement_slug;
$height_value = $parallax_options['height']['value'];
$height_unit = $parallax_options['height']['unit'];
$height_units = [
'px' => 'px',
'vh' => '%',
];
ob_start();
require __DIR__ . '/../views/placement-options-after.php';
$option_content = ob_get_clean();
WordPress::render_option(
'placement-parallax',
__( 'Parallax Ads', 'advanced-ads-pro' ),
$option_content
);
}
}

View File

@@ -0,0 +1,385 @@
<?php // phpcs:ignoreFile
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Abstracts\Group;
use AdvancedAds\Framework\Utilities\Params;
/**
* Frontend output of the parallax option.
*/
class Advanced_Ads_Pro_Module_Parallax_Frontend {
/**
* The injected parallax class.
*
* @var Advanced_Ads_Pro_Module_Parallax
*/
private $parallax;
/**
* Check if we have already generated the style.
*
* @var bool
*/
private $style_generated = false;
/**
* Array that will be filled with placement options and passed to the frontend.
*
* @var array
*/
private $placements = [];
/**
* Handle for the frontend script.
*
* @const string
*/
private const SCRIPT_HANDLE = 'advads-parallax-script';
/**
* Name for the window object that holds localized data.
*
* @const string
*/
private const LOCALIZE_OBJECT_NAME = 'advads_parallax_placement_options';
/**
* Static storage to collect wrapped ads.
*
* @var array
*/
private static $wrapped_output = [];
/**
* @var string
*/
private $script_debug;
/**
* Constructor.
*
* @param Advanced_Ads_Pro_Module_Parallax $parallax The parallax class.
*/
public function __construct( Advanced_Ads_Pro_Module_Parallax $parallax ) {
$this->parallax = $parallax;
$this->script_debug = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
add_filter( 'advanced-ads-output-wrapper-options', [ $this, 'add_ad_wrapper' ], 10, 2 );
add_filter( 'advanced-ads-group-refresh-enabled', [ $this, 'disable_group_refresh' ], 10, 2 );
add_action( 'wp_footer', [ $this, 'output_placement_options' ] );
}
/**
* If the ad is in a parallax placement, add another wrapper.
*
* @param iterable $wrapper_options Array with the current wrapper options.
* @param Ad $ad The ad object to be rendered.
*
* @return iterable
*/
public function add_ad_wrapper( iterable $wrapper_options, Ad $ad ): iterable {
$placement = $ad->get_root_placement();
if (
! $placement ||
! ( $placement->get_prop( 'parallax.enabled' ) ) ||
! $this->parallax->allowed_on_placement( $placement->get_type() ) ||
! $this->ad_has_image( $ad )
) {
return $wrapper_options;
}
if ( empty( $wrapper_options['id'] ) ) {
$wrapper_options['id'] = wp_advads()->get_frontend_prefix() . wp_rand();
}
$id = $wrapper_options['id'];
// if we have already wrapped the ad, change the id. Otherwise, register it.
if ( array_key_exists( $ad->get_id(), self::$wrapped_output ) ) {
$id .= random_int( 1, 100 );
} else {
self::$wrapped_output[ $ad->get_id() ] = null;
}
$frontend_prefix = wp_advads()->get_frontend_prefix();
$wrapper_options['class'][] = $frontend_prefix . 'parallax-content';
$parallax_options = $placement->get_prop( 'parallax' );
$this->placements[ $id ] = $parallax_options;
$global_style = $this->generate_global_style();
$placement_style = $this->generate_placement_style( $id, $parallax_options );
$additional_output = '';
// this is a cache-busting AJAX call.
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- we're only comparing strings, no security implications.
if ( wp_doing_ajax() && Params::post( 'action' ) === 'advads_ad_select' ) {
$script_url = plugins_url( 'assets/js/parallax-ads' . $this->script_debug . '.js', __DIR__ );
$localized_object_name = self::LOCALIZE_OBJECT_NAME;
$localized_data = wp_json_encode( $this->get_localized_script_data() );
$additional_output = <<<A_CB_SCRIPT
<script>
(()=>{
window.{$localized_object_name} = window.{$localized_object_name} || {$localized_data};
if (document.getElementById('{$frontend_prefix}'+'parallax-acb-script') !== null) {
return;
}
const script = document.createElement('script');
script.id = '{$frontend_prefix}'+'parallax-acb-script';
script.src = '{$script_url}';
document.head.appendChild(script);
const style = document.createElement('style');
style.innerText = '{$global_style}';
document.head.appendChild(style);
})();
</script>
A_CB_SCRIPT;
} else {
if ( did_action( 'wp_enqueue_scripts' ) ) {
$this->enqueue_script();
} else {
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_script' ] );
}
if ( $global_style !== '' ) {
printf( '<style>%s</style>', esc_html( $global_style ) );
}
}
$additional_output .= sprintf( '<style>%s</style>', $placement_style );
$this->filter_output( $ad, $id, $additional_output );
return $wrapper_options;
}
/**
* Inline the parallax CSS. Generate from PHP to use the frontend prefix.
*
* @return string
*/
private function generate_global_style(): string {
if ( $this->style_generated ) {
return '';
}
$this->style_generated = true;
$frontend_prefix = wp_advads()->get_frontend_prefix();
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- frontend prefix is already escaped
return <<<CSS
.{$frontend_prefix}parallax-container {
position: relative;
}
.{$frontend_prefix}parallax-clip {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
clip-path: inset(0);
clip: rect(auto, auto, auto, auto);
overflow: hidden;
}
.{$frontend_prefix}parallax-inner {
position: fixed;
visibility: hidden;
width: 100%;
display: flex;
justify-content: center;
will-change: transform;
left: 50%;
transform: translateX(-50%);
}
.{$frontend_prefix}parallax-content {
height: 100%;
overflow: hidden;
}
.{$frontend_prefix}parallax-content * {
height: 100%;
}
.{$frontend_prefix}parallax-content img,
.{$frontend_prefix}parallax-content iframe,
.{$frontend_prefix}parallax-content video,
.{$frontend_prefix}parallax-content embed
{
object-fit: cover;
object-position: center;
max-width: 100%;
height: auto;
}
CSS;
}
/**
* Return placement-specific CSS string.
*
* @param string $id Generated ID for the ad.
* @param iterable $parallax_options Array of placement options.
*
* @return string
*/
private function generate_placement_style( string $id, iterable $parallax_options ): string {
$frontend_prefix = wp_advads()->get_frontend_prefix();
$parallax_container_id = $frontend_prefix . 'parallax-container-' . $id;
$css_selectors = [
'container' => '#' . $parallax_container_id,
'inner' => sprintf( '#%s .%sparallax-inner', $parallax_container_id, $frontend_prefix ),
'content' => '#' . $id,
];
$css_directives = [
'container' => [
'height' => $parallax_options['height']['value'] . $parallax_options['height']['unit'],
],
'inner' => [
'top' => 0,
],
'content' => [],
];
$css_string = '';
foreach ( $css_directives as $key => $directives ) {
if ( ! array_key_exists( $key, $css_selectors ) || empty( $directives ) ) {
continue;
}
$directives_string = '';
foreach ( $directives as $directive => $value ) {
$directives_string .= "$directive:$value;";
}
$css_string .= sprintf( '%s {%s}', $css_selectors[ $key ], $directives_string );
}
return $css_string;
}
/**
* Enqueue the frontend JavaScript.
*
* @return void
*/
public function enqueue_script(): void {
if ( wp_script_is( self::SCRIPT_HANDLE ) ) {
return;
}
$dependencies = [];
if ( wp_script_is( 'advanced-ads-pro/cache_busting' ) ) {
$dependencies[] = 'advanced-ads-pro/cache_busting';
}
wp_enqueue_script( self::SCRIPT_HANDLE, plugins_url( 'assets/js/parallax-ads' . $this->script_debug . '.js', __DIR__ ), $dependencies, AAP_VERSION, true );
}
/**
* Output the collected placement options to pass to JS.
*
* @return void
*/
public function output_placement_options(): void {
if ( wp_script_is( self::SCRIPT_HANDLE ) ) {
wp_localize_script( self::SCRIPT_HANDLE, self::LOCALIZE_OBJECT_NAME, $this->get_localized_script_data() );
}
}
/**
* Filter the ad output by adding parallax-specific wrappers.
*
* @param Ad $ad The ad object passed from the placement.
* @param string $wrapper_id The ID for this placement wrapper.
* @param string $additional_output String (script/style) to add after placement.
*
* @return void
*/
private function filter_output( Ad $ad, string $wrapper_id, string $additional_output ): void {
$additional_output = preg_replace( '/\s+/', ' ', $additional_output );
/**
* Add a wrapper for the parallax effect around the existing ad wrapper.
*
* @param string $output The current ad output string.
* @param Ad $inner_ad The ad object to compare against the ad from the placement.
*
* @return string
*/
add_filter( 'advanced-ads-ad-output', function( $output, Ad $inner_ad ) use ( $ad, $additional_output, $wrapper_id ) {
if ( $ad->get_id() !== $inner_ad->get_id() || ! in_array( $inner_ad->get_root_placement()->get_type(), $this->parallax->get_allowed_placement_types(), true ) ) {
return $output;
}
// save the raw output, to re-use it, if the same ad is added in two different parallax placements.
if ( self::$wrapped_output[ $ad->get_id() ] === null ) {
self::$wrapped_output[ $ad->get_id() ] = $output;
}
$output = self::$wrapped_output[ $ad->get_id() ];
$frontend_prefix = wp_advads()->get_frontend_prefix();
return <<<OUTPUT
<div class="{$frontend_prefix}parallax-container" id="{$frontend_prefix}parallax-container-{$wrapper_id}">
<div class="{$frontend_prefix}parallax-clip">
<div class="{$frontend_prefix}parallax-inner">
$output
</div>
</div>
</div>
{$additional_output}
OUTPUT;
}, 10, 2 );
}
/**
* Get the data for localizing a script. Either via `wp_localize_script` or in the AJAX call.
*
* @return array
*/
private function get_localized_script_data(): array {
return [
'classes' => [
'prefix' => wp_advads()->get_frontend_prefix(),
'container' => 'parallax-container-',
'clip' => 'parallax-clip',
'inner' => 'parallax-inner',
],
'placements' => $this->placements,
];
}
/**
* Whether the current ad has an image in its content.
* This should also match valid <picture> tags, since they include on `<img>` tag, cf. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
*
*
* @param Ad $ad The current ad object.
*
* @return bool
*/
private function ad_has_image( Ad $ad ): bool {
if ( $ad->is_type( 'image' ) ) {
return true;
}
// Match an opening "<img" tag followed by exactly one whitespace character and see if there is a "src" attribute before the closing ">"
return (bool) preg_match( '/<img\s[^>]+?src=/i', $ad->get_content() );
}
/**
* Disable the group refresh if parallax is enabled.
*
* @param bool $enabled Whether the group refresh is enabled.
* @param Group $group Group instance.
*
* @return bool
*/
public function disable_group_refresh( bool $enabled, Group $group ): bool {
if ( ! $enabled || ! ( $group->is_parent_placement() && $group->get_prop( 'parallax.enabled' ) ) ) {
return $enabled;
}
return false;
}
}

View File

@@ -0,0 +1,3 @@
<?php
( new Advanced_Ads_Pro_Module_Parallax() );

View File

@@ -0,0 +1,52 @@
<?php
/**
* Render the options on the placement
*
* @var string $option_prefix
* @var string $parallax_enabled_id
* @var bool $parallax_enabled
* @var string $placement_slug
* @var float $height_value
* @var string $height_unit
* @var string[] $height_units
* @var int $offset
*/
?>
<input type="checkbox" name="<?php echo esc_attr( $option_prefix ); ?>[enabled]" <?php checked( $parallax_enabled ); ?> id="<?php echo esc_attr( $parallax_enabled_id ); ?>" class="advads-option-placement-parallax-enabled">
<label for="<?php echo esc_attr( $parallax_enabled_id ); ?>">
<?php esc_html_e( 'Enable the parallax effect.', 'advanced-ads-pro' ); ?>
<span> </span>
<?php
/* translators: Link to parallax manual */
printf( esc_html__( 'Optimized for image ads. %s', 'advanced-ads-pro' ), '<a href="https://wpadvancedads.com/parallax-ads/?utm_source=advanced-ads&utm_medium=link&utm_campaign=pro-parallax-manual" target="_blank" class="advads-manual-link">' . esc_html__( 'Manual', 'advanced-ads-pro' ) . '</a>' );
?>
</label>
<br>
<div class="advads-option-placement-parallax-height">
<label>
<?php echo esc_html_x( 'Height', 'Parallax Ad placement height', 'advanced-ads-pro' ); ?>
<br>
<input type="number" min="1" max="<?php echo esc_attr( $height_unit === 'vh' ? 100 : '' ); ?>" step="any" name="<?php echo esc_attr( $option_prefix ); ?>[height][value]" value="<?php echo (float) $height_value; ?>">
</label>
<label>
<?php echo esc_html_x( 'Unit', 'Parallax Ad placement height unit', 'advanced-ads-pro' ); ?>
<span class="advads-help">
<span class="advads-tooltip">
<?php esc_html_e( 'Choose the height of the cutout, either in pixels or relative to the viewport.', 'advanced-ads-pro' ); ?>
</span>
</span>
<br>
<select name="<?php echo esc_attr( $option_prefix ); ?>[height][unit]" class="advads-option-placement-parallax-unit">
<?php foreach ( $height_units as $value => $option ) : ?>
<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, $height_unit ); ?>>
<?php echo esc_html( $option ); ?>
</option>
<?php endforeach; ?>
</select>
</label>
</div>