Files
roi-theme/wp-content/plugins/advanced-ads/modules/privacy/classes/class-privacy.php
root a22573bf0b 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>
2025-11-03 21:04:30 -06:00

273 lines
6.5 KiB
PHP
Executable File

<?php // phpcs:ignore WordPress.Files.FileName
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Utilities\Conditional;
use AdvancedAds\Framework\Utilities\Str;
use AdvancedAds\Framework\Utilities\Params;
/**
* Handles Advanced Ads privacy settings.
*/
class Advanced_Ads_Privacy {
/**
* Singleton instance of the plugin
*
* @var self
*/
protected static $instance;
/**
* Module options
*
* @var null|array
*/
protected $options;
/**
* Option key
*
* @const string
*/
const OPTION_KEY = 'advanced-ads-privacy';
/**
* Initialize the module
*/
private function __construct() {
add_filter( 'advanced-ads-can-display-ad', [ $this, 'can_display_by_consent' ], 10, 3 );
$this->options();
if ( ! empty( $this->options['enabled'] ) ) {
add_filter( 'advanced-ads-activate-advanced-js', '__return_true' );
if ( 'iab_tcf_20' === $this->options['consent-method'] ) {
add_filter( 'advanced-ads-ad-output', [ $this, 'final_ad_output' ], 10, 2 );
}
}
}
/**
* If this ad is not image or dummy base64_encode the text.
*
* @param string $output The output string.
* @param Ad $ad Ad instance.
*
* @return string
*/
public function final_ad_output( $output, Ad $ad ) {
if (
Conditional::is_amp() ||
! $this->ad_type_needs_consent( $ad->get_type() ) ||
( ! $ad->is_type( 'adsense' ) && $ad->get_prop( 'privacy.ignore-consent' ) )
) {
return $output;
}
return $this->encode_ad( $output, $ad );
}
/**
* Encode the ad output.
*
* @param string $output The output string.
* @param Ad $ad Ad intance.
*
* @return string
*/
public function encode_ad( $output, Ad $ad ) {
$data_attributes = [
'id' => $ad->get_id(),
'bid' => get_current_blog_id(),
];
if ( $ad->is_parent_placement() ) {
$data_attributes['placement'] = $ad->get_parent()->get_id();
}
/**
* Filter the data attributes and allow removing/adding attributes.
* All attributes will be prefix with `data-` on output.
*
* @param array $data_attributes The default data attributes.
* @param Ad $ad Ad instance.
*/
$data_attributes = (array) apply_filters( 'advanced-ads-privacy-output-attributes', $data_attributes, $ad );
// Convert the data-attributes array into a string.
$attributes_string = '';
array_walk(
$data_attributes,
function ( $value, $key ) use ( &$attributes_string ) {
$attributes_string .= sprintf( ' data-%s="%s"', sanitize_key( $key ), esc_attr( $value ) );
}
);
return sprintf(
'<script type="text/plain" data-tcf="waiting-for-consent"%s>%s</script>',
$attributes_string,
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- we need to obfuscate the html (and maybe decode it in JS).
base64_encode( $output )
);
}
/**
* Check if the current ad output is encoded.
*
* @param string $output The ad output.
*
* @return bool
*/
public function is_ad_output_encoded( $output ) {
return (bool) strpos( $output, 'data-tcf="waiting-for-consent"' );
}
/**
* Return an instance of Advanced_Ads_Privacy
*
* @return self
*/
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;
}
/**
* Return module options
*
* @return array
*/
public function options() {
if ( ! isset( $this->options ) ) {
$this->options = get_option( self::OPTION_KEY, [] );
if ( isset( $this->options['enabled'] ) && empty( $this->options['consent-method'] ) ) {
$this->options['enabled'] = false;
}
}
return $this->options;
}
/**
* Check if ad can be displayed based on user's consent.
*
* @param bool $can_display Whether to display this ad.
* @param Ad $ad Ad instance.
* @param array $check_options Additional options passed to can_display.
*
* @return bool
*/
public function can_display_by_consent( $can_display, Ad $ad, $check_options ) {
// Early bail!!
if ( ! $can_display ) {
return $can_display;
}
// Passive cache busting enabled.
if ( $check_options['passive_cache_busting'] ) {
return true;
}
// privacy module not active, bail early.
if ( empty( $this->options['enabled'] ) ) {
return true;
}
// If consent is overriden for the ad.
if ( ! empty( $ad->get_prop( 'privacy.ignore-consent' ) ) ) {
return true;
}
$consent_method = $this->options['consent-method'] ?? '';
// If the consent method is set to cookie and the ad type does not need consent.
if ( 'custom' === $consent_method && ! $this->ad_type_needs_consent( $ad->get_type() ) ) {
return true;
}
// If method is iab_tcf_20, always set to true, JS needs to decide whether to display ad or not.
if ( 'iab_tcf_20' === $consent_method ) {
return true;
}
// Either personalized or non-personalized ad will be shown.
if ( $ad->is_type( 'adsense' ) && ! empty( $this->options()['show-non-personalized-adsense'] ) ) {
return true;
}
return $this->get_state() !== 'unknown';
}
/**
* Check whether this ad_type needs consent.
*
* @param string $type The ad type.
*
* @return bool
*/
public function ad_type_needs_consent( $type ) {
return ! in_array( $type, [ 'image', 'dummy', 'group' ], true );
}
/**
* Check if consent is not needed or was given by the user.
*
* @return string
* 'not_needed' - consent is not needed.
* 'accepted' - consent was given.
* 'unknown' - consent was not given yet.
*/
public function get_state() {
static $state;
if ( is_null( $state ) ) {
$state = $this->parse_state();
}
return $state;
}
/**
* Used by get_state() to parse the state of privacy/consent.
*
* @return string
* 'not_needed' - consent is not needed.
* 'accepted' - consent was given.
* 'unknown' - consent was not given yet.
*/
private function parse_state() {
if ( empty( $this->options['enabled'] ) || Conditional::is_amp() ) {
return 'not_needed';
}
$consent_method = $this->options['consent-method'] ?? '';
switch ( $consent_method ) {
case 'custom':
$name = $this->options['custom-cookie-name'];
if ( empty( $name ) ) {
return 'not_needed';
}
if ( ! Params::cookie( $name ) ) {
return 'unknown';
}
$value = $this->options['custom-cookie-value'] ?? '';
if (
( '' === $value && '' === Params::cookie( $name ) ) ||
Str::contains( $value, Params::cookie( $name ) )
) {
return 'accepted';
}
return 'unknown';
case 'iab_tcf_20':
default:
return 'unknown';
}
}
}