PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.42.1
Advanced Ads – Ad Manager & AdSense v1.42.1
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 / classes / compatibility.php
advanced-ads / classes Last commit date
Advanced_Ads_Modal.php 3 years ago EDD_SL_Plugin_Updater.php 4 years ago ad-ajax.php 3 years ago ad-debug.php 3 years ago ad-expiration.php 3 years ago ad-health-notices.php 3 years ago ad-model.php 3 years ago ad-select.php 3 years ago ad.php 3 years ago ad_ajax_callbacks.php 3 years ago ad_group.php 3 years ago ad_placements.php 3 years ago ad_type_abstract.php 3 years ago ad_type_content.php 3 years ago ad_type_dummy.php 3 years ago ad_type_group.php 3 years ago ad_type_image.php 3 years ago ad_type_plain.php 3 years ago checks.php 3 years ago compatibility.php 3 years ago display-conditions.php 3 years ago filesystem.php 3 years ago frontend-notices.php 3 years ago frontend_checks.php 3 years ago in-content-injector.php 3 years ago inline-css.php 3 years ago plugin.php 3 years ago upgrades.php 6 years ago utils.php 3 years ago visitor-conditions.php 3 years ago widget.php 3 years ago
compatibility.php
382 lines
1 <?php
2 /**
3 * Compatibility fixes with other plugins.
4 */
5 class Advanced_Ads_Compatibility {
6 /**
7 * Array that holds strings that should not be optimized by other plugins.
8 *
9 * @var array
10 */
11 private $critical_inline_js;
12
13 /**
14 * Advanced_Ads_Compatibility constructor.
15 */
16 public function __construct() {
17 // Elementor plugin.
18 if ( defined( 'ELEMENTOR_VERSION' ) ) {
19 add_filter(
20 'advanced-ads-placement-content-injection-xpath',
21 [
22 $this,
23 'content_injection_elementor',
24 ],
25 10,
26 1
27 );
28 }
29 // WP Rocket
30 add_filter( 'rocket_excluded_inline_js_content', [ $this, 'rocket_exclude_inline_js' ] );
31 add_filter( 'rocket_delay_js_exclusions', [ $this, 'rocket_exclude_inline_js' ] );
32 // WPML.
33 add_filter( 'wpml_admin_language_switcher_active_languages', [ $this, 'wpml_language_switcher' ] );
34 // WordPress SEO by Yoast.
35 add_filter( 'wpseo_sitemap_entry', [ $this, 'wordpress_seo_noindex_ad_attachments' ], 10, 3 );
36 // Add shortcode for MailPoet.
37 add_filter( 'mailpoet_newsletter_shortcode', [ 'Advanced_Ads_Compatibility', 'mailpoet_ad_shortcode' ], 10, 5 );
38
39 // Enable Advanced Custom Fields on ad edit pages.
40 if ( class_exists( 'ACF', false ) ) {
41 add_filter( 'advanced-ads-ad-edit-allowed-metaboxes', [ $this, 'advanced_custom_fields_box' ] );
42 }
43
44 add_action( 'admin_enqueue_scripts', [ $this, 'admin_dequeue_scripts_and_styles' ], 100 );
45
46 if ( defined( 'BORLABS_COOKIE_VERSION' ) ) {
47 // Check if Verification code & Auto ads ads can be displayed.
48 add_filter( 'advanced-ads-can-display-ads-in-header', [ $this, 'borlabs_cookie_can_add_auto_ads_code' ], 10 );
49 }
50
51 // Make sure inline JS in head is executed when Complianz is set to block JS.
52 add_filter( 'cmplz_script_class', [ $this, 'complianz_exclude_inline_js' ], 10, 2 );
53
54 $this->critical_inline_js = $this->critical_inline_js();
55 }
56
57 /**
58 * Modify xPath expression for Elementor plugin.
59 * The plugin does not wrap newly created text in 'p' tags.
60 *
61 * @param string $tag xpath tag.
62 * @return string xPath expression
63 */
64 public function content_injection_elementor( $tag ) {
65 if ( 'p' === $tag ) {
66 // 'p' or 'div.elementor-widget-text-editor' without nested 'p'
67 $tag = "*[self::p or self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' elementor-widget-text-editor ') and not(descendant::p)]]";
68 }
69
70 return $tag;
71 }
72
73 /**
74 * Prevent the 'advanced_ads_ready' function declaration from being merged with other JS
75 * and outputted into the footer. This is needed because WP Rocket does not output all
76 * the code that depends on this function into the footer.
77 *
78 * @param array $exclusions Patterns to match in inline JS content.
79 *
80 * @return array
81 */
82 public function rocket_exclude_inline_js( $exclusions ) {
83 return array_merge( $exclusions, $this->critical_inline_js );
84 }
85
86 /**
87 * Prevent Complianz from suppressing our head inline script.
88 *
89 * @param string $class the class Complianz adds to the script, `cmplz-script` for prevented scripts, `cmplz-native` for allowed.
90 * @param string $total_match the script string.
91 *
92 * @return string
93 */
94 public function complianz_exclude_inline_js( $class, $total_match ) {
95 if ( $class === 'cmplz-native' ) {
96 return $class;
97 }
98 foreach ( $this->critical_inline_js as $critical_inline_js ) {
99 if ( strpos( $total_match, $critical_inline_js ) !== false ) {
100 return 'cmplz-native';
101 }
102 }
103
104 return $class;
105 }
106
107 /**
108 * Compatibility with WPML
109 * show only all languages in language switcher on Advanced Ads pages if ads and groups are translated
110 *
111 * @param array $active_languages languages that can be used in language switcher.
112 * @return array
113 */
114 public function wpml_language_switcher( $active_languages ) {
115 global $sitepress;
116 $screen = get_current_screen();
117 if ( ! isset( $screen->id ) ) {
118 return $active_languages;
119 }
120
121 switch ( $screen->id ) {
122 // check if we are on a group edit page and ad group translations are disabled.
123 case 'advanced-ads_page_advanced-ads-groups':
124 $translatable_taxonomies = $sitepress->get_translatable_taxonomies();
125 if ( ! is_array( $translatable_taxonomies ) || ! in_array( 'advanced_ads_groups', $translatable_taxonomies, true ) ) {
126 return [];
127 }
128 break;
129 // check if Advanced Ads ad post type is translatable.
130 case 'edit-advanced_ads': // overview page.
131 case 'advanced_ads': // edit page.
132 $translatable_documents = $sitepress->get_translatable_documents();
133 if ( empty( $translatable_documents['advanced_ads'] ) ) {
134 return [];
135 }
136 break;
137 }
138
139 return $active_languages;
140 }
141
142 /**
143 * WordPress SEO: remove attachments attached to ads from `/attachment-sitemap.xml`.
144 *
145 * @param array $url Array of URL parts.
146 * @param string $type URL type.
147 * @param object $post WP_Post object of attachment.
148 * @return array|bool Unmodified array of URL parts or false to remove URL.
149 */
150 public function wordpress_seo_noindex_ad_attachments( $url, $type, $post ) {
151 if ( 'post' !== $type ) {
152 return $url;
153 }
154
155 static $ad_ids = null;
156 if ( null === $ad_ids ) {
157 $ad_ids = Advanced_Ads::get_instance()->get_model()->get_ads(
158 [
159 'post_status' => 'any',
160 'fields' => 'ids',
161 ]
162 );
163 }
164
165 if ( isset( $post->post_parent ) && in_array( $post->post_parent, $ad_ids, true ) ) {
166 return false;
167 }
168
169 return $url;
170 }
171
172 /**
173 * Display an ad or ad group in a newsletter created by MailPoet.
174 * e.g., [custom:ad:123] to display ad with the ID 123
175 * [custom:ad_group:345] to display ad group with the ID 345
176 *
177 * @param string $shortcode shortcode that placed the ad.
178 * @param mixed $newsletter unused.
179 * @param mixed $subscriber unused.
180 * @param mixed $queue unused.
181 * @param string $newsletter_body unused.
182 *
183 * @return string
184 */
185 public static function mailpoet_ad_shortcode( $shortcode, $newsletter, $subscriber, $queue, $newsletter_body ) {
186
187 // display an ad group.
188 if ( 0 === strpos( $shortcode, '[custom:ad_group:' ) ) {
189 // get ad group ID.
190 preg_match( '/\d+/', $shortcode, $matches );
191 $group_id = $matches[0];
192
193 // is returning an empty string when the ad group is not found good UI?
194 if ( empty( $group_id ) ) {
195 return '';
196 }
197
198 // only display if the ad group type could work, i.e. default (random) and ordered.
199 $ad_group = new Advanced_Ads_Group( $group_id );
200 if ( isset( $ad_group->type ) && in_array( $ad_group->type, [ 'default', 'ordered' ], true ) ) {
201 return get_ad_group( $group_id );
202 }
203
204 return '';
205
206 // display individual ad.
207 } elseif ( 0 === strpos( $shortcode, '[custom:ad:' ) ) {
208 // get ad ID.
209 preg_match( '/\d+/', $shortcode, $matches );
210 $ad_id = $matches[0];
211
212 // is returning an empty string when the ad is not found good UI?
213 if ( empty( $ad_id ) ) {
214 return '';
215 }
216
217 $ad = \Advanced_Ads\Ad_Repository::get( $ad_id );
218 // only display if the ad type could work, i.e. plain text and image ads.
219 if ( isset( $ad->type ) && in_array( $ad->type, [ 'plain', 'image' ], true ) ) {
220 return get_ad( $ad_id );
221 }
222
223 return '';
224 } else {
225 // always return the shortcode if it doesn't match your own!
226 return $shortcode;
227 }
228 }
229
230 /**
231 * Check if placements of type other than `header` can be injected during `wp_head` action.
232 */
233 public static function can_inject_during_wp_head() {
234 // the "Thrive Theme Builder" theme.
235 if ( did_action( 'before_theme_builder_template_render' ) && ! did_action( 'after_theme_builder_template_render' ) ) {
236 return true;
237 }
238 return false;
239 }
240
241 /**
242 * Dequeue scripts and styles to prevent layout issues.
243 */
244 public function admin_dequeue_scripts_and_styles() {
245 if ( ! Advanced_Ads_Admin::screen_belongs_to_advanced_ads() ) {
246 return;
247 }
248
249 // Dequeue the css file enqueued by the JNews theme.
250 if ( defined( 'JNEWS_THEME_URL' ) ) {
251 wp_dequeue_style( 'jnews-admin' );
252 }
253 }
254
255 /**
256 * Check if Adsense Auto ads code can be added to the header.
257 *
258 * @param bool $can_display if the ad can already be displayed.
259 * @return bool
260 */
261 public function borlabs_cookie_can_add_auto_ads_code( $can_display ) {
262 if ( ! $can_display ) {
263 return false;
264 }
265
266 return ! self::borlabs_cookie_adsense_auto_ads_code_exists();
267 }
268
269 /**
270 * Check if Adsense Auto ads code is added by the Borlabs Cookie plugin.
271 *
272 * This allows to prevent the "Only one 'enable_page_level_ads' allowed per page" error
273 * that makes impossible to close the "Privacy Preference" window created by the "Borlabs Cookie" plugin.
274 *
275 * @return bool
276 */
277 public static function borlabs_cookie_adsense_auto_ads_code_exists() {
278 // Cache the result in order to perform the check only once.
279 static $result = null;
280
281 if ( null !== $result ) {
282 return $result;
283 }
284
285 // Set the `autoload` param to `true` so that the class loads both in frontend and backend.
286 if ( class_exists( '\BorlabsCookie\Cookie\Frontend\Cookies', true ) ) {
287 try {
288 $refl_cookies = new ReflectionClass( '\BorlabsCookie\Cookie\Frontend\Cookies' );
289
290 if ( $refl_cookies->hasMethod( 'getInstance' ) && $refl_cookies->hasMethod( 'getAllCookieGroups' ) ) {
291 $instance = $refl_cookies->getMethod( 'getInstance' );
292 $cookie_groups = $refl_cookies->getMethod( 'getAllCookieGroups' );
293
294 if ( $instance->isPublic() && $instance->isStatic() && $cookie_groups->isPublic() ) {
295 $all_cookies = BorlabsCookie\Cookie\Frontend\Cookies::getInstance()->getAllCookieGroups();
296 }
297 }
298 } catch ( Exception $e ) {
299 $result = false;
300 return $result;
301 }
302 }
303
304 if ( empty( $all_cookies ) ) {
305 $result = false;
306 return $result;
307 }
308
309 foreach ( $all_cookies as $cookie_group_data ) {
310 if ( ! empty( $cookie_group_data->group_id ) && 'marketing' === $cookie_group_data->group_id
311 && ! empty( $cookie_group_data->cookies ) ) {
312 foreach ( $cookie_group_data->cookies as $cookie_data ) {
313 if ( ! empty( $cookie_data->cookie_id ) && 'google-adsense' === $cookie_data->cookie_id
314 && ! empty( $cookie_data->opt_in_js ) ) {
315 $opt_in_js = $cookie_data->opt_in_js;
316 }
317 }
318 }
319 }
320
321 if ( empty( $opt_in_js ) ) {
322 $result = false;
323 return $result;
324 }
325
326 $result = preg_match( '/<script[^>]+data-ad-client/', $opt_in_js ) || false !== strpos( $opt_in_js, 'enable_page_level_ads:' );
327 return $result;
328 }
329
330 /**
331 * Whitelist meta boxes created by the Advanced Custom Fields plugin on the ad edit pages
332 * when they are dedicated for the "Ad" post type.
333 *
334 * @param array $meta_boxes already whitelisted meta boxes.
335 * @return array
336 */
337 public function advanced_custom_fields_box( $meta_boxes ) {
338
339 // fixes an issue reported when ACF class exists, but this function does not
340 if ( ! function_exists( 'acf_get_field_groups' ) ) {
341 return $meta_boxes;
342 }
343
344 // load ACF field groups dedicated to the Advanced Ads post type
345 $groups = acf_get_field_groups( [ 'post_type' => Advanced_Ads::POST_TYPE_SLUG ] );
346
347 if ( is_array( $groups ) && $groups ) {
348 foreach ( $groups as $_group ) {
349 if ( isset( $_group['key'] ) ) {
350 $meta_boxes[] = 'acf-' . $_group['key'];
351 }
352 }
353 }
354
355 return $meta_boxes;
356 }
357
358 /**
359 * Get an array of strings to exclude when plugins "optimize" JS.
360 *
361 * @return array
362 */
363 private function critical_inline_js() {
364 $frontend_prefix = Advanced_Ads_Plugin::get_instance()->get_frontend_prefix();
365 $default = [
366 sprintf( 'id="%sready"', $frontend_prefix ),
367 ];
368 /**
369 * Filters an array of strings of (inline) JavaScript "identifiers" that should not be "optimized"/delayed etc.
370 *
371 * @param array $default Array of excluded patterns.
372 */
373 $exclusions = apply_filters( 'advanced-ads-compatibility-critical-inline-js', $default, $frontend_prefix );
374
375 if ( ! is_array( $exclusions ) ) {
376 $exclusions = $default;
377 }
378
379 return $exclusions;
380 }
381 }
382