PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.29.0
Advanced Ads – Ad Manager & AdSense v1.29.0
2.0.26 2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / modules / privacy / classes / class-privacy.php
advanced-ads / modules / privacy / classes Last commit date
class-privacy.php 5 years ago
class-privacy.php
266 lines
1 <?php
2
3 /**
4 * Handles Advanced Ads privacy settings.
5 */
6 class Advanced_Ads_Privacy {
7 /**
8 * Singleton instance of the plugin
9 *
10 * @var self
11 */
12 protected static $instance;
13
14 /**
15 * Module options
16 *
17 * @var null|array
18 */
19 protected $options;
20
21 /**
22 * Option key
23 *
24 * @const string
25 */
26 const OPTION_KEY = 'advanced-ads-privacy';
27
28 /**
29 * Initialize the module
30 */
31 private function __construct() {
32 add_filter( 'advanced-ads-can-display', array( $this, 'can_display_by_consent' ), 10, 3 );
33
34 $this->options();
35
36 if ( ! empty( $this->options['enabled'] ) ) {
37 add_filter( 'advanced-ads-activate-advanced-js', '__return_true' );
38
39 if ( $this->options['consent-method'] === 'iab_tcf_20' ) {
40 add_filter( 'advanced-ads-output-final', array( $this, 'final_ad_output' ), 10, 2 );
41 }
42 }
43 }
44
45 /**
46 * If this ad is not image or dummy base64_encode the text.
47 *
48 * @param string $output The output string.
49 * @param Advanced_Ads_Ad $ad The ad object.
50 *
51 * @return string
52 */
53 public function final_ad_output( $output, Advanced_Ads_Ad $ad ) {
54 if (
55 advads_is_amp()
56 // Never encode image, dummy or group ads.
57 || ! $this->ad_type_needs_consent( $ad->type )
58 // Consent is overridden, and this is not an AdSense ad, don't encode it.
59 || ( $ad->type !== 'adsense' && isset( $ad->options()['privacy']['ignore-consent'] ) )
60 ) {
61 return $output;
62 }
63
64 return $this->encode_ad( $output, $ad );
65 }
66
67 /**
68 * Encode the ad output.
69 *
70 * @param string $output The output string.
71 * @param Advanced_Ads_Ad $ad The ad object.
72 *
73 * @return string
74 */
75 public function encode_ad( $output, Advanced_Ads_Ad $ad ) {
76 $data_attributes = array(
77 'id' => $ad->id,
78 'bid' => get_current_blog_id(),
79 );
80 if ( ! empty( $ad->output['placement_id'] ) ) {
81 $data_attributes['placement'] = $ad->output['placement_id'];
82 }
83
84 /**
85 * Filter the data attributes and allow removing/adding attributes.
86 * All attributes will be prefix with `data-` on output.
87 *
88 * @param array $data_attributes The default data attributes.
89 * @param Advanced_Ads_Ad $ad The current ad.
90 */
91 $data_attributes = (array) apply_filters( 'advanced-ads-privacy-output-attributes', $data_attributes, $ad );
92
93 // convert the data-attributes array into a string.
94 $attributes_string = '';
95 array_walk( $data_attributes, function( $value, $key ) use ( &$attributes_string ) {
96 $attributes_string .= sprintf( 'data-%s="%s"', sanitize_key( $key ), esc_attr( $value ) );
97 } );
98
99 return sprintf(
100 '<script type="text/plain" data-tcf="waiting-for-consent" %s>%s</script>',
101 $attributes_string,
102 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- we need to obfuscate the html (and maybe decode it in JS).
103 base64_encode( $output )
104 );
105 }
106
107 /**
108 * Check if the current ad output is encoded.
109 *
110 * @param string $output The ad output.
111 *
112 * @return bool
113 */
114 public function is_ad_output_encoded( $output ) {
115 return (bool) strpos( $output, 'data-tcf="waiting-for-consent"' );
116 }
117
118 /**
119 * Return an instance of Advanced_Ads_Privacy
120 *
121 * @return self
122 */
123 public static function get_instance() {
124 // If the single instance hasn't been set, set it now.
125 if ( null === self::$instance ) {
126 self::$instance = new self();
127 }
128
129 return self::$instance;
130 }
131
132 /**
133 * Return module options
134 *
135 * @return array
136 */
137 public function options() {
138 if ( ! isset( $this->options ) ) {
139 $this->options = get_option( self::OPTION_KEY, array() );
140 if ( isset( $this->options['enabled'] ) && empty( $this->options['consent-method'] ) ) {
141 $this->options['enabled'] = false;
142 }
143 }
144
145 return $this->options;
146 }
147
148 /**
149 * Check if ad can be displayed based on user's consent.
150 *
151 * @param bool $can_display Whether to display this ad.
152 * @param Advanced_Ads_Ad $ad The ad object.
153 * @param array $check_options Additional options passed to can_display.
154 *
155 * @return bool
156 */
157 public function can_display_by_consent( $can_display, Advanced_Ads_Ad $ad, $check_options ) {
158 // already false, honor this.
159 if ( ! $can_display ) {
160 return $can_display;
161 }
162
163 // passive cache busting enabled.
164 if ( $check_options['passive_cache_busting'] ) {
165 return true;
166 }
167
168 // privacy module not active, bail early.
169 if ( empty( $this->options['enabled'] ) ) {
170 return true;
171 }
172
173 // If consent is overriden for the ad.
174 if ( ! empty( $ad->options()['privacy']['ignore-consent'] ) ) {
175 return true;
176 }
177
178 $consent_method = isset( $this->options['consent-method'] ) ? $this->options['consent-method'] : '';
179
180 // If the consent method is set to cookie and the ad type does not need consent.
181 if ( $consent_method === 'custom' && ! $this->ad_type_needs_consent( $ad->type ) ) {
182 return true;
183 }
184
185 // If method is iab_tcf_20, always set to true, JS needs to decide whether to display ad or not.
186 if ( $consent_method === 'iab_tcf_20' ) {
187 return true;
188 }
189
190 // Either personalized or non-personalized ad will be shown.
191 if ( $ad->type === 'adsense' && ! empty( $this->options()['show-non-personalized-adsense'] ) ) {
192 return true;
193 }
194
195 return $this->get_state() !== 'unknown';
196 }
197
198 /**
199 * Check whether this ad_type needs consent.
200 *
201 * @param string $type The ad type.
202 *
203 * @return bool
204 */
205 public function ad_type_needs_consent( $type ) {
206 return ! in_array( $type, array( 'image', 'dummy', 'group' ), true );
207 }
208
209 /**
210 * Check if consent is not needed or was given by the user.
211 *
212 * @return string
213 * 'not_needed' - consent is not needed.
214 * 'accepted' - consent was given.
215 * 'unknown' - consent was not given yet.
216 */
217 public function get_state() {
218 static $state;
219 if ( is_null( $state ) ) {
220 $state = $this->parse_state();
221 }
222
223 return $state;
224 }
225
226 /**
227 * Used by get_state() to parse the state of privacy/consent.
228 *
229 * @return string
230 * 'not_needed' - consent is not needed.
231 * 'accepted' - consent was given.
232 * 'unknown' - consent was not given yet.
233 */
234 private function parse_state() {
235 if ( empty( $this->options['enabled'] ) || advads_is_amp() ) {
236 return 'not_needed';
237 }
238
239 $consent_method = isset( $this->options['consent-method'] ) ? $this->options['consent-method'] : '';
240 switch ( $consent_method ) {
241 case 'custom':
242 $name = $this->options['custom-cookie-name'];
243 if ( empty( $name ) ) {
244 return 'not_needed';
245 }
246
247 if ( ! isset( $_COOKIE[ $name ] ) ) {
248 return 'unknown';
249 }
250
251 $value = isset( $this->options['custom-cookie-value'] ) ? $this->options['custom-cookie-value'] : '';
252 if (
253 ( $value === '' && $_COOKIE[ $name ] === '' )
254 || ( $value !== '' && strpos( $_COOKIE[ $name ], $value ) !== false )
255 ) {
256 return 'accepted';
257 }
258
259 return 'unknown';
260 case 'iab_tcf_20':
261 default:
262 return 'unknown';
263 }
264 }
265 }
266