Advanced Ads - Version 1.8.29

Version Description

  • added ad block that works with Gutenberg version 2.8.0
  • allowed to use uppercase letters in wrapper ID
  • do not count cache preload features of caching plugins as bots
  • removed orange border for just updated placements since it implicated that there was something wrong
  • use AnonymizeIP by default for ad block counter feature
  • remove "ca-" from AdSense publisher ID dynamically if entered by accident
  • fixed possible content breaking by empty Content placement
  • fixed issue with Pagination condition in Pro
  • fixed minor license check issue
  • fixed issue with legacy value for the Unlimited Ad Injection option
Download this release

Release Info

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

Code changes from version 1.8.28 to 1.8.29

admin/assets/css/admin.css CHANGED
@@ -255,12 +255,6 @@ fieldset.advads-group-add-ad { margin-top: 1em; }
255
  .advads-placements-table-options { text-align: right; }
256
  .advads-placements-table-options input[type="number"] { width: 4.5em; }
257
  .advads-placements-table ol { margin: 0.5em 0; list-style-position: inside; }
258
- .advads-placement-background-blink {
259
- box-shadow: inset 0px 0px 3px 3px #ff9800;
260
- -webkit-transition: box-shadow 1.0s ease-in-out;
261
- -ms-transition: box-shadow 1.0s ease-in-out;
262
- transition: box-shadow 1.0s ease-in-out;
263
- }
264
 
265
  /**
266
  GENERAL ELEMENTS
255
  .advads-placements-table-options { text-align: right; }
256
  .advads-placements-table-options input[type="number"] { width: 4.5em; }
257
  .advads-placements-table ol { margin: 0.5em 0; list-style-position: inside; }
 
 
 
 
 
 
258
 
259
  /**
260
  GENERAL ELEMENTS
admin/assets/js/admin.js CHANGED
@@ -266,7 +266,7 @@ jQuery( document ).ready(function ($) {
266
  * also highlight the box with an effect for a short time
267
  */
268
  if( jQuery( window.location.hash ).length ){
269
- jQuery( window.location.hash ).toggleClass( 'advads-placement-background-blink' ).find( '.advads-toggle-link + div, .advads-usage' ).show();
270
 
271
  }
272
 
266
  * also highlight the box with an effect for a short time
267
  */
268
  if( jQuery( window.location.hash ).length ){
269
+ jQuery( window.location.hash ).find( '.advads-toggle-link + div, .advads-usage' ).show();
270
 
271
  }
272
 
admin/includes/class-licenses.php CHANGED
@@ -135,7 +135,9 @@ class Advanced_Ads_Admin_Licenses {
135
 
136
  $license_data = json_decode( wp_remote_retrieve_body( $response ) );
137
  // save license status
138
- update_option($options_slug . '-license-status', $license_data->license, false);
 
 
139
  if( !empty( $license_data->expires ) ){
140
  update_option($options_slug . '-license-expires', $license_data->expires, false);
141
  }
135
 
136
  $license_data = json_decode( wp_remote_retrieve_body( $response ) );
137
  // save license status
138
+ if( !empty( $license_data->license ) ){
139
+ update_option($options_slug . '-license-status', $license_data->license, false);
140
+ }
141
  if( !empty( $license_data->expires ) ){
142
  update_option($options_slug . '-license-expires', $license_data->expires, false);
143
  }
admin/includes/class-meta-box.php CHANGED
@@ -244,7 +244,7 @@ class Advanced_Ads_Admin_Meta_Boxes {
244
  __( 'Ad Settings', 'advanced-ads' ),
245
  array( $this, 'render_post_meta_box' ),
246
  $post_type,
247
- 'advanced',
248
  'low'
249
  );
250
  }
244
  __( 'Ad Settings', 'advanced-ads' ),
245
  array( $this, 'render_post_meta_box' ),
246
  $post_type,
247
+ 'side',
248
  'low'
249
  );
250
  }
admin/includes/class-overview-widgets.php CHANGED
@@ -402,11 +402,11 @@ class Advanced_Ads_Overview_Widgets_Callbacks {
402
  }
403
  }
404
 
405
- // add Visual Composer Ads, if VC was detected
406
  if( defined( 'WPB_VC_VERSION') ) {
407
  $add_ons['visual_composer'] = array(
408
- 'title' => 'Visual Composer Ads',
409
- 'desc' => __( 'Manage ad positions with Visual Composer.', 'advanced-ads' ),
410
  'order' => 2,
411
  'class' => 'free',
412
  'link' => wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . 'ads-for-visual-composer'), 'install-plugin_' . 'ads-for-visual-composer'),
402
  }
403
  }
404
 
405
+ // add Ads for WPBakery Page Builder (formerly Visual Composer), if VC was detected
406
  if( defined( 'WPB_VC_VERSION') ) {
407
  $add_ons['visual_composer'] = array(
408
+ 'title' => 'Ads for WPBakery Page Builder (formerly Visual Composer)',
409
+ 'desc' => __( 'Manage ad positions with WPBakery Page Builder (formerly Visual Composer).', 'advanced-ads' ),
410
  'order' => 2,
411
  'class' => 'free',
412
  'link' => wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . 'ads-for-visual-composer'), 'install-plugin_' . 'ads-for-visual-composer'),
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.28
16
  * Author: Thomas Maier
17
  * Author URI: https://wpadvancedads.com
18
  * Text Domain: advanced-ads
@@ -36,10 +36,10 @@ define( 'ADVADS_BASE', plugin_basename( __FILE__ ) ); // plugin base as used by
36
  define( 'ADVADS_BASE_PATH', plugin_dir_path( __FILE__ ) );
37
  define( 'ADVADS_BASE_URL', plugin_dir_url( __FILE__ ) );
38
  define( 'ADVADS_BASE_DIR', dirname( ADVADS_BASE ) ); // directory of the plugin without any paths
39
- // general and global slug, e.g. to store options in WP, textdomain
40
  define( 'ADVADS_SLUG', 'advanced-ads' );
41
  define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
42
- define( 'ADVADS_VERSION', '1.8.28' );
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.8.29
16
  * Author: Thomas Maier
17
  * Author URI: https://wpadvancedads.com
18
  * Text Domain: advanced-ads
36
  define( 'ADVADS_BASE_PATH', plugin_dir_path( __FILE__ ) );
37
  define( 'ADVADS_BASE_URL', plugin_dir_url( __FILE__ ) );
38
  define( 'ADVADS_BASE_DIR', dirname( ADVADS_BASE ) ); // directory of the plugin without any paths
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.29' );
43
 
44
  /*----------------------------------------------------------------------------*
45
  * Autoloading, modules and functions
classes/ad_placements.php CHANGED
@@ -357,29 +357,30 @@ class Advanced_Ads_Placements {
357
  // check if mbstring exists
358
  if ( ! function_exists( 'mb_convert_encoding' ) ) {
359
  if ( $wpCharset === "UTF-8" ) {
360
- $content = htmlspecialchars_decode( htmlentities( $content, ENT_COMPAT, $wpCharset, false ) );
361
  } else {
362
  return $content;
363
  }
364
  } else {
365
- $content = mb_convert_encoding( $content, 'HTML-ENTITIES', $wpCharset );
366
  }
367
 
368
  // check which priority the wpautop filter has; might have been disabled on purpose
369
  $wpautop_priority = has_filter( 'the_content', 'wpautop');
370
  if ( $wpautop_priority && Advanced_Ads_Plugin::get_instance()->get_content_injection_priority() < $wpautop_priority ) {
371
- $content = wpautop( $content );
372
  }
373
 
374
- $dom = new DOMDocument('1.0', $wpCharset);
375
- // may loose some fragments or add autop-like code
376
- libxml_use_internal_errors(true); // avoid notices and warnings - html is most likely malformed
377
-
378
  // temporarily change content during processing
379
  $replacements = array(
380
  'gcse:search' => 'gcse__search', // Google custom search namespaced tags.
381
  );
382
  $content_to_load = str_replace( array_keys( $replacements ), array_values( $replacements ), $content );
 
 
 
 
 
383
  $success = $dom->loadHtml('<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wpCharset . '" /><body>' . $content_to_load);
384
  libxml_use_internal_errors(false);
385
  if ($success !== true) {
@@ -455,12 +456,13 @@ class Advanced_Ads_Placements {
455
  if ($options['paragraph_count'] >= $options['paragraph_id']) {
456
  $offset = $options['paragraph_select_from_bottom'] ? $options['paragraph_count'] - $options['paragraph_id'] : $options['paragraph_id'] - 1;
457
  $offsets = apply_filters( 'advanced-ads-placement-content-offsets', array( $offset ), $options, $placement_opts );
 
458
 
459
  foreach ( $offsets as $offset ) {
460
  // test ad is emtpy
461
  $adContent = Advanced_Ads_Select::get_instance()->get_ad_by_method( $placement_id, 'placement', $options );
462
  if ( trim( $adContent, $whitespaces ) === '' ) {
463
- return $content;
464
  }
465
 
466
  // convert HTML to XML!
@@ -511,6 +513,29 @@ class Advanced_Ads_Placements {
511
  }
512
 
513
  libxml_use_internal_errors(false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  }
515
  /**
516
  * show a warning to ad admins in the Ad Health bar in the frontend, when
@@ -531,24 +556,6 @@ class Advanced_Ads_Placements {
531
  }
532
  }
533
 
534
- // convert to text-representation
535
- $content = $dom->saveHTML();
536
- // remove head and tail (required for dom parser but unwanted for content)
537
- $content = substr($content, stripos($content, '<body>') + 6);
538
- $content = str_replace(array('</body>', '</html>'), '', $content);
539
- $content = str_replace( array_values( $replacements ), array_keys( $replacements ), $content );
540
-
541
- // no fall-back desired: if there are too few paragraphs do nothing
542
-
543
- // fix shortcode quotes (malformed by backend editor)
544
- $matches = array();
545
- if (0 < preg_match_all('/\[[^]]+\]/Siu', $content, $matches, PREG_OFFSET_CAPTURE) && isset($matches[0])) {
546
- foreach ($matches[0] as $match) {
547
- $offset = $match[1];
548
- $content = substr($content, 0, $offset) . str_replace(array('“', '″', '&#8220;', '&quote;', '&#8243;'), '"', $match[0]) . substr($content, $offset + strlen($match[0]));
549
- }
550
- }
551
-
552
  return $content;
553
  }
554
 
357
  // check if mbstring exists
358
  if ( ! function_exists( 'mb_convert_encoding' ) ) {
359
  if ( $wpCharset === "UTF-8" ) {
360
+ $content_to_load = htmlspecialchars_decode( htmlentities( $content, ENT_COMPAT, $wpCharset, false ) );
361
  } else {
362
  return $content;
363
  }
364
  } else {
365
+ $content_to_load = mb_convert_encoding( $content, 'HTML-ENTITIES', $wpCharset );
366
  }
367
 
368
  // check which priority the wpautop filter has; might have been disabled on purpose
369
  $wpautop_priority = has_filter( 'the_content', 'wpautop');
370
  if ( $wpautop_priority && Advanced_Ads_Plugin::get_instance()->get_content_injection_priority() < $wpautop_priority ) {
371
+ $content_to_load = wpautop( $content_to_load );
372
  }
373
 
 
 
 
 
374
  // temporarily change content during processing
375
  $replacements = array(
376
  'gcse:search' => 'gcse__search', // Google custom search namespaced tags.
377
  );
378
  $content_to_load = str_replace( array_keys( $replacements ), array_values( $replacements ), $content );
379
+
380
+ $dom = new DOMDocument('1.0', $wpCharset);
381
+ // may loose some fragments or add autop-like code
382
+ libxml_use_internal_errors(true); // avoid notices and warnings - html is most likely malformed
383
+
384
  $success = $dom->loadHtml('<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wpCharset . '" /><body>' . $content_to_load);
385
  libxml_use_internal_errors(false);
386
  if ($success !== true) {
456
  if ($options['paragraph_count'] >= $options['paragraph_id']) {
457
  $offset = $options['paragraph_select_from_bottom'] ? $options['paragraph_count'] - $options['paragraph_id'] : $options['paragraph_id'] - 1;
458
  $offsets = apply_filters( 'advanced-ads-placement-content-offsets', array( $offset ), $options, $placement_opts );
459
+ $did_inject = false;
460
 
461
  foreach ( $offsets as $offset ) {
462
  // test ad is emtpy
463
  $adContent = Advanced_Ads_Select::get_instance()->get_ad_by_method( $placement_id, 'placement', $options );
464
  if ( trim( $adContent, $whitespaces ) === '' ) {
465
+ continue;
466
  }
467
 
468
  // convert HTML to XML!
513
  }
514
 
515
  libxml_use_internal_errors(false);
516
+ $did_inject = true;
517
+ }
518
+
519
+ if ( ! $did_inject ) {
520
+ return $content;
521
+ }
522
+
523
+ // convert to text-representation
524
+ $content = $dom->saveHTML();
525
+ // remove head and tail (required for dom parser but unwanted for content)
526
+ $content = substr($content, stripos($content, '<body>') + 6);
527
+ $content = str_replace(array('</body>', '</html>'), '', $content);
528
+ $content = str_replace( array_values( $replacements ), array_keys( $replacements ), $content );
529
+
530
+ // no fall-back desired: if there are too few paragraphs do nothing
531
+
532
+ // fix shortcode quotes (malformed by backend editor)
533
+ $matches = array();
534
+ if (0 < preg_match_all('/\[[^]]+\]/Siu', $content, $matches, PREG_OFFSET_CAPTURE) && isset($matches[0])) {
535
+ foreach ($matches[0] as $match) {
536
+ $offset = $match[1];
537
+ $content = substr($content, 0, $offset) . str_replace(array('“', '″', '&#8220;', '&quote;', '&#8243;'), '"', $match[0]) . substr($content, $offset + strlen($match[0]));
538
+ }
539
  }
540
  /**
541
  * show a warning to ad admins in the Ad Health bar in the frontend, when
556
  }
557
  }
558
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  return $content;
560
  }
561
 
classes/display-conditions.php CHANGED
@@ -1100,7 +1100,7 @@ class Advanced_Ads_Display_Conditions {
1100
 
1101
  // `<!-- nextpage -->` tags
1102
  if ( ! isset( $args['wp_the_query']['page'] ) ) {
1103
- $args['wp_the_query']['page'] = isset( $wp_the_query->query_vars['page'] ) ? $wp_the_query->query_vars['page'] : 1;
1104
  $args['wp_the_query']['numpages'] = isset( $numpages ) ? $numpages : 1;
1105
  }
1106
 
1100
 
1101
  // `<!-- nextpage -->` tags
1102
  if ( ! isset( $args['wp_the_query']['page'] ) ) {
1103
+ $args['wp_the_query']['page'] = isset( $wp_the_query->query_vars['page'] ) && $wp_the_query->query_vars['page'] ? $wp_the_query->query_vars['page'] : 1;
1104
  $args['wp_the_query']['numpages'] = isset( $numpages ) ? $numpages : 1;
1105
  }
1106
 
classes/plugin.php CHANGED
@@ -227,7 +227,7 @@ class Advanced_Ads_Plugin {
227
  */
228
  public function load_plugin_textdomain() {
229
  // $locale = apply_filters('advanced-ads-plugin-locale', get_locale(), $domain);
230
- load_plugin_textdomain( ADVADS_SLUG, false, ADVADS_BASE_DIR . '/languages' );
231
  }
232
 
233
  /**
227
  */
228
  public function load_plugin_textdomain() {
229
  // $locale = apply_filters('advanced-ads-plugin-locale', get_locale(), $domain);
230
+ load_plugin_textdomain( 'advanced-ads', false, ADVADS_BASE_DIR . '/languages' );
231
  }
232
 
233
  /**
classes/utils.php CHANGED
@@ -63,9 +63,9 @@ class Advanced_Ads_Utils {
63
  $result .= " style=\"$_style_values_string\"";
64
  } else {
65
  if ( is_array( $_values ) ) {
66
- $_values_string = implode( ' ', $_values ); }
67
  else {
68
- $_values_string = sanitize_title( $_values ); }
69
  $result .= " $_html_attr=\"$_values_string\"";
70
  }
71
  }
@@ -84,5 +84,42 @@ class Advanced_Ads_Utils {
84
  }
85
  return $content;
86
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
88
  ?>
63
  $result .= " style=\"$_style_values_string\"";
64
  } else {
65
  if ( is_array( $_values ) ) {
66
+ $_values_string = esc_attr( implode( ' ', $_values ) ); }
67
  else {
68
+ $_values_string = esc_attr( $_values ); }
69
  $result .= " $_html_attr=\"$_values_string\"";
70
  }
71
  }
84
  }
85
  return $content;
86
  }
87
+
88
+ /**
89
+ * Get nested ads of an ad or a group.
90
+ *
91
+ * @param str $id Id.
92
+ * @param str $type Type (placement, ad or group).
93
+ * @return array of Advanced_Ads_Ad objects.
94
+ */
95
+ public static function get_nested_ads( $id, $type ) {
96
+ $result = array();
97
+
98
+ switch( $type ) {
99
+ case 'placement':
100
+ $placements = Advanced_Ads::get_ad_placements_array();
101
+ if ( isset( $placements[ $id ]['item'] ) ) {
102
+ $item = explode( '_', $placements[ $id ]['item'] );
103
+ if ( isset( $item[1] ) ) {
104
+ return self::get_nested_ads( $item[1], $item[0] );
105
+ }
106
+ }
107
+ case 'ad':
108
+ $ad = new Advanced_Ads_Ad( $id );
109
+ $result[] = $ad;
110
+ if ( 'group' === $ad->type && ! empty( $ad->output['group_id'] ) ) {
111
+ $result = array_merge( $result, self::get_nested_ads( $ad->output['group_id'], 'group' ) );
112
+ }
113
+ break;
114
+ case 'group':
115
+ $group = new Advanced_Ads_Group( $id );
116
+ $ads = $group->get_all_ads();
117
+ foreach ( $ads as $ad ) {
118
+ $result = array_merge( $result, self::get_nested_ads( $ad->ID, 'ad' ) );
119
+ }
120
+ break;
121
+ }
122
+ return $result;
123
+ }
124
  }
125
  ?>
classes/widget.php CHANGED
@@ -134,6 +134,10 @@ class Advanced_Ads_Widget extends WP_Widget {
134
  $select = array();
135
  $placements = Advanced_Ads::get_ad_placements_array();
136
 
 
 
 
 
137
  foreach( $placements as $_placement_slug => $_placement ){
138
  if( isset( $_placement['type'] ) && 'sidebar_widget' === $_placement['type'] ){
139
  $select['placements']['placement_' . $_placement_slug ] = $_placement['name'];
134
  $select = array();
135
  $placements = Advanced_Ads::get_ad_placements_array();
136
 
137
+ if ( is_array( $placements ) ) {
138
+ ksort( $placements );
139
+ }
140
+
141
  foreach( $placements as $_placement_slug => $_placement ){
142
  if( isset( $_placement['type'] ) && 'sidebar_widget' === $_placement['type'] ){
143
  $select['placements']['placement_' . $_placement_slug ] = $_placement['name'];
includes/load_modules.php CHANGED
@@ -59,23 +59,9 @@ final class Advanced_Ads_ModuleLoader {
59
  self::$modules[$moduleName] = $modulePath;
60
  }
61
 
62
- // register textdomains if non-empty
63
- /* if ( self::$textdomains !== array() ) {
64
- add_action( 'plugins_loaded', array( 'Advanced_Ads_ModuleLoader', 'load_module_textdomains') );
65
- }*/
66
-
67
  // load modules
68
  foreach ( self::$modules as $name => $path ) {
69
  require_once $path . '/main.php';
70
  }
71
  }
72
-
73
- /**
74
- * @deprecated since 1.7.6
75
- */
76
- public static function load_module_textdomains() {
77
- foreach ( self::$textdomains as $slug => $rel_path ) {
78
- load_plugin_textdomain( ADVADS_SLUG, false, ADVADS_BASE_DIR . '/languages' );
79
- }
80
- }
81
  }
59
  self::$modules[$moduleName] = $modulePath;
60
  }
61
 
 
 
 
 
 
62
  // load modules
63
  foreach ( self::$modules as $name => $path ) {
64
  require_once $path . '/main.php';
65
  }
66
  }
 
 
 
 
 
 
 
 
 
67
  }
modules/adblock-finder/public/public.php CHANGED
@@ -11,7 +11,13 @@ class Advanced_Ads_Adblock_Finder {
11
 
12
  ?><script>
13
  var advanced_ads_ga_UID = <?php echo isset( $options['ga-UID'] ) ? "'" . esc_js( $options['ga-UID'] ). "'" : 'false' ?>;
14
- <?php
 
 
 
 
 
 
15
 
16
  if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && current_user_can( 'manage_options' ) ) {
17
  readfile( dirname( __FILE__ ) . '/script.js' );
11
 
12
  ?><script>
13
  var advanced_ads_ga_UID = <?php echo isset( $options['ga-UID'] ) ? "'" . esc_js( $options['ga-UID'] ). "'" : 'false' ?>;
14
+ var advanced_ads_ga_anonymIP = <?php
15
+
16
+ if ( defined( 'ADVANCED_ADS_DISABLE_ANALYTICS_ANONYMIZE_IP' ) ) {
17
+ echo "false;\n";
18
+ } else {
19
+ echo "true;\n";
20
+ }
21
 
22
  if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && current_user_can( 'manage_options' ) ) {
23
  readfile( dirname( __FILE__ ) . '/script.js' );
modules/adblock-finder/public/script.js CHANGED
@@ -78,11 +78,15 @@
78
  })(window,document,'script','https://www.google-analytics.com/analytics.js','_advads_ga');
79
 
80
  _advads_ga( 'create', that.UID, 'auto', this.name );
 
 
 
81
  _advads_ga( that.name + '.send', data );
82
  } else {
83
  // someone has already created a variable, use it to avoid conflicts.
84
  window.console && window.console.log( "Advanced Ads Analytics >> using other's variable named `" + GoogleAnalyticsObject + "`" );
85
  window[GoogleAnalyticsObject]( 'create', that.UID, 'auto', this.name );
 
86
  window[GoogleAnalyticsObject]( that.name + '.send', data );
87
  }
88
  }
78
  })(window,document,'script','https://www.google-analytics.com/analytics.js','_advads_ga');
79
 
80
  _advads_ga( 'create', that.UID, 'auto', this.name );
81
+ if ( advanced_ads_ga_anonymIP ) {
82
+ _advads_ga( 'set', 'anonymizeIp', true );
83
+ }
84
  _advads_ga( that.name + '.send', data );
85
  } else {
86
  // someone has already created a variable, use it to avoid conflicts.
87
  window.console && window.console.log( "Advanced Ads Analytics >> using other's variable named `" + GoogleAnalyticsObject + "`" );
88
  window[GoogleAnalyticsObject]( 'create', that.UID, 'auto', this.name );
89
+ window[GoogleAnalyticsObject]( 'set', 'anonymizeIp', true );
90
  window[GoogleAnalyticsObject]( that.name + '.send', data );
91
  }
92
  }
modules/adblock-finder/public/script.min.js CHANGED
@@ -1 +1 @@
1
- advanced_ads_check_adblocker=function(t){function e(t){(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||function(t){return setTimeout(t,16)}).call(window,t)}var n=[],a=null;return e(function(){var t=document.createElement("div");t.innerHTML="&nbsp;",t.setAttribute("class","ad_unit ad-unit text-ad text_ad pub_300x250"),t.setAttribute("style","width: 1px !important; height: 1px !important; position: absolute !important; left: 0px !important; top: 0px !important; overflow: hidden !important;"),document.body.appendChild(t),e(function(){var e=window.getComputedStyle&&window.getComputedStyle(t),o=e&&e.getPropertyValue("-moz-binding");a=e&&"none"===e.getPropertyValue("display")||"string"==typeof o&&-1!==o.indexOf("about:");for(var i=0;i<n.length;i++)n[i](a);n=[]})}),function(t){if(null===a)return void n.push(t);t(a)}}(),function(){var t=function(t,e){this.name=t,this.UID=e,this.analyticsObject=null;var n=this,a={hitType:"event",eventCategory:"Advanced Ads",eventAction:"AdBlock",eventLabel:"Yes",nonInteraction:!0,transport:"beacon"};this.analyticsObject="string"==typeof GoogleAnalyticsObject&&"function"==typeof window[GoogleAnalyticsObject]&&window[GoogleAnalyticsObject],!1===this.analyticsObject?(!function(t,e,n,a,o,i,d){t.GoogleAnalyticsObject=o,t[o]=t[o]||function(){(t[o].q=t[o].q||[]).push(arguments)},t[o].l=1*new Date,i=e.createElement(n),d=e.getElementsByTagName(n)[0],i.async=1,i.src="https://www.google-analytics.com/analytics.js",d.parentNode.insertBefore(i,d)}(window,document,"script",0,"_advads_ga"),_advads_ga("create",n.UID,"auto",this.name),_advads_ga(n.name+".send",a)):(window.console&&window.console.log("Advanced Ads Analytics >> using other's variable named `"+GoogleAnalyticsObject+"`"),window[GoogleAnalyticsObject]("create",n.UID,"auto",this.name),window[GoogleAnalyticsObject](n.name+".send",a))};advanced_ads_check_adblocker(function(e){e&&"string"==typeof advanced_ads_ga_UID&&advanced_ads_ga_UID&&new t("advadsTracker",advanced_ads_ga_UID)})}();
1
+ advanced_ads_check_adblocker=function(t){function e(t){(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||function(t){return setTimeout(t,16)}).call(window,t)}var n=[],a=null;return e(function(){var t=document.createElement("div");t.innerHTML="&nbsp;",t.setAttribute("class","ad_unit ad-unit text-ad text_ad pub_300x250"),t.setAttribute("style","width: 1px !important; height: 1px !important; position: absolute !important; left: 0px !important; top: 0px !important; overflow: hidden !important;"),document.body.appendChild(t),e(function(){var e=window.getComputedStyle&&window.getComputedStyle(t),o=e&&e.getPropertyValue("-moz-binding");a=e&&"none"===e.getPropertyValue("display")||"string"==typeof o&&-1!==o.indexOf("about:");for(var i=0;i<n.length;i++)n[i](a);n=[]})}),function(t){if(null===a)return void n.push(t);t(a)}}(),function(){var t=function(t,e){this.name=t,this.UID=e,this.analyticsObject=null;var n=this,a={hitType:"event",eventCategory:"Advanced Ads",eventAction:"AdBlock",eventLabel:"Yes",nonInteraction:!0,transport:"beacon"};this.analyticsObject="string"==typeof GoogleAnalyticsObject&&"function"==typeof window[GoogleAnalyticsObject]&&window[GoogleAnalyticsObject],!1===this.analyticsObject?(!function(t,e,n,a,o,i,d){t.GoogleAnalyticsObject=o,t[o]=t[o]||function(){(t[o].q=t[o].q||[]).push(arguments)},t[o].l=1*new Date,i=e.createElement(n),d=e.getElementsByTagName(n)[0],i.async=1,i.src="https://www.google-analytics.com/analytics.js",d.parentNode.insertBefore(i,d)}(window,document,"script",0,"_advads_ga"),_advads_ga("create",n.UID,"auto",this.name),advanced_ads_ga_anonymIP&&_advads_ga("set","anonymizeIp",!0),_advads_ga(n.name+".send",a)):(window.console&&window.console.log("Advanced Ads Analytics >> using other's variable named `"+GoogleAnalyticsObject+"`"),window[GoogleAnalyticsObject]("create",n.UID,"auto",this.name),window[GoogleAnalyticsObject]("set","anonymizeIp",!0),window[GoogleAnalyticsObject](n.name+".send",a))};advanced_ads_check_adblocker(function(e){e&&"string"==typeof advanced_ads_ga_UID&&advanced_ads_ga_UID&&new t("advadsTracker",advanced_ads_ga_UID)})}();
modules/gadsense/admin/admin.php CHANGED
@@ -282,7 +282,12 @@ class Advanced_Ads_AdSense_Admin {
282
 
283
  // sanitize whatever option one wants to sanitize
284
  if(isset($options['adsense-id']) && $options['adsense-id'] != ''){
285
- if(0 !== strpos( $options['adsense-id'], 'pub-' )){
 
 
 
 
 
286
  // add settings error
287
  add_settings_error(
288
  'adsense-limit',
282
 
283
  // sanitize whatever option one wants to sanitize
284
  if(isset($options['adsense-id']) && $options['adsense-id'] != ''){
285
+ // remove "ca-" prefix if it was added by the user
286
+ if( 0 === strpos( $options['adsense-id'], 'ca-' ) ){
287
+ $options['adsense-id'] = str_replace( 'ca-', '', $options['adsense-id'] );
288
+ }
289
+
290
+ if( 0 !== strpos( $options['adsense-id'], 'pub-' ) ){
291
  // add settings error
292
  add_settings_error(
293
  'adsense-limit',
modules/gutenberg/config.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // module configuration
4
+
5
+ $path = dirname( __FILE__ );
6
+
7
+ return array(
8
+ 'classmap' => array(
9
+ 'Advanced_Ads_Gutenberg' => $path . '/includes/class-gutenberg.php',
10
+ ),
11
+ 'textdomain' => null,
12
+ );
modules/gutenberg/includes/class-gutenberg.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Advanced_Ads_Gutenberg {
4
+
5
+ private static $instance;
6
+
7
+ private static $css_class;
8
+
9
+ private function __construct() {
10
+ add_action( 'init', array( $this, 'init' ) );
11
+ add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
12
+ }
13
+
14
+ /**
15
+ * Register blocks
16
+ */
17
+ public function init() {
18
+ if ( !function_exists( 'register_block_type' ) ) {
19
+ // no Gutenberg, Abort
20
+ return;
21
+ }
22
+
23
+ register_block_type( 'advads/gblock', array(
24
+ 'editor_script' => ADVADS_BASE . '/gutenberg-ad',
25
+ 'render_callback' => array( $this, 'render_ad_selector' ),
26
+ ) );
27
+ }
28
+
29
+ /**
30
+ * register back end scripts
31
+ */
32
+ public function register_scripts() {
33
+ if ( !function_exists( 'register_block_type' ) ) {
34
+ // no Gutenberg, Abort
35
+ return;
36
+ }
37
+
38
+ wp_register_script(
39
+ ADVADS_BASE . '/gutenberg-ad',
40
+ ADVADS_BASE_URL . 'modules/gutenberg/js/advanced-ads.block.js',
41
+ array( 'wp-blocks', 'wp-element' )
42
+ );
43
+
44
+ $model = Advanced_Ads::get_instance()->get_model();
45
+
46
+ $all_ads = Advanced_Ads::get_ads( array( 'post_status' => array( 'publish' ), 'orderby' => 'title', 'order' => 'ASC' ) );
47
+ $all_groups = $model->get_ad_groups();
48
+ $all_placements = Advanced_Ads::get_ad_placements_array();
49
+
50
+ $ads = array();
51
+ $groups = array();
52
+ $placements = array();
53
+
54
+ foreach ( $all_ads as $ad ) {
55
+ $ads[] = array( 'id' => $ad->ID, 'title' => $ad->post_title );
56
+ }
57
+
58
+ foreach ( $all_groups as $gr ) {
59
+ $groups[] = array( 'id' => $gr->term_id, 'name' => $gr->name );
60
+ }
61
+
62
+ if ( is_array( $all_placements ) ) {
63
+ ksort( $all_placements );
64
+ }
65
+
66
+ foreach( $all_placements as $key => $value ) {
67
+ if ( 'sidebar_widget' == $value['type'] ) {
68
+ $placements[] = array( 'id' => $key, 'name' => $value['name'] );
69
+ }
70
+ }
71
+
72
+ if ( empty( $placements ) ) {
73
+ $placements = false;
74
+ }
75
+
76
+ $i18n = array(
77
+ '--empty--' => __( '--empty--', 'advanced-ads' ),
78
+ 'advads' => __( 'Advanced Ads', 'advanced-ads' ),
79
+ 'ads' => __( 'Ads', 'advanced-ads' ),
80
+ 'adGroups' => __( 'Ad Groups', 'advanced-ads' ),
81
+ 'placements' => __( 'Placements', 'advanced-ads' ),
82
+ );
83
+
84
+ $inline_script = wp_json_encode(
85
+ array(
86
+ 'ads' => $ads,
87
+ 'groups' => $groups,
88
+ 'placements' => $placements,
89
+ 'editLinks' => array(
90
+ 'group' => admin_url( 'admin.php?page=advanced-ads-groups' ),
91
+ 'placement' => admin_url( 'admin.php?page=advanced-ads-placements' ),
92
+ 'ad' => admin_url( 'post.php?post=%ID%&action=edit' ),
93
+ ),
94
+ 'i18n' => $i18n
95
+ )
96
+ );
97
+
98
+ // put the inline code with the global variable right before the block's JS file
99
+ wp_add_inline_script( ADVADS_BASE . '/gutenberg-ad', 'var advadsGutenberg = ' . $inline_script, 'before' );
100
+
101
+ }
102
+
103
+ /**
104
+ * Server side rendering for single ad block
105
+ */
106
+ public static function render_ad_selector( $attr ) {
107
+ ob_start();
108
+
109
+ if ( !isset( $attr['itemID'] ) ) {
110
+ ob_end_clean();
111
+ return '';
112
+ }
113
+
114
+ // the item is an ad
115
+ if ( 0 === strpos( $attr['itemID'], 'ad_' ) ) {
116
+
117
+ $id = substr( $attr['itemID'], 3 );
118
+
119
+ // add CSS classes to the wrapper via filter
120
+ if ( isset( $attr['className'] ) ) {
121
+ echo get_ad( absint( $id ), array( 'output' => array( 'class' => explode( ' ', $attr['className'] ) ) ) );
122
+ } else {
123
+ the_ad( absint( $id ) );
124
+ }
125
+
126
+ } elseif ( 0 === strpos( $attr['itemID'], 'group_' ) ) {
127
+
128
+ $id = substr( $attr['itemID'], 6 );
129
+
130
+ if ( isset( $attr['className'] ) ) {
131
+ echo get_ad_group( $id, array( 'output' => array( 'class' => explode( ' ', $attr['className'] ) ) ) );
132
+ } else {
133
+ the_ad_group( $id );
134
+ }
135
+
136
+ } elseif ( 0 === strpos( $attr['itemID'], 'place_' ) ) {
137
+
138
+ $id = substr( $attr['itemID'], 6 );
139
+
140
+ if ( isset( $attr['className'] ) ) {
141
+ echo get_ad_placement( $id, array( 'output' => array( 'class' => explode( ' ', $attr['className'] ) ) ) );
142
+ } else {
143
+ the_ad_placement( $id );
144
+ }
145
+
146
+ }
147
+
148
+ return ob_get_clean();
149
+ }
150
+
151
+ /**
152
+ * Return the unique instance
153
+ */
154
+ public static function get_instance() {
155
+ if ( null == self::$instance ) {
156
+ self::$instance = new self;
157
+ }
158
+ return self::$instance;
159
+ }
160
+
161
+ }
modules/gutenberg/js/advanced-ads.block.js ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ;(function(wp){
2
+
3
+ /**
4
+ * Shortcut variables
5
+ */
6
+ var el = wp.element.createElement,
7
+ registerBlockType = wp.blocks.registerBlockType;
8
+
9
+ /**
10
+ * Register the single ad block type
11
+ */
12
+ registerBlockType( 'advads/gblock', {
13
+
14
+ title: advadsGutenberg.i18n.advads,
15
+
16
+ icon: 'chart-line',
17
+
18
+ category: 'common',
19
+
20
+ attributes: {
21
+ itemID: {
22
+ type: 'string',
23
+ },
24
+ },
25
+
26
+ edit: function( props ) {
27
+
28
+ var itemID = props.attributes.itemID;
29
+
30
+ /**
31
+ * Update property on submit
32
+ */
33
+ function setItemID( event ) {
34
+ var selected = event.target.querySelector( 'option:checked' );
35
+ props.setAttributes( { itemID: selected.value } );
36
+ event.preventDefault();
37
+ }
38
+
39
+ // the form children elements
40
+ var children = [];
41
+
42
+ // argument list (in array form) for the children creation
43
+ var args = [];
44
+ var ads = [];
45
+ var groups = [];
46
+ var placements = [];
47
+
48
+ args.push( 'select' );
49
+ args.push( { value: itemID, onChange: setItemID } );
50
+ args.push( el( 'option', null, advadsGutenberg.i18n['--empty--'] ) );
51
+
52
+ for ( var adID in advadsGutenberg.ads ) {
53
+ if ( 'undefined' == typeof advadsGutenberg.ads[adID].id ) continue;
54
+ ads.push( el( 'option', {value: 'ad_' + advadsGutenberg.ads[adID].id}, advadsGutenberg.ads[adID].title ) );
55
+ }
56
+
57
+ for ( var GID in advadsGutenberg.groups ) {
58
+ if ( 'undefined' == typeof advadsGutenberg.groups[GID].id ) continue;
59
+ groups.push( el( 'option', {value: 'group_' + advadsGutenberg.groups[GID]['id'] }, advadsGutenberg.groups[GID]['name'] ) );
60
+
61
+ }
62
+
63
+ if ( advadsGutenberg.placements ) {
64
+ for ( var pid in advadsGutenberg.placements ) {
65
+ if ( 'undefined' == typeof advadsGutenberg.placements[pid].id ) continue;
66
+ placements.push( el( 'option', {value: 'place_' + advadsGutenberg.placements[pid]['id']}, advadsGutenberg.placements[pid]['name'] ) );
67
+ }
68
+ }
69
+
70
+ if ( advadsGutenberg.placements ) {
71
+ args.push( el( 'optgroup', {label: advadsGutenberg.i18n['placements']}, placements ) );
72
+ }
73
+
74
+ args.push( el( 'optgroup', {label: advadsGutenberg.i18n['adGroups']}, groups ) );
75
+
76
+ args.push( el( 'optgroup', {label: advadsGutenberg.i18n['ads']}, ads ) );
77
+
78
+ // add a <label /> first and style it.
79
+ children.push( el( 'label', {style:{fontWeight:'bold',display:'block'}}, advadsGutenberg.i18n.advads ) );
80
+
81
+ // then add the <select /> input with its own children
82
+ children.push( el.apply( null, args ) );
83
+
84
+ if ( itemID && advadsGutenberg.i18n['--empty--'] != itemID ) {
85
+
86
+ var url = '#';
87
+ if ( 0 === itemID.indexOf( 'place_' ) ) {
88
+ url = advadsGutenberg.editLinks.placement;
89
+ } else if ( 0 === itemID.indexOf( 'group_' ) ) {
90
+ url = advadsGutenberg.editLinks.group;
91
+ } else if ( 0 === itemID.indexOf( 'ad_' ) ) {
92
+ var _adID = itemID.substr(3);
93
+ url = advadsGutenberg.editLinks.ad.replace( '%ID%', _adID );
94
+ }
95
+
96
+ children.push(
97
+ el(
98
+ 'a',
99
+ {
100
+ class: 'dashicons dashicons-external',
101
+ style: {
102
+ 'vetical-align': 'middle',
103
+ margin: 5,
104
+ },
105
+ href: url,
106
+ target: '_blank',
107
+ }
108
+ )
109
+ );
110
+
111
+ }
112
+ // return the complete form
113
+ return el( 'form', { onSubmit: setItemID }, children );
114
+
115
+ },
116
+
117
+ save: function() {
118
+ // server side rendering
119
+ return null;
120
+ },
121
+
122
+ } );
123
+
124
+ })(window.wp);
modules/gutenberg/main.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'Advanced_Ads', false ) ) {
4
+ Advanced_Ads_Gutenberg::get_instance();
5
+ }
public/class-advanced-ads.php CHANGED
@@ -408,8 +408,8 @@ class Advanced_Ads {
408
  }
409
 
410
  // check if admin allows injection in all places
411
- if( ! isset( $options['content-injection-everywhere'] ) ){
412
- // check if this is a singular page within the loop or an amp page
413
  $is_amp = advads_is_amp();
414
  if ( ( ! is_singular( $public_post_types ) && ! is_feed() ) || ( ! $is_amp && ! in_the_loop() ) ) { return $content; }
415
  } else {
@@ -528,7 +528,8 @@ class Advanced_Ads {
528
  }
529
 
530
  // check bots if option is enabled
531
- if( isset($options['block-bots']) && $options['block-bots'] && $this->is_bot() ) {
 
532
  return false;
533
  }
534
 
@@ -563,6 +564,29 @@ class Advanced_Ads {
563
  return true;
564
  }
565
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
  /**
567
  * Registers ad post type and group taxonomies
568
  *
408
  }
409
 
410
  // check if admin allows injection in all places
411
+ if( ! isset( $options['content-injection-everywhere'] ) || 0 === $options['content-injection-everywhere'] ){
412
+ // check if this is a singular page within the loop or an AMP page
413
  $is_amp = advads_is_amp();
414
  if ( ( ! is_singular( $public_post_types ) && ! is_feed() ) || ( ! $is_amp && ! in_the_loop() ) ) { return $content; }
415
  } else {
528
  }
529
 
530
  // check bots if option is enabled
531
+ if ( ( isset( $options['block-bots'] ) && $options['block-bots']
532
+ && ! $this->is_cache_bot() && $this->is_bot() ) ) {
533
  return false;
534
  }
535
 
564
  return true;
565
  }
566
 
567
+ /**
568
+ * check if the current user is a bot prepopulating the cache
569
+ * ads should be loaded for the bot, because they should show up on the cached site
570
+ *
571
+ * @return bool
572
+ */
573
+ public function is_cache_bot(){
574
+ if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] !== '' ) {
575
+ // WP Rocket
576
+ if ( false !== strpos( $_SERVER['HTTP_USER_AGENT'], 'wprocketbot' ) ) {
577
+ return true;
578
+ }
579
+
580
+ // WP Super Cache.
581
+ $wp_useragent = apply_filters( 'http_headers_useragent', 'WordPress/' . get_bloginfo( 'version' ) . '; ' . get_bloginfo( 'url' ) );
582
+ if ( $wp_useragent === $_SERVER['HTTP_USER_AGENT'] ) {
583
+ return true;
584
+ }
585
+ }
586
+
587
+ return false;
588
+ }
589
+
590
  /**
591
  * Registers ad post type and group taxonomies
592
  *
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.28
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -163,6 +163,14 @@ How to install the plugin and get it working?
163
 
164
  == Frequently Asked Questions ==
165
 
 
 
 
 
 
 
 
 
166
  = Which ad networks are supported? =
167
 
168
  Advanced Ads is compatible with all ad networks and banners from affiliate programs like Google AdSense, Chitika, Clickbank, Amazon, and also Google Double Click (DFP), media.net.
@@ -212,8 +220,8 @@ There is a dedicated Flash ad type in [Pro](https://wpadvancedads.com/add-ons/ad
212
 
213
  = Is the plugin compatible with site builders? =
214
 
215
- Yes. It works out of the box with all site builders that allow shortcodes or widgets, like SiteOrigin, Beaver Builder, Visual Composer, and others.
216
- There is also a [free add-on to support Visual Composer](https://wordpress.org/plugins/ads-for-visual-composer/).
217
 
218
  = Will ads show up for ad block users? =
219
 
@@ -240,6 +248,19 @@ Yes. Advanced Ads is based on WordPress standards and therefore easily customiza
240
 
241
  == Changelog ==
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  = 1.8.28 =
244
 
245
  * prevent possible issue with empty groups
5
  Requires at least: 4.6
6
  Tested up to: 4.9
7
  Requires PHP: 5.2
8
+ Stable tag: 1.8.29
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
163
 
164
  == Frequently Asked Questions ==
165
 
166
+ = What about my users’ privacy and GDPR? =
167
+
168
+ Advanced Ads does neither save personal information (e.g., an IP address) in your database nor cookies in the visitor’s browser.
169
+
170
+ Third party services like Google Analytics are disabled by default.
171
+
172
+ You can learn more about how Advanced Ads and its add-ons handles data and privacy of your visitors [on this page](https://wpadvancedads.com/manual/privacy-information-for-users/).
173
+
174
  = Which ad networks are supported? =
175
 
176
  Advanced Ads is compatible with all ad networks and banners from affiliate programs like Google AdSense, Chitika, Clickbank, Amazon, and also Google Double Click (DFP), media.net.
220
 
221
  = Is the plugin compatible with site builders? =
222
 
223
+ Yes. It works out of the box with all site builders that allow shortcodes or widgets, like SiteOrigin, Beaver Builder, WPBakery Page Builder (formerly Visual Composer), and others.
224
+ There is also a [free add-on to support the WPBakery Page Builder (formerly Visual Composer)](https://wordpress.org/plugins/ads-for-visual-composer/).
225
 
226
  = Will ads show up for ad block users? =
227
 
248
 
249
  == Changelog ==
250
 
251
+ = 1.8.29 =
252
+
253
+ * added ad block that works with Gutenberg version 2.8.0
254
+ * allowed to use uppercase letters in wrapper ID
255
+ * do not count cache preload features of caching plugins as bots
256
+ * removed orange border for just updated placements since it implicated that there was something wrong
257
+ * use AnonymizeIP by default for ad block counter feature
258
+ * remove "ca-" from AdSense publisher ID dynamically if entered by accident
259
+ * fixed possible content breaking by empty Content placement
260
+ * fixed issue with Pagination condition in Pro
261
+ * fixed minor license check issue
262
+ * fixed issue with legacy value for the Unlimited Ad Injection option
263
+
264
  = 1.8.28 =
265
 
266
  * prevent possible issue with empty groups