Advanced Ads - Version 1.9

Version Description

  • added Privacy module to hide ads until consent is given, see new Privacy settings
Download this release

Release Info

Developer webzunft
Plugin Icon 128x128 Advanced Ads
Version 1.9
Comparing to
See all releases

Code changes from version 1.8.30 to 1.9

advanced-ads.php CHANGED
@@ -12,7 +12,7 @@
12
  * Plugin Name: Advanced Ads
13
  * Plugin URI: https://wpadvancedads.com
14
  * Description: Manage and optimize your ads in WordPress
15
- * Version: 1.8.30
16
  * Author: Thomas Maier
17
  * Author URI: https://wpadvancedads.com
18
  * Text Domain: advanced-ads
@@ -39,7 +39,7 @@ define( 'ADVADS_BASE_DIR', dirname( ADVADS_BASE ) ); // directory of the plugin
39
  // general and global slug, e.g. to store options in WP
40
  define( 'ADVADS_SLUG', 'advanced-ads' );
41
  define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
42
- define( 'ADVADS_VERSION', '1.8.30' );
43
 
44
  /*----------------------------------------------------------------------------*
45
  * Autoloading, modules and functions
12
  * Plugin Name: Advanced Ads
13
  * Plugin URI: https://wpadvancedads.com
14
  * Description: Manage and optimize your ads in WordPress
15
+ * Version: 1.9
16
  * Author: Thomas Maier
17
  * Author URI: https://wpadvancedads.com
18
  * Text Domain: advanced-ads
39
  // general and global slug, e.g. to store options in WP
40
  define( 'ADVADS_SLUG', 'advanced-ads' );
41
  define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
42
+ define( 'ADVADS_VERSION', '1.9' );
43
 
44
  /*----------------------------------------------------------------------------*
45
  * Autoloading, modules and functions
classes/frontend_checks.php CHANGED
@@ -271,6 +271,21 @@ class Advanced_Ads_Frontend_Checks {
271
  ) );
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  $nodes[] = array( 'type' => 3, 'data' => array(
275
  'parent' => 'advanced_ads_ad_health',
276
  'id' => 'advanced_ads_ad_health_debug_dfp',
@@ -501,6 +516,21 @@ class Advanced_Ads_Frontend_Checks {
501
  }
502
 
503
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  <?php endif; ?>
505
  })(document, window);
506
  </script>
271
  ) );
272
  }
273
 
274
+ // warn if consent was not given
275
+ $privacy_state = Advanced_Ads_Privacy::get_instance()->get_state();
276
+ if( 'not_needed' !== $privacy_state ) {
277
+ $nodes[] = array( 'type' => 2, 'data' => array(
278
+ 'parent' => 'advanced_ads_ad_health',
279
+ 'id' => 'advanced_ads_ad_health_consent_missing',
280
+ 'title' => __( 'Consent not given', 'advanced-ads' ),
281
+ 'href' => admin_url( 'admin.php?page=advanced-ads-settings#top#privacy' ),
282
+ 'meta' => array(
283
+ 'class' => 'hidden advanced_ads_ad_health_warning advanced_ads_ad_health_consent_missing',
284
+ 'target' => '_blank'
285
+ )
286
+ ) );
287
+ }
288
+
289
  $nodes[] = array( 'type' => 3, 'data' => array(
290
  'parent' => 'advanced_ads_ad_health',
291
  'id' => 'advanced_ads_ad_health_debug_dfp',
516
  }
517
 
518
  }
519
+ <?php endif;
520
+ /**
521
+ * code to check if current user gave consent to show ads
522
+ */
523
+ $privacy_state = Advanced_Ads_Privacy::get_instance()->get_state();
524
+ if( 'not_needed' !== $privacy_state ) :
525
+ ?>advanced_ads_ready( function() {
526
+ var state = ( advads.privacy ) ? advads.privacy.get_state() : "";
527
+ var advads_consent_link = document.querySelector( '#wp-admin-bar-advanced_ads_ad_health_consent_missing.hidden' );
528
+ if ( 'unknown' === state && advads_consent_link ) {
529
+ advads_consent_link.className = advads_consent_link.className.replace( 'hidden', '' );
530
+ }
531
+
532
+ advanced_ads_frontend_checks.showCount();
533
+ });
534
  <?php endif; ?>
535
  })(document, window);
536
  </script>
classes/plugin.php CHANGED
@@ -175,8 +175,17 @@ class Advanced_Ads_Plugin {
175
  advanced_ads_ready=function(){var fns=[],listener,doc=typeof document==="object"&&document,hack=doc&&doc.documentElement.doScroll,domContentLoaded="DOMContentLoaded",loaded=doc&&(hack?/^loaded|^c/:/^loaded|^i|^c/).test(doc.readyState);if(!loaded&&doc){listener=function(){doc.removeEventListener(domContentLoaded,listener);window.removeEventListener("load",listener);loaded=1;while(listener=fns.shift())listener()};doc.addEventListener(domContentLoaded,listener);window.addEventListener("load",listener)}return function(fn){loaded?setTimeout(fn,0):fns.push(fn)}}();
176
  <?php
177
  }
 
 
 
 
 
 
 
178
  ?></script><?php
179
  echo Advanced_Ads_Utils::get_inline_asset( ob_get_clean() );
 
 
180
  }
181
 
182
  public function widget_init() {
175
  advanced_ads_ready=function(){var fns=[],listener,doc=typeof document==="object"&&document,hack=doc&&doc.documentElement.doScroll,domContentLoaded="DOMContentLoaded",loaded=doc&&(hack?/^loaded|^c/:/^loaded|^i|^c/).test(doc.readyState);if(!loaded&&doc){listener=function(){doc.removeEventListener(domContentLoaded,listener);window.removeEventListener("load",listener);loaded=1;while(listener=fns.shift())listener()};doc.addEventListener(domContentLoaded,listener);window.addEventListener("load",listener)}return function(fn){loaded?setTimeout(fn,0):fns.push(fn)}}();
176
  <?php
177
  }
178
+
179
+ // Output privacy options.
180
+ $privacy_options = Advanced_Ads_Privacy::get_instance()->options();
181
+ if ( ! empty( $privacy_options['enabled'] ) ) {
182
+ printf( '(advads_options = window.advads_options || {} )["privacy"] = %s;', json_encode( $privacy_options ) );
183
+ }
184
+
185
  ?></script><?php
186
  echo Advanced_Ads_Utils::get_inline_asset( ob_get_clean() );
187
+
188
+
189
  }
190
 
191
  public function widget_init() {
modules/gadsense/admin/admin.php CHANGED
@@ -143,15 +143,6 @@ class Advanced_Ads_AdSense_Admin {
143
  'advanced_ads_adsense_setting_section'
144
  );
145
 
146
- // add setting field for adsense limit
147
- add_settings_field(
148
- 'adsense-limit',
149
- __( 'Limit to 3 ads', 'advanced-ads' ),
150
- array($this, 'render_settings_adsense_limit'),
151
- $hook,
152
- 'advanced_ads_adsense_setting_section'
153
- );
154
-
155
  // activate AdSense verification code and Auto ads (previously Page-Level ads)
156
  add_settings_field(
157
  'adsense-page-level',
@@ -161,6 +152,15 @@ class Advanced_Ads_AdSense_Admin {
161
  'advanced_ads_adsense_setting_section'
162
  );
163
 
 
 
 
 
 
 
 
 
 
164
  // disable AdSense violation warnings
165
  add_settings_field(
166
  'adsense-warnings-disable',
143
  'advanced_ads_adsense_setting_section'
144
  );
145
 
 
 
 
 
 
 
 
 
 
146
  // activate AdSense verification code and Auto ads (previously Page-Level ads)
147
  add_settings_field(
148
  'adsense-page-level',
152
  'advanced_ads_adsense_setting_section'
153
  );
154
 
155
+ // add setting field for adsense limit
156
+ add_settings_field(
157
+ 'adsense-limit',
158
+ __( 'Limit to 3 ads', 'advanced-ads' ),
159
+ array($this, 'render_settings_adsense_limit'),
160
+ $hook,
161
+ 'advanced_ads_adsense_setting_section'
162
+ );
163
+
164
  // disable AdSense violation warnings
165
  add_settings_field(
166
  'adsense-warnings-disable',
modules/gadsense/public/public.php CHANGED
@@ -28,6 +28,29 @@ class Advanced_Ads_AdSense_Public {
28
  if ( ! empty( $options['background'] ) ) {
29
  echo '<style>ins.adsbygoogle { background-color: transparent; }</style>';
30
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  /**
32
  * inject page-level header code
33
  *
28
  if ( ! empty( $options['background'] ) ) {
29
  echo '<style>ins.adsbygoogle { background-color: transparent; }</style>';
30
  }
31
+
32
+ $privacy_options = Advanced_Ads_Privacy::get_instance()->options();
33
+ $privacy_enabled = ! empty( $privacy_options['enabled'] ) && 'not_needed' !== Advanced_Ads_Privacy::get_instance()->get_state();
34
+ $npa_enabled = ! empty( $privacy_options['show-non-personalized-adsense'] );
35
+
36
+ // Show non-personalized Adsense ads if consent was not given.
37
+ // If non-personalized ads are enabled.
38
+ if ( $privacy_enabled && $npa_enabled ) {
39
+ echo '<script>';
40
+ // If the page is not from a cache.
41
+ if ( Advanced_Ads_Privacy::get_instance()->get_state() === 'unknown' ) {
42
+ echo '(adsbygoogle=window.adsbygoogle||[]).requestNonPersonalizedAds=1;';
43
+ }
44
+
45
+ // If the page is from a cache.
46
+ // Wait until 'advads.privacy' is available. Execute before cache-busting.
47
+ echo '( window.advanced_ads_ready || jQuery( document ).ready ).call( null, function() {
48
+ var state = ( advads.privacy ) ? advads.privacy.get_state() : "";
49
+ var use_npa = ( state === "unknown" ) ? 1 : 0;
50
+ (adsbygoogle=window.adsbygoogle||[]).requestNonPersonalizedAds=use_npa;
51
+ } )</script>';
52
+ }
53
+
54
  /**
55
  * inject page-level header code
56
  *
modules/gadsense/public/templates/page-level.php CHANGED
@@ -1,7 +1,30 @@
 
1
  <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
2
  <script>
3
  (adsbygoogle = window.adsbygoogle || []).push({
4
  google_ad_client: "<?php echo $client_id; ?>",
5
  enable_page_level_ads: true
6
  });
7
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! $privacy_enabled ) : ?>
2
  <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
3
  <script>
4
  (adsbygoogle = window.adsbygoogle || []).push({
5
  google_ad_client: "<?php echo $client_id; ?>",
6
  enable_page_level_ads: true
7
  });
8
+ </script>
9
+ <?php else: ?>
10
+ <script>
11
+ // Wait until 'advads.privacy' is available.
12
+ ( window.advanced_ads_ready || jQuery( document ).ready ).call( null, function() {
13
+ var npa_enabled = <?php echo $npa_enabled ? 1 : 0; ?>;
14
+ if ( npa_enabled
15
+ || ( advads.privacy && advads.privacy.get_state() !== 'unknown' )
16
+ ) {
17
+ var script = document.createElement( 'script' );
18
+ script.async=1;
19
+ script.src='//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
20
+ var first = document.getElementsByTagName( 'script' )[0];
21
+ first.parentNode.insertBefore( script, first );
22
+
23
+ (adsbygoogle = window.adsbygoogle || []).push({
24
+ google_ad_client: "<?php echo $client_id; ?>",
25
+ enable_page_level_ads: true
26
+ });
27
+ }
28
+ } );
29
+ </script>
30
+ <?php endif ?>
modules/privacy/admin/admin.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Advanced_Ads_Privacy_Admin
4
+ {
5
+ /**
6
+ * Singleton instance of the plugin
7
+ *
8
+ * @var Advanced_Ads_Privacy_Admin
9
+ */
10
+ protected static $instance;
11
+
12
+ /**
13
+ * module options
14
+ *
15
+ * @var array (if loaded)
16
+ */
17
+ protected $options;
18
+
19
+ /**
20
+ * Initialize the module
21
+ *
22
+ */
23
+ private function __construct() {
24
+
25
+ // add module settings to Advanced Ads settings page
26
+ add_action( 'advanced-ads-settings-init', array( $this, 'settings_init' ), 20, 1 );
27
+ add_filter('advanced-ads-setting-tabs', array($this, 'setting_tabs'), 20 );
28
+
29
+ // additional ad options
30
+ add_action('advanced-ads-ad-params-after', array($this, 'render_ad_options'), 20, 2);
31
+ add_filter( 'advanced-ads-save-options', array( $this, 'save_ad_options' ), 10, 2 );
32
+ }
33
+
34
+ /**
35
+ * Return an instance of Advanced_Ads_Privacy_Admin
36
+ *
37
+ * @return Advanced_Ads_Privacy_Admin
38
+ */
39
+ public static function get_instance() {
40
+ // If the single instance hasn't been set, set it now.
41
+ if (null === self::$instance)
42
+ {
43
+ self::$instance = new self;
44
+ }
45
+
46
+ return self::$instance;
47
+ }
48
+
49
+ /**
50
+ * add tracking settings tab
51
+ *
52
+ * @since 1.8.30
53
+ * @param arr $tabs existing setting tabs
54
+ * @return arr $tabs setting tabs with AdSense tab attached
55
+ */
56
+ public function setting_tabs(array $tabs) {
57
+
58
+ $tabs['privacy'] = array(
59
+ // TODO abstract string
60
+ 'page' => ADVADS_PRIVACY_SLUG . '-settings',
61
+ 'group' => ADVADS_PRIVACY_SLUG,
62
+ 'tabid' => 'privacy',
63
+ 'title' => __( 'Privacy', 'advanced-ads' )
64
+ );
65
+
66
+ return $tabs;
67
+ }
68
+
69
+ /**
70
+ * add settings to settings page
71
+ *
72
+ * @param string $hook settings page hook
73
+ */
74
+ public function settings_init($hook) {
75
+
76
+ register_setting( ADVADS_PRIVACY_SLUG, Advanced_Ads_Privacy::OPTION_KEY );
77
+
78
+ // add new section
79
+ add_settings_section(
80
+ ADVADS_PRIVACY_SLUG . '_settings_section', '', array($this, 'render_settings_section'), ADVADS_PRIVACY_SLUG . '-settings'
81
+ );
82
+
83
+ add_settings_field(
84
+ 'enable-privacy-module', __('Enable Privacy module', 'advanced-ads'), array($this, 'render_settings_enable_module'), ADVADS_PRIVACY_SLUG . '-settings', ADVADS_PRIVACY_SLUG . '_settings_section'
85
+ );
86
+ add_settings_field(
87
+ 'consent-method', __('Consent method', 'advanced-ads'), array($this, 'render_settings_consent_method'), ADVADS_PRIVACY_SLUG . '-settings', ADVADS_PRIVACY_SLUG . '_settings_section'
88
+ );
89
+ }
90
+
91
+
92
+ /**
93
+ * render settings section
94
+ */
95
+ public function render_settings_section() {
96
+
97
+ }
98
+
99
+ /**
100
+ * Render enable module setting
101
+ */
102
+ public function render_settings_enable_module() {
103
+ $options = Advanced_Ads_Privacy::get_instance()->options();
104
+ $module_enabled = isset( $options['enabled']) ? $options['enabled'] : false;
105
+ require ADVADS_BASE_PATH . 'modules/privacy/admin/views/setting-enable.php';
106
+ }
107
+
108
+ /**
109
+ * Render setting to choose the cookie method to hide ads
110
+ */
111
+ public function render_settings_consent_method() {
112
+ $options = Advanced_Ads_Privacy::get_instance()->options();
113
+ $methods = Advanced_Ads_Privacy::get_instance()->get_consent_methods();
114
+ $current_method = isset( $options['consent-method']) ? $options['consent-method'] : '0';
115
+ $custom_cookie_name = isset( $options['custom-cookie-name'] ) ? $options['custom-cookie-name'] : '';
116
+ $custom_cookie_value = isset( $options['custom-cookie-value'] ) ? $options['custom-cookie-value'] : '';
117
+ $show_non_personalized_adsense = isset( $options['show-non-personalized-adsense']) ? 1 : false;
118
+ require ADVADS_BASE_PATH . 'modules/privacy/admin/views/setting-consent-method.php';
119
+ }
120
+
121
+ /**
122
+ * add options to ad edit page
123
+ *
124
+ * @param obj $ad ad object
125
+ * @param arr $types ad types
126
+ */
127
+ public function render_ad_options( $ad, $types ) {
128
+
129
+ if (!isset($ad->id) || empty($ad->id)) {
130
+ return;
131
+ }
132
+
133
+ $ad = new Advanced_Ads_Ad($ad->id);
134
+ $ad_options = $ad->options();
135
+ $ad_privacy_options = isset( $ad_options['privacy'] ) ? $ad_options['privacy'] : array();
136
+ $ignore_consent = isset( $ad_privacy_options['ignore-consent']) ? true : false;
137
+
138
+ $privacy_options = Advanced_Ads_Privacy::get_instance()->options();
139
+ $module_enabled = ! empty( $privacy_options['enabled'] );
140
+
141
+ // If the module is not enabled and the option wasn't checked before.
142
+ if ( ! $module_enabled && ! $ignore_consent ) {
143
+ return;
144
+ }
145
+
146
+ include ADVADS_BASE_PATH . 'modules/privacy/admin/views/setting-ad-ignore-consent.php';
147
+
148
+ }
149
+
150
+ /**
151
+ * Save ad options.
152
+ *
153
+ * @param arr $options
154
+ * @param obj $ad Advanced_Ads_Ad
155
+ * @return arr $options
156
+ */
157
+ public function save_ad_options( $options = array(), Advanced_Ads_Ad $ad ) {
158
+ if ( isset( $_POST['advanced_ad']['privacy'] ) ) {
159
+ $options['privacy'] = $_POST['advanced_ad']['privacy'];
160
+ } else {
161
+ unset( $options['privacy'] );
162
+ }
163
+
164
+ return $options;
165
+ }
166
+
167
+ }
modules/privacy/admin/views/setting-ad-ignore-consent.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <div class="advads-option-list">
2
+ <span class="label"><?php _e( 'privacy', 'advanced-ads' ); ?></span>
3
+ <div id="advanced-ads-ad-parameters-privacy">
4
+ <label>
5
+ <input name="advanced_ad[privacy][ignore-consent]" type="checkbox" value="1" <?php checked( $ignore_consent, true ); ?>/>
6
+ <?php printf( __( 'Ignore <a href="%s">general Privacy settings</a> and display the ad even without consent.', 'advanced-ads' ), esc_url( admin_url( 'admin.php?page=advanced-ads-settings#top#privacy' ) ) ); ?>
7
+ </label>
8
+ </div>
9
+ </div>
10
+ <hr/>
modules/privacy/admin/views/setting-consent-method.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //dynamically show activated cookie consent plugins here
3
+ ?>
4
+ <ul>
5
+ <?php foreach ( $methods as $method => $description ): ?>
6
+ <li><label><input type="radio" name="<?php echo Advanced_Ads_Privacy::OPTION_KEY; ?>[consent-method]" value="<?php echo $method; ?>" <?php checked( $method , $current_method ); ?> /><?php echo $description ?></label>
7
+ <?php if ( $method === 'custom' ): ?>
8
+ <input type="text" name="<?php echo Advanced_Ads_Privacy::OPTION_KEY; ?>[custom-cookie-name]" value="<?php esc_attr_e( $custom_cookie_name );
9
+ ?>" placeholder="<?php _e( 'Name', 'advanced-ads' ); ?>"/>
10
+ <label><?php _e( 'contains', 'advanced-ads' ) ?> <input type="text" name="<?php
11
+ echo Advanced_Ads_Privacy::OPTION_KEY; ?>[custom-cookie-value]" value="<?php esc_attr_e( $custom_cookie_value );
12
+ ?>" placeholder="<?php _e( 'Value', 'advanced-ads' ); ?>"/> </label>
13
+ <?php endif; ?>
14
+ </li>
15
+ <?php endforeach; ?>
16
+ </ul>
17
+
18
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<label><input type="checkbox" name="<?php echo Advanced_Ads_Privacy::OPTION_KEY; ?>[show-non-personalized-adsense]" value="1" <?php checked( $show_non_personalized_adsense, 1 ); ?> /><?php _e( 'Show non-personalized AdSense ads until consent is given.', 'advanced-ads' ); ?></label>
modules/privacy/admin/views/setting-enable.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <input name="<?php echo Advanced_Ads_Privacy::OPTION_KEY; ?>[enabled]" type="checkbox" value="1" <?php checked( $module_enabled, 1 ); ?>/>&nbsp;
2
+ <a href="<?php echo ADVADS_URL . 'manual/ad-cookie-consent/#utm_source=advanced-ads&utm_medium=link&utm_campaign=privacy-tab'; ?>" target="_blank"><?php _e( 'Manual', 'advanced-ads' ); ?></a>
3
+ <?php if( Advanced_Ads_Checks::cache() && ! defined('AAP_VERSION') ) :
4
+ ?><p><span class="advads-error-message"><?php _e( 'It seems that a caching plugin is activated.', 'advanced-ads' ); ?></span>&nbsp;<?php
5
+ printf( __( 'Your users’ consent might get cached and show ads without to users who didn’t give their consent yet. Cache-busting in <a href="%s" target="_blank">Advanced Ads Pro</a> solves that.', 'advanced-ads' ), ADVADS_URL . 'add-ons/advanced-ads-pro/#utm_source=advanced-ads&utm_medium=link&utm_campaign=privacy-cache' ); ?></p><?php
6
+ endif;
modules/privacy/classes/plugin.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Advanced_Ads_Privacy
3
+ {
4
+ /**
5
+ * Singleton instance of the plugin
6
+ *
7
+ * @var Advanced_Ads_Privacy
8
+ */
9
+ protected static $instance;
10
+
11
+ /**
12
+ * module options
13
+ *
14
+ * @var array (if loaded)
15
+ */
16
+ protected $options;
17
+
18
+ /**
19
+ * option key
20
+ *
21
+ * @const array
22
+ */
23
+ const OPTION_KEY = 'advanced-ads-privacy';
24
+
25
+ /**
26
+ * Initialize the module
27
+ */
28
+ private function __construct() {
29
+ $options = $this->options();
30
+
31
+ add_filter( 'advanced-ads-can-display', array( $this, 'can_display_by_consent' ), 10, 3 );
32
+
33
+ }
34
+
35
+ /**
36
+ * Return an instance of Advanced_Ads_Privacy
37
+ *
38
+ * @return Advanced_Ads_Privacy
39
+ */
40
+ public static function get_instance() {
41
+ // If the single instance hasn't been set, set it now.
42
+ if ( null === self::$instance )
43
+ {
44
+ self::$instance = new self;
45
+ }
46
+
47
+ return self::$instance;
48
+ }
49
+
50
+ /**
51
+ * Return module options
52
+ *
53
+ * @return array $options
54
+ */
55
+ public function options() {
56
+ if ( ! isset( $this->options ) ) {
57
+ $this->options = get_option( self::OPTION_KEY, array() );
58
+ }
59
+ return $this->options;
60
+ }
61
+
62
+ /**
63
+ * Check if ad can be displayed based on user's consent.
64
+ *
65
+ * @return bool
66
+ */
67
+ public function can_display_by_consent( $can_display, Advanced_Ads_Ad $ad, $check_options ) {
68
+ if ( ! $can_display ) {
69
+ return $can_display;
70
+ }
71
+
72
+ if ( $check_options['passive_cache_busting'] ) {
73
+ return true;
74
+ }
75
+
76
+ $ad_options = $ad->options();
77
+ // If consent is not needed for the ad.
78
+ if ( ! empty( $ad_options['privacy']['ignore-consent'] ) ) {
79
+ return true;
80
+ }
81
+
82
+ $privacy_options = $this->options();
83
+ if ( $ad->type === 'adsense' ) {
84
+ if ( ! empty( $privacy_options['show-non-personalized-adsense'] ) ) {
85
+ // Either personalized or non-personalized ad will be shown.
86
+ return true;
87
+ }
88
+ }
89
+
90
+ $state = $this->get_state();
91
+ return ( $state === 'accepted' || $state === 'not_needed' );
92
+ }
93
+
94
+ /**
95
+ * Check if consent is not needed or was given by the user.
96
+ *
97
+ * @return str
98
+ * 'not_needed' - consent is not needed.
99
+ * 'accepted' - consent was given.
100
+ * 'unknown' - consent was not given yet.
101
+ */
102
+ public function get_state() {
103
+ if ( empty ( $this->options['enabled'] ) ) {
104
+ return 'not_needed';
105
+ }
106
+
107
+ $consent_method = isset( $this->options['consent-method'] ) ? $this->options['consent-method'] : 0;
108
+ switch ( $consent_method ) {
109
+ case '0':
110
+ return 'not_needed';
111
+ break;
112
+ case 'custom':
113
+ if ( ! isset( $this->options['custom-cookie-name'] ) || ! isset( $this->options['custom-cookie-value'] ) ) {
114
+ return 'not_needed';
115
+ }
116
+ $name = $this->options['custom-cookie-name'];
117
+ $value = $this->options['custom-cookie-value'];
118
+ if ( ! isset( $_COOKIE[ $name ] ) ) {
119
+ return 'unknown';
120
+ }
121
+
122
+ if ( ( $value === '' && $_COOKIE[ $name ] === '' )
123
+ || ($value !== '' && strpos( $_COOKIE[ $name ], $value ) !== false ) ) {
124
+ return 'accepted';
125
+ }
126
+ return 'unknown';
127
+ break;
128
+ default:
129
+ return isset( $_COOKIE[ $consent_method ] ) ? 'accepted' : 'unknown';
130
+ break;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Get consent methods.
136
+ *
137
+ * @return arr
138
+ */
139
+ public function get_consent_methods() {
140
+ $methods = array(
141
+ '0' => __( 'Show all ads even without consent.', 'advanced-ads' ),
142
+ 'custom' => __( 'Cookie', 'advanced-ads' ),
143
+ );
144
+ /*
145
+ // https://wordpress.org/plugins/cookie-notice/
146
+ if ( class_exists( 'Cookie_Notice' ) ) {
147
+ $methods['cookie_notice_accepted'] = 'Cookie Notice by dFactory';
148
+ }
149
+ // https://wordpress.org/plugins/uk-cookie-consent/
150
+ if ( defined( 'CTCC_PLUGIN_URL' ) ) {
151
+ $methods['catAccCookies'] = 'Cookie Consent';
152
+ }
153
+ // https://wordpress.org/plugins/cookie-law-info/
154
+ if ( defined( 'CLI_PLUGIN_DEVELOPMENT_MODE' ) ) {
155
+ $methods['viewed_cookie_policy'] = 'GDPR Cookie Consent';
156
+ }
157
+ */
158
+ return $methods;
159
+ }
160
+ }
modules/privacy/config.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // module configuration
4
+
5
+ $path = dirname( __FILE__ );
6
+
7
+ return array(
8
+ 'classmap' => array(
9
+ 'Advanced_Ads_Privacy' => $path . '/classes/plugin.php',
10
+ 'Advanced_Ads_Privacy_Admin' => $path . '/admin/admin.php',
11
+ ),
12
+ 'textdomain' => null,
13
+ );
modules/privacy/main.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( class_exists( 'Advanced_Ads', false ) ) {
3
+
4
+ // only load if not already existing (maybe included from another plugin)
5
+ if ( defined( 'ADVADS_PRIVACY_SLUG' ) ) {
6
+ return ;
7
+ }
8
+
9
+ // general and global slug, e.g. to store options in WP
10
+ define( 'ADVADS_PRIVACY_SLUG', 'advanced-ads-privacy' );
11
+
12
+ Advanced_Ads_Privacy::get_instance();
13
+
14
+ if ( is_admin() ) {
15
+ Advanced_Ads_Privacy_Admin::get_instance();
16
+ }
17
+ }
18
+
19
+
20
+
public/assets/js/advanced.js CHANGED
@@ -1 +1 @@
1
- advads={supports_localstorage:function(){"use strict";try{if(!window||window.localStorage===undefined){return false}window.localStorage.setItem("x","x");window.localStorage.removeItem("x");return true}catch(e){return false}},max_per_session:function(name,max){var num=1;if(max===undefined||parseInt(max)===0){max=1}if(this.cookie_exists(name)){if(this.get_cookie(name)>=max){return true}num=num+parseInt(this.get_cookie(name))}this.set_cookie(name,num);return false},count_up:function(name,exdays){var num=1;if(this.cookie_exists(name)){num=num+parseInt(this.get_cookie(name))}this.set_cookie(name,num)},set_cookie_exists:function(name){if(get_cookie(name)){return true}set_cookie(name,"",0);return false},get_cookie:function(name){var i,x,y,ADVcookies=document.cookie.split(";");for(i=0;i<ADVcookies.length;i++){x=ADVcookies[i].substr(0,ADVcookies[i].indexOf("="));y=ADVcookies[i].substr(ADVcookies[i].indexOf("=")+1);x=x.replace(/^\s+|\s+$/g,"");if(x===name){return unescape(y)}}},set_cookie:function(name,value,exdays,path,domain,secure){var expiry=exdays==null?null:exdays*24*60*60;this.set_cookie_sec(name,value,expiry,path,domain,secure)},set_cookie_sec:function(name,value,expiry,path,domain,secure){var exdate=new Date;exdate.setSeconds(exdate.getSeconds()+parseInt(expiry));document.cookie=name+"="+escape(value)+(expiry==null?"":"; expires="+exdate.toUTCString())+(path==null?"; path=/":"; path="+path)+(domain==null?"":"; domain="+domain)+(secure==null?"":"; secure")},cookie_exists:function(name){var c_value=this.get_cookie(name);if(c_value!==null&&c_value!==""&&c_value!==undefined){return true}return false},move:function(element,target,options){var el=jQuery(element);if(typeof options==="undefined"){options={}}if(typeof options.css==="undefined"){options.css={}}if(typeof options.method==="undefined"){options.method="prependTo"}if(target===""&&typeof options.target!=="undefined"){switch(options.target){case"wrapper":var offset="left";if(typeof options.offset!=="undefined"){offset=options.offset}target=this.find_wrapper(element,offset);break}}if(typeof options.moveintohidden==="undefined"){target=jQuery(target).filter(":visible")}switch(options.method){case"insertBefore":el.insertBefore(target);break;case"insertAfter":el.insertAfter(target);break;case"appendTo":el.appendTo(target);break;case"prependTo":el.prependTo(target);break;default:el.prependTo(target)}},set_parent_relative:function(element){var el=jQuery(element);var parent=el.parent();if(parent.css("position")==="static"||parent.css("position")===""){parent.css("position","relative")}},fix_element:function(element,options){this.set_parent_relative(element);var el=jQuery(element);if(typeof options!=="undefined"&&options.is_invisible){el.show()}var topoffset=parseInt(el.offset().top);var leftoffset=parseInt(el.offset().left);if(typeof options!=="undefined"&&options.is_invisible){el.hide()}el.css("position","fixed").css("top",topoffset+"px").css("left",leftoffset+"px").css("right","")},find_wrapper:function(element,offset){var returnValue;jQuery("body").children().each(function(key,value){if(value.id!==element.substring(1)){var checkedelement=jQuery(value);if(offset==="right"&&checkedelement.offset().left+jQuery(checkedelement).width()<jQuery(window).width()||offset==="left"&&checkedelement.offset().left>0){if(checkedelement.css("position")==="static"||checkedelement.css("position")===""){checkedelement.css("position","relative")}returnValue=value;return false}}});return returnValue},center_fixed_element:function(element){var el=jQuery(element);var left=jQuery(window).width()/2-parseInt(el.css("width"))/2;el.css("left",left+"px")},center_vertically:function(element){var el=jQuery(element);var left=jQuery(window).height()/2-parseInt(el.css("height"))/2;el.css("top",left+"px")},close:function(element){var wrapper=jQuery(element);wrapper.remove()}};jQuery(document).ready(function(){if(advads.supports_localstorage()&&localStorage.getItem("advads_frontend_picker")){var advads_picker_cur,advads_picker_overlay=jQuery("<div id='advads-picker-overlay'>"),advads_picker_no=[document.body,document.documentElement,document];advads_picker_overlay.css({position:"absolute",border:"solid 2px #428bca",backgroundColor:"rgba(66,139,202,0.5)",boxSizing:"border-box",zIndex:1e6,pointerEvents:"none"}).prependTo("body");jQuery(document).mousemove(function(e){if(e.target===advads_picker_cur){return}if(~advads_picker_no.indexOf(e.target)){advads_picker_cur=null;advads_picker_overlay.hide();return}var target=jQuery(e.target),offset=target.offset(),width=target.outerWidth(),height=target.outerHeight();advads_picker_cur=e.target;advads_picker_overlay.css({top:offset.top,left:offset.left,width:width,height:height}).show();console.log(jQuery(advads_picker_cur).getPath())});jQuery(document).click(function(e){var path=jQuery(advads_picker_cur).getPath();localStorage.setItem("advads_frontend_element",path);window.location=localStorage.getItem("advads_prev_url")})}});jQuery.fn.extend({getPath:function(path,depth){if(typeof path==="undefined")path="";if(typeof depth==="undefined")depth=0;if(this.is("html")){return"html > "+path}else if(3===depth){return path}var cur=this.get(0).nodeName.toLowerCase();var el_id=this.attr("id"),el_class=this.attr("class");depth=depth+1;if(typeof el_id!=="undefined"&&!/\d/.test(el_id)){cur+="#"+el_id}else if(typeof el_class!=="undefined"){el_class=el_class.split(/[\s\n]+/);el_class=jQuery.grep(el_class,function(element,index){return!/\d/.test(element)});if(el_class.length){cur+="."+el_class.slice(0,2).join(".")}}if(this.siblings(cur).length){cur+=":eq("+this.siblings(cur).addBack().not("#advads-picker-overlay").index(this)+")"}if(path===""){return this.parent().getPath(cur,depth)}else{return this.parent().getPath(cur+" > "+path,depth)}}});
1
+ advads={supports_localstorage:function(){"use strict";try{if(!window||window.localStorage===undefined){return false}window.localStorage.setItem("x","x");window.localStorage.removeItem("x");return true}catch(e){return false}},max_per_session:function(name,max){var num=1;if(max===undefined||parseInt(max)===0){max=1}if(this.cookie_exists(name)){if(this.get_cookie(name)>=max){return true}num=num+parseInt(this.get_cookie(name))}this.set_cookie(name,num);return false},count_up:function(name,exdays){var num=1;if(this.cookie_exists(name)){num=num+parseInt(this.get_cookie(name))}this.set_cookie(name,num)},set_cookie_exists:function(name){if(get_cookie(name)){return true}set_cookie(name,"",0);return false},get_cookie:function(name){var i,x,y,ADVcookies=document.cookie.split(";");for(i=0;i<ADVcookies.length;i++){x=ADVcookies[i].substr(0,ADVcookies[i].indexOf("="));y=ADVcookies[i].substr(ADVcookies[i].indexOf("=")+1);x=x.replace(/^\s+|\s+$/g,"");if(x===name){return unescape(y)}}},set_cookie:function(name,value,exdays,path,domain,secure){var expiry=exdays==null?null:exdays*24*60*60;this.set_cookie_sec(name,value,expiry,path,domain,secure)},set_cookie_sec:function(name,value,expiry,path,domain,secure){var exdate=new Date;exdate.setSeconds(exdate.getSeconds()+parseInt(expiry));document.cookie=name+"="+escape(value)+(expiry==null?"":"; expires="+exdate.toUTCString())+(path==null?"; path=/":"; path="+path)+(domain==null?"":"; domain="+domain)+(secure==null?"":"; secure")},cookie_exists:function(name){var c_value=this.get_cookie(name);if(c_value!==null&&c_value!==""&&c_value!==undefined){return true}return false},move:function(element,target,options){var el=jQuery(element);if(typeof options==="undefined"){options={}}if(typeof options.css==="undefined"){options.css={}}if(typeof options.method==="undefined"){options.method="prependTo"}if(target===""&&typeof options.target!=="undefined"){switch(options.target){case"wrapper":var offset="left";if(typeof options.offset!=="undefined"){offset=options.offset}target=this.find_wrapper(element,offset);break}}if(typeof options.moveintohidden==="undefined"){target=jQuery(target).filter(":visible")}switch(options.method){case"insertBefore":el.insertBefore(target);break;case"insertAfter":el.insertAfter(target);break;case"appendTo":el.appendTo(target);break;case"prependTo":el.prependTo(target);break;default:el.prependTo(target)}},set_parent_relative:function(element){var el=jQuery(element);var parent=el.parent();if(parent.css("position")==="static"||parent.css("position")===""){parent.css("position","relative")}},fix_element:function(element,options){this.set_parent_relative(element);var el=jQuery(element);if(typeof options!=="undefined"&&options.is_invisible){el.show()}var topoffset=parseInt(el.offset().top);var leftoffset=parseInt(el.offset().left);if(typeof options!=="undefined"&&options.is_invisible){el.hide()}el.css("position","fixed").css("top",topoffset+"px").css("left",leftoffset+"px").css("right","")},find_wrapper:function(element,offset){var returnValue;jQuery("body").children().each(function(key,value){if(value.id!==element.substring(1)){var checkedelement=jQuery(value);if(offset==="right"&&checkedelement.offset().left+jQuery(checkedelement).width()<jQuery(window).width()||offset==="left"&&checkedelement.offset().left>0){if(checkedelement.css("position")==="static"||checkedelement.css("position")===""){checkedelement.css("position","relative")}returnValue=value;return false}}});return returnValue},center_fixed_element:function(element){var el=jQuery(element);var left=jQuery(window).width()/2-parseInt(el.css("width"))/2;el.css("left",left+"px")},center_vertically:function(element){var el=jQuery(element);var left=jQuery(window).height()/2-parseInt(el.css("height"))/2;el.css("top",left+"px")},close:function(element){var wrapper=jQuery(element);wrapper.remove()},privacy:{get_state:function(){if(!window.advads_options||!window.advads_options.privacy){return"not_needed"}var options=window.advads_options.privacy;if(!options.enabled){return"not_needed"}var method=options["consent-method"]?options["consent-method"]:"0";switch(method){case"0":return"not_needed";break;case"custom":if(options["custom-cookie-value"===undefined]||options["custom-cookie-value"]===undefined){return"not_needed"}var found=advads.get_cookie(options["custom-cookie-name"]);if(typeof found!=="string"){return"unknown"}if(options["custom-cookie-value"]===""&&found===""||options["custom-cookie-value"]!==""&&found.indexOf(options["custom-cookie-value"])!==-1){return"accepted"}return"unknown";break;default:return advads.cookie_exists(method)?"accepted":"unknown"}},is_adsense_npa_enabled:function(){if(!window.advads_options||!window.advads_options.privacy){return true}var options=window.advads_options.privacy;return!!options["show-non-personalized-adsense"]}}};jQuery(document).ready(function(){if(advads.supports_localstorage()&&localStorage.getItem("advads_frontend_picker")){var advads_picker_cur,advads_picker_overlay=jQuery("<div id='advads-picker-overlay'>"),advads_picker_no=[document.body,document.documentElement,document];advads_picker_overlay.css({position:"absolute",border:"solid 2px #428bca",backgroundColor:"rgba(66,139,202,0.5)",boxSizing:"border-box",zIndex:1e6,pointerEvents:"none"}).prependTo("body");jQuery(document).mousemove(function(e){if(e.target===advads_picker_cur){return}if(~advads_picker_no.indexOf(e.target)){advads_picker_cur=null;advads_picker_overlay.hide();return}var target=jQuery(e.target),offset=target.offset(),width=target.outerWidth(),height=target.outerHeight();advads_picker_cur=e.target;advads_picker_overlay.css({top:offset.top,left:offset.left,width:width,height:height}).show();console.log(jQuery(advads_picker_cur).getPath())});jQuery(document).click(function(e){var path=jQuery(advads_picker_cur).getPath();localStorage.setItem("advads_frontend_element",path);window.location=localStorage.getItem("advads_prev_url")})}});jQuery.fn.extend({getPath:function(path,depth){if(typeof path==="undefined")path="";if(typeof depth==="undefined")depth=0;if(this.is("html")){return"html > "+path}else if(3===depth){return path}var cur=this.get(0).nodeName.toLowerCase();var el_id=this.attr("id"),el_class=this.attr("class");depth=depth+1;if(typeof el_id!=="undefined"&&!/\d/.test(el_id)){cur+="#"+el_id}else if(typeof el_class!=="undefined"){el_class=el_class.split(/[\s\n]+/);el_class=jQuery.grep(el_class,function(element,index){return!/\d/.test(element)});if(el_class.length){cur+="."+el_class.slice(0,2).join(".")}}if(this.siblings(cur).length){cur+=":eq("+this.siblings(cur).addBack().not("#advads-picker-overlay").index(this)+")"}if(path===""){return this.parent().getPath(cur,depth)}else{return this.parent().getPath(cur+" > "+path,depth)}}});
public/assets/js/advanced.orig.js CHANGED
@@ -297,6 +297,60 @@ advads = {
297
  var wrapper = jQuery(element);
298
  // remove the ad
299
  wrapper.remove();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  }
301
 
302
  };
297
  var wrapper = jQuery(element);
298
  // remove the ad
299
  wrapper.remove();
300
+ },
301
+
302
+ privacy: {
303
+ /**
304
+ * Get consent state.
305
+ *
306
+ * @return str
307
+ * 'not_needed' - consent is not needed.
308
+ * 'accepted' - consent was given.
309
+ * 'unknown' - consent was not given yet.
310
+ */
311
+ get_state: function() {
312
+ if ( ! window.advads_options || ! window.advads_options.privacy ) {
313
+ return 'not_needed';
314
+ }
315
+
316
+ var options = window.advads_options.privacy;
317
+
318
+ if ( ! options.enabled ) {
319
+ return 'not_needed';
320
+ }
321
+
322
+ var method = options['consent-method'] ? options['consent-method'] : '0';
323
+
324
+ switch ( method ) {
325
+ case '0':
326
+ return 'not_needed';
327
+ break;
328
+ case 'custom':
329
+ if ( options['custom-cookie-value' === undefined] || options['custom-cookie-value'] === undefined ) {
330
+ return 'not_needed';
331
+ }
332
+
333
+ var found = advads.get_cookie( options['custom-cookie-name'] );
334
+ if ( typeof found !== 'string' ) {
335
+ return 'unknown';
336
+ }
337
+ if ( ( options['custom-cookie-value'] === '' && found === '' )
338
+ || ( options['custom-cookie-value'] !== '' && found.indexOf( options['custom-cookie-value'] ) !== -1 ) ) {
339
+ return 'accepted';
340
+ }
341
+ return 'unknown';
342
+ break;
343
+ default:
344
+ return ( advads.cookie_exists( method ) ) ? 'accepted' : 'unknown';
345
+ }
346
+ },
347
+ is_adsense_npa_enabled: function() {
348
+ if ( ! window.advads_options || ! window.advads_options.privacy ) {
349
+ return true;
350
+ }
351
+ var options = window.advads_options.privacy;
352
+ return !! options['show-non-personalized-adsense'];
353
+ }
354
  }
355
 
356
  };
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: ads, ad manager, ad widget, ad rotation, adsense, advertise, advertisement
5
  Requires at least: 4.6
6
  Tested up to: 4.9
7
  Requires PHP: 5.2
8
- Stable tag: 1.8.30
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -15,10 +15,11 @@ Manage and optimize your ads. All ad codes, AdSense Auto ads, ad widget, rotatio
15
 
16
  Are you looking for a simple ad manager plugin? These are the top arguments to use Advanced Ads:
17
 
 
 
18
  * most features to test and optimize ads
19
  * unlimited ad units
20
- * approved by 9 years in Publishing and Ad Optimization
21
- * Google AdSense Partner
22
  * works with all ad types and networks (e.g. AdSense or Amazon)
23
  * the only solution with *Ad Health* integration and AdSense violation checks
24
  * best rated [free support](https://wordpress.org/support/plugin/advanced-ads)
@@ -167,7 +168,9 @@ How to install the plugin and get it working?
167
 
168
  = What about my users’ privacy and GDPR? =
169
 
170
- Advanced Ads does neither save personal information (e.g., an IP address) in your database nor cookies in the visitor’s browser.
 
 
171
 
172
  Third party services like Google Analytics are disabled by default.
173
 
@@ -250,6 +253,10 @@ Yes. Advanced Ads is based on WordPress standards and therefore easily customiza
250
 
251
  == Changelog ==
252
 
 
 
 
 
253
  = 1.8.30 =
254
 
255
  * prevented entering 0 in the position index field of the Content placement
5
  Requires at least: 4.6
6
  Tested up to: 4.9
7
  Requires PHP: 5.2
8
+ Stable tag: 1.9
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
15
 
16
  Are you looking for a simple ad manager plugin? These are the top arguments to use Advanced Ads:
17
 
18
+ * approved in 9 years of Publishing and Ad Optimization
19
+ * Google AdSense Partner
20
  * most features to test and optimize ads
21
  * unlimited ad units
22
+ * [GDPR support](https://wpadvancedads.com/manual/ad-cookie-consent/): hide ads until consent is given
 
23
  * works with all ad types and networks (e.g. AdSense or Amazon)
24
  * the only solution with *Ad Health* integration and AdSense violation checks
25
  * best rated [free support](https://wordpress.org/support/plugin/advanced-ads)
168
 
169
  = What about my users’ privacy and GDPR? =
170
 
171
+ You can show ads only to visitors that give their consent. See [GDPR support](https://wpadvancedads.com/manual/ad-cookie-consent/).
172
+
173
+ Advanced Ads itself does neither save personal information (e.g., an IP address) in your database nor cookies in the visitor’s browser.
174
 
175
  Third party services like Google Analytics are disabled by default.
176
 
253
 
254
  == Changelog ==
255
 
256
+ = 1.9 =
257
+
258
+ * added Privacy module to hide ads until consent is given, see new [Privacy settings](https://wpadvancedads.com/manual/ad-cookie-consent/)
259
+
260
  = 1.8.30 =
261
 
262
  * prevented entering 0 in the position index field of the Content placement