PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 14.9.2
Jetpack – WP Security, Backup, Speed, & Growth v14.9.2
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / wordads / class-wordads.php
jetpack / modules / wordads Last commit date
css 1 year ago js 1 year ago php 1 year ago class-wordads.php 1 year ago
class-wordads.php
1062 lines
1 <?php
2 /**
3 * Main WordAds file.
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Status\Host;
9
10 define( 'WORDADS_ROOT', __DIR__ );
11 define( 'WORDADS_BASENAME', plugin_basename( __FILE__ ) );
12 define( 'WORDADS_FILE_PATH', WORDADS_ROOT . '/' . basename( __FILE__ ) );
13 define( 'WORDADS_URL', plugins_url( '/', __FILE__ ) );
14 define( 'WORDADS_API_TEST_ID', '26942' );
15 define( 'WORDADS_API_TEST_ID2', '114160' );
16
17 require_once WORDADS_ROOT . '/php/class-wordads-sidebar-widget.php';
18 require_once WORDADS_ROOT . '/php/class-wordads-api.php';
19 require_once WORDADS_ROOT . '/php/class-wordads-cron.php';
20 require_once WORDADS_ROOT . '/php/class-wordads-california-privacy.php';
21 require_once WORDADS_ROOT . '/php/class-wordads-ccpa-do-not-sell-link-widget.php';
22 require_once WORDADS_ROOT . '/php/class-wordads-consent-management-provider.php';
23 require_once WORDADS_ROOT . '/php/class-wordads-formats.php';
24 require_once WORDADS_ROOT . '/php/class-wordads-smart.php';
25 require_once WORDADS_ROOT . '/php/class-wordads-shortcode.php';
26
27 /**
28 * Primary WordAds class.
29 */
30 class WordAds {
31
32 /**
33 * Ads parameters.
34 *
35 * @var WordAds_Params
36 */
37 public $params = null;
38
39 /**
40 * Ads.
41 *
42 * @var array
43 */
44 public $ads = array();
45
46 /**
47 * Array of supported ad types.
48 *
49 * @var array
50 */
51 public static $ad_tag_ids = array(
52 'mrec' => array(
53 'tag' => '300x250_mediumrectangle',
54 'height' => '250',
55 'width' => '300',
56 ),
57 'leaderboard' => array(
58 'tag' => '728x90_leaderboard',
59 'height' => '90',
60 'width' => '728',
61 ),
62 'mobile_leaderboard' => array(
63 'tag' => '320x50_mobileleaderboard',
64 'height' => '50',
65 'width' => '320',
66 ),
67 'wideskyscraper' => array(
68 'tag' => '160x600_wideskyscraper',
69 'height' => '600',
70 'width' => '160',
71 ),
72 );
73
74 /**
75 * Mapping array of location slugs to placement ids
76 *
77 * @var array
78 */
79 public static $ad_location_ids = array(
80 'top' => 110,
81 'belowpost' => 120,
82 'belowpost2' => 130,
83 'sidebar' => 140,
84 'widget' => 150,
85 'gutenberg' => 200,
86 'inline' => 310,
87 'inline-plugin' => 320,
88 );
89
90 /**
91 * Mapping array of form factor slugs to form factor ids
92 *
93 * @var array
94 */
95 public static $form_factor_ids = array(
96 'square' => '001', // 250x250
97 'leaderboard' => '002', // 728x90
98 'skyscraper' => '003', // 120x600
99 );
100
101 /**
102 * Counter to enable unique, sequential section IDs for all amp-ad units
103 *
104 * @var int
105 */
106 public static $amp_section_id = 1;
107
108 /**
109 * Solo unit CSS string.
110 *
111 * @var string
112 */
113 public static $solo_unit_css = 'float:left;margin-right:5px;margin-top:0;';
114
115 /**
116 * Checks for AMP support and returns true iff active & AMP request
117 *
118 * @return boolean True if supported AMP request
119 *
120 * @since 7.5.0
121 */
122 public static function is_amp() {
123 return class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
124 }
125
126 /**
127 * Increment the AMP section ID and return the value
128 *
129 * @return int
130 */
131 public static function get_amp_section_id() {
132 return self::$amp_section_id++;
133 }
134
135 /**
136 * Convenience function for grabbing options from params->options
137 *
138 * @param string $option the option to grab.
139 * @param mixed $default (optional).
140 * @return mixed option or $default if not set
141 *
142 * @since 4.5.0
143 */
144 public function option( $option, $default = false ) {
145 if ( ! isset( $this->params->options[ $option ] ) ) {
146 return $default;
147 }
148
149 return $this->params->options[ $option ];
150 }
151
152 /**
153 * Returns the ad tag property array for supported ad types.
154 *
155 * @return array array with ad tags
156 *
157 * @since 7.1.0
158 */
159 public function get_ad_tags() {
160 return self::$ad_tag_ids;
161 }
162
163 /**
164 * Returns the solo css for unit
165 *
166 * @return string the special css for solo units
167 *
168 * @since 7.1.0
169 */
170 public function get_solo_unit_css() {
171 return self::$solo_unit_css;
172 }
173
174 /**
175 * Instantiate the plugin
176 *
177 * @since 4.5.0
178 */
179 public function __construct() {
180 add_action( 'wp', array( $this, 'init' ) );
181 add_action( 'rest_api_init', array( $this, 'init' ) );
182 add_action( 'widgets_init', array( $this, 'widget_callback' ) );
183
184 if ( is_admin() ) {
185 WordAds_California_Privacy::init_ajax_actions();
186 WordAds_Consent_Management_Provider::init_ajax_actions();
187 }
188 }
189
190 /**
191 * Code to run on WordPress 'init' hook
192 *
193 * @since 4.5.0
194 */
195 public function init() {
196 require_once WORDADS_ROOT . '/php/class-wordads-params.php';
197 $this->params = new WordAds_Params();
198
199 if ( $this->should_bail() || self::is_infinite_scroll() ) {
200 return;
201 }
202
203 if ( is_admin() ) {
204 require_once WORDADS_ROOT . '/php/class-wordads-admin.php';
205 return;
206 }
207
208 $this->insert_adcode();
209
210 // Include California Privacy Act related features if enabled.
211 if ( $this->params->options['wordads_ccpa_enabled'] ) {
212 WordAds_California_Privacy::init();
213 }
214
215 // Initialize CMP if enabled.
216 if ( isset( $this->params->options['wordads_cmp_enabled'] ) && $this->params->options['wordads_cmp_enabled'] ) {
217 WordAds_Consent_Management_Provider::init();
218 }
219
220 // Initialize [wordads] shortcode.
221 WordAds_Shortcode::init();
222
223 // Initialize Smart.
224 WordAds_Smart::instance()->init( $this->params );
225
226 if ( ( isset( $_SERVER['REQUEST_URI'] ) && '/ads.txt' === $_SERVER['REQUEST_URI'] )
227 || ( site_url( 'ads.txt', 'relative' ) === $_SERVER['REQUEST_URI'] ) ) {
228
229 $ads_txt_transient = get_transient( 'wordads_ads_txt' );
230
231 if ( false === ( $ads_txt_transient ) ) {
232 $wordads_ads_txt = WordAds_API::get_wordads_ads_txt();
233 $ads_txt_transient = is_wp_error( $wordads_ads_txt ) ? '' : $wordads_ads_txt;
234 set_transient( 'wordads_ads_txt', $ads_txt_transient, DAY_IN_SECONDS );
235 }
236
237 /**
238 * Provide plugins a way of modifying the contents of the automatically-generated ads.txt file.
239 *
240 * @module wordads
241 *
242 * @since 6.1.0
243 *
244 * @param string WordAds_API::get_wordads_ads_txt() The contents of the ads.txt file.
245 */
246 $ads_txt_content = apply_filters( 'wordads_ads_txt', $ads_txt_transient );
247
248 http_response_code( 200 );
249 header( 'Content-Type: text/plain; charset=utf-8' );
250 echo esc_html( $ads_txt_content );
251 die( 0 );
252 }
253 }
254
255 /**
256 * Check for Jetpack's The_Neverending_Home_Page and use got_infinity
257 *
258 * @return boolean true if load came from infinite scroll
259 *
260 * @since 4.5.0
261 */
262 public static function is_infinite_scroll() {
263 return class_exists( 'The_Neverending_Home_Page' ) && The_Neverending_Home_Page::got_infinity();
264 }
265
266 /**
267 * Add the actions/filters to insert the ads. Checks for mobile or desktop.
268 *
269 * @since 4.5.0
270 */
271 private function insert_adcode() {
272 add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
273
274 // These 'wp_head' actions add the IPONWEB JavaScript snippets to the page.
275 // We need to remove these calls whenever migration to Aditude is complete.
276 add_action( 'wp_head', array( $this, 'insert_head_meta' ), 20 );
277
278 // TODO: Remove this function after June 30th, 2025.
279 add_action( 'wp_head', array( $this, 'insert_head_iponweb' ), 30 );
280
281 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
282 add_filter( 'wordads_ads_txt', array( $this, 'insert_custom_adstxt' ) );
283
284 /**
285 * Filters enabling ads in `the_content` filter
286 *
287 * @see https://jetpack.com/support/ads/
288 *
289 * @module wordads
290 *
291 * @since 5.8.0
292 *
293 * @param bool True to disable ads in `the_content`
294 */
295 if ( ! apply_filters( 'wordads_content_disable', false ) ) {
296 add_filter( 'the_content', array( $this, 'insert_ad' ) );
297 }
298
299 /**
300 * Filters enabling ads in `the_excerpt` filter
301 *
302 * @see https://jetpack.com/support/ads/
303 *
304 * @module wordads
305 *
306 * @since 5.8.0
307 *
308 * @param bool True to disable ads in `the_excerpt`
309 */
310 if ( ! apply_filters( 'wordads_excerpt_disable', false ) ) {
311 add_filter( 'the_excerpt', array( $this, 'insert_ad' ) );
312 }
313
314 if ( $this->option( 'enable_header_ad', true ) ) {
315 if ( self::is_amp() ) {
316 add_filter( 'the_content', array( $this, 'insert_header_ad_amp' ) );
317 } else {
318 add_action( 'wordads_header_ad', array( $this, 'insert_header_ad' ), 100 );
319 add_action( 'wp_footer', array( $this, 'insert_header_ad' ), 100 );
320 }
321 }
322 }
323
324 /**
325 * Register desktop scripts and styles
326 *
327 * @since 4.5.0
328 */
329 public function enqueue_scripts() {
330 wp_enqueue_style(
331 'wordads',
332 WORDADS_URL . 'css/style.css',
333 array(),
334 '2015-12-18'
335 );
336 }
337
338 /**
339 * Add the IPW resource hints
340 *
341 * @since 7.9
342 *
343 * @param array $hints Domains for hinting.
344 * @param string $relation_type Resource type.
345 *
346 * @return array Domains for hinting.
347 */
348 public function resource_hints( $hints, $relation_type ) {
349 if ( 'dns-prefetch' === $relation_type ) {
350 $hints[] = '//s.pubmine.com';
351 $hints[] = '//x.bidswitch.net';
352 $hints[] = '//static.criteo.net';
353 $hints[] = '//ib.adnxs.com';
354 $hints[] = '//aax.amazon-adsystem.com';
355 $hints[] = '//bidder.criteo.com';
356 $hints[] = '//cas.criteo.com';
357 $hints[] = '//gum.criteo.com';
358 $hints[] = '//ads.pubmatic.com';
359 $hints[] = '//gads.pubmatic.com';
360 $hints[] = '//tpc.googlesyndication.com';
361 $hints[] = '//ad.doubleclick.net';
362 $hints[] = '//googleads.g.doubleclick.net';
363 $hints[] = '//www.googletagservices.com';
364 $hints[] = '//cdn.switchadhub.com';
365 $hints[] = '//delivery.g.switchadhub.com';
366 $hints[] = '//delivery.swid.switchadhub.com';
367 }
368
369 return $hints;
370 }
371
372 /**
373 * IPONWEB metadata used by the various scripts
374 */
375 public function insert_head_meta() {
376 if ( self::is_amp() ) {
377 return;
378 }
379 $hosting_type = ( new Host() )->is_woa_site() ? 1 : 2; // 1 = WPCOM, 2 = Jetpack.
380 $pagetype = (int) $this->params->get_page_type_ipw();
381 $data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
382 $site_id = $this->params->blog_id;
383 $consent = (int) isset( $_COOKIE['personalized-ads-consent'] );
384 $is_logged_in = is_user_logged_in() ? '1' : '0';
385
386 $disabled_slot_formats = apply_filters( 'wordads_disabled_slot_formats', array() );
387
388 if ( apply_filters( 'wordads_iponweb_bottom_sticky_ad_disable', false ) ) {
389 $disabled_slot_formats[] = 'MTS';
390 }
391
392 if ( apply_filters( 'wordads_iponweb_sidebar_sticky_right_ad_disable', false ) ) {
393 $disabled_slot_formats[] = 'DPR';
394 }
395
396 $config = array(
397 'pt' => $pagetype,
398 'ht' => $hosting_type,
399 'tn' => get_stylesheet(),
400 'uloggedin' => $is_logged_in,
401 'amp' => false,
402 'siteid' => $site_id,
403 'consent' => $consent,
404 'ad' => array(
405 'label' => array(
406 'text' => __( 'Advertisements', 'jetpack' ),
407 ),
408 'reportAd' => array(
409 'text' => __( 'Report this ad', 'jetpack' ),
410 ),
411 'privacySettings' => array(
412 'text' => __( 'Privacy', 'jetpack' ),
413 'onClick' => 'js:function() { window.__tcfapi && window.__tcfapi(\'showUi\'); }',
414 ),
415 ),
416 'disabled_slot_formats' => $disabled_slot_formats,
417 );
418 $js_config = WordAds_Array_Utils::array_to_js_object( $config );
419 ?>
420 <script<?php echo esc_attr( $data_tags ); ?> type="text/javascript">
421 var __ATA_PP = <?php echo $js_config; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>;
422 var __ATA = __ATA || {};
423 __ATA.cmd = __ATA.cmd || [];
424 __ATA.criteo = __ATA.criteo || {};
425 __ATA.criteo.cmd = __ATA.criteo.cmd || [];
426 </script>
427 <?php
428
429 $section_id = $this->params->blog_id . 5;
430
431 // Get below post tag.
432 $tag_belowpost = $this->get_fallback_ad_snippet( $section_id, 'square', 'belowpost', '', '{{unique_id}}' );
433
434 // Remove linebreaks and sanitize.
435 $tag_belowpost = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_belowpost ) );
436
437 // Get an inline tag with a macro as id handled on JS side to use as a fallback.
438 $tag_inline = $this->get_fallback_ad_snippet( $section_id, 'square', 'inline', '', '{{unique_id}}' );
439
440 // Remove linebreaks and sanitize.
441 $tag_inline = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_inline ) );
442
443 // Get top tag.
444 $tag_top = $this->get_fallback_ad_snippet( $section_id, 'leaderboard', 'top', '', '{{unique_id}}' );
445
446 // Remove linebreaks and sanitize.
447 $tag_top = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_top ) );
448
449 // phpcs:disable WordPress.Security.EscapeOutput.HeredocOutputNotEscaped
450 echo <<<HTML
451 <script type="text/javascript">
452 window.sas_fallback = window.sas_fallback || [];
453 window.sas_fallback.push(
454 { tag: "$tag_inline", type: 'inline' },
455 { tag: "$tag_belowpost", type: 'belowpost' },
456 { tag: "$tag_top", type: 'top' }
457 );
458 </script>
459 HTML;
460 }
461
462 /**
463 * IPONWEB scripts in <head>
464 *
465 * @since 4.5.0
466 */
467 public function insert_head_iponweb() {
468 if ( self::is_amp() ) {
469 return;
470 }
471
472 $data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
473 ?>
474 <script<?php echo esc_attr( $data_tags ); ?> type="text/javascript">
475 function loadIPONWEB() { // TODO: Remove this after June 30th, 2025
476 (function(){var g=Date.now||function(){return+new Date};function h(a,b){a:{for(var c=a.length,d="string"==typeof a?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){b=e;break a}b=-1}return 0>b?null:"string"==typeof a?a.charAt(b):a[b]};function k(a,b,c){c=null!=c?"="+encodeURIComponent(String(c)):"";if(b+=c){c=a.indexOf("#");0>c&&(c=a.length);var d=a.indexOf("?");if(0>d||d>c){d=c;var e=""}else e=a.substring(d+1,c);a=[a.substr(0,d),e,a.substr(c)];c=a[1];a[1]=b?c?c+"&"+b:b:c;a=a[0]+(a[1]?"?"+a[1]:"")+a[2]}return a};var l=0;function m(a,b){var c=document.createElement("script");c.src=a;c.onload=function(){b&&b(void 0)};c.onerror=function(){b&&b("error")};a=document.getElementsByTagName("head");var d;a&&0!==a.length?d=a[0]:d=document.documentElement;d.appendChild(c)}function n(a){var b=void 0===b?document.cookie:b;return(b=h(b.split("; "),function(c){return-1!=c.indexOf(a+"=")}))?b.split("=")[1]:""}function p(a){return"string"==typeof a&&0<a.length}
477 function r(a,b,c){b=void 0===b?"":b;c=void 0===c?".":c;var d=[];Object.keys(a).forEach(function(e){var f=a[e],q=typeof f;"object"==q&&null!=f||"function"==q?d.push(r(f,b+e+c)):null!==f&&void 0!==f&&(e=encodeURIComponent(b+e),d.push(e+"="+encodeURIComponent(f)))});return d.filter(p).join("&")}function t(a,b){a||((window.__ATA||{}).config=b.c,m(b.url))}var u=Math.floor(1E13*Math.random()),v=window.__ATA||{};window.__ATA=v;window.__ATA.cmd=v.cmd||[];v.rid=u;v.createdAt=g();var w=window.__ATA||{},x="s.pubmine.com";
478 w&&w.serverDomain&&(x=w.serverDomain);var y="//"+x+"/conf",z=window.top===window,A=window.__ATA_PP&&window.__ATA_PP.gdpr_applies,B="boolean"===typeof A?Number(A):null,C=window.__ATA_PP||null,D=z?document.referrer?document.referrer:null:null,E=z?window.location.href:document.referrer?document.referrer:null,F,G=n("__ATA_tuuid");F=G?G:null;var H=window.innerWidth+"x"+window.innerHeight,I=n("usprivacy"),J=r({gdpr:B,pp:C,rid:u,src:D,ref:E,tuuid:F,vp:H,us_privacy:I?I:null},"",".");
479 (function(a){var b=void 0===b?"cb":b;l++;var c="callback__"+g().toString(36)+"_"+l.toString(36);a=k(a,b,c);window[c]=function(d){t(void 0,d)};m(a,function(d){d&&t(d)})})(y+"?"+J);}).call(this);
480 }
481 </script>
482 <?php
483 }
484
485 /**
486 * Insert the ad onto the page
487 *
488 * @since 4.5.0
489 *
490 * @param string $content HTML content.
491 */
492 public function insert_ad( $content ) {
493 // Don't insert ads in feeds, or for anything but the main display. (This is required for compatibility with the Publicize module).
494 if ( is_feed() || ! is_main_query() || ! in_the_loop() ) {
495 return $content;
496 }
497 /**
498 * Allow third-party tools to disable the display of in post ads.
499 *
500 * @module wordads
501 *
502 * @since 4.5.0
503 *
504 * @param bool true Should the in post unit be disabled. Default to false.
505 */
506 $disable = apply_filters( 'wordads_inpost_disable', false );
507 if ( ! $this->params->should_show() || $disable ) {
508 return $content;
509 }
510
511 $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
512 return $content . $this->get_ad( 'belowpost', $ad_type );
513 }
514
515 /**
516 * Insert an inline ad into a post content
517 * Used for rendering the `wordads` shortcode.
518 *
519 * @since 6.1.0
520 *
521 * @param string $content HTML content.
522 */
523 public function insert_inline_ad( $content ) {
524 // Ad JS won't work in XML feeds.
525 if ( is_feed() ) {
526 return $content;
527 }
528 /**
529 * Allow third-party tools to disable the display of in post ads.
530 *
531 * @module wordads
532 *
533 * @since 4.5.0
534 *
535 * @param bool true Should the in post unit be disabled. Default to false.
536 */
537 $disable = apply_filters( 'wordads_inpost_disable', false );
538 if ( $disable ) {
539 return $content;
540 }
541
542 $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
543 $location = 'shortcode';
544
545 // Not house ad and WATL enabled.
546 // phpcs:disable WordPress.Security.NonceVerification.Recommended
547 if ( 'house' !== $ad_type && ( isset( $_GET['wordads-logging'] ) && isset( $_GET[ $location ] ) && 'true' === $_GET[ $location ] ) ) {
548 return $content . $this->get_watl_ad_html_tag( $location );
549 }
550
551 return $content . $this->get_ad( 'inline', $ad_type );
552 }
553
554 /**
555 * Inserts ad into header
556 *
557 * @since 4.5.0
558 */
559 public function insert_header_ad() {
560 /**
561 * Allow third-party tools to disable the display of header ads.
562 *
563 * @module wordads
564 *
565 * @since 4.5.0
566 *
567 * @param bool true Should the header unit be disabled. Default to false.
568 */
569 if ( apply_filters( 'wordads_header_disable', false ) ) {
570 return;
571 }
572
573 // Prevent multiple manual ads.
574 if ( 2 <= did_action( 'wordads_header_ad' ) ) {
575 return;
576 }
577
578 // Prevent placing an automatic ad if a manual ad has already been placed.
579 if ( doing_action( 'wp_footer' ) && did_action( 'wordads_header_ad' ) ) {
580 return;
581 }
582
583 // Prevent placing a manual ad if an automatic ad has already been placed.
584 if ( doing_action( 'wordads_header_ad' ) && did_action( 'wp_footer' ) ) {
585 return;
586 }
587
588 // Default ad placement to just after the <body> tag.
589 $selector = 'body > :first-child';
590
591 // Special theme cases.
592 switch ( get_stylesheet() ) {
593 case 'twentyseventeen':
594 $selector = '#content';
595 break;
596 case 'twentyfifteen':
597 $selector = '#main';
598 break;
599 case 'twentyfourteen':
600 $selector = 'article';
601 break;
602 }
603
604 // Don't relocate if the ad is being placed manually.
605 if ( doing_action( 'wordads_header_ad' ) ) {
606 $selector = '';
607 }
608
609 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '2';
610 $form_factor = $this->params->mobile_device ? 'square' : 'leaderboard';
611 echo $this->get_dynamic_ad_snippet( $section_id, $form_factor, 'top', $selector ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
612 }
613
614 /**
615 * Header unit for AMP
616 *
617 * @param string $content Content of the page.
618 *
619 * @since 7.5.0
620 */
621 public function insert_header_ad_amp( $content ) {
622
623 $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
624 if ( 'house' === $ad_type ) {
625 return $content;
626 }
627 return $this->get_ad( 'top_amp', $ad_type ) . $content;
628 }
629
630 /**
631 * Filter the latest ads.txt to include custom user entries. Strips any tags or whitespace.
632 *
633 * @param string $adstxt The ads.txt being filtered.
634 * @return string Filtered ads.txt with custom entries, if applicable.
635 *
636 * @since 6.5.0
637 */
638 public function insert_custom_adstxt( $adstxt ) {
639 if ( ! $this->option( 'wordads_custom_adstxt_enabled' ) ) {
640 return $adstxt;
641 }
642
643 $custom_adstxt = trim( wp_strip_all_tags( $this->option( 'wordads_custom_adstxt' ) ) );
644 if ( $custom_adstxt ) {
645 $adstxt .= "\n\n#Jetpack - User Custom Entries\n";
646 $adstxt .= $custom_adstxt . "\n";
647 }
648
649 return $adstxt;
650 }
651
652 /**
653 * Get the ad for the spot and type.
654 *
655 * @param string $spot top, side, inline, or belowpost.
656 * @param string $type iponweb or adsense.
657 */
658 public function get_ad( $spot, $type = 'iponweb' ) {
659 $snippet = '';
660 if ( 'iponweb' === $type ) {
661 $section_id = WORDADS_API_TEST_ID;
662 $snippet = '';
663
664 if ( 'top' === $spot ) {
665 // mrec for mobile, leaderboard for desktop.
666 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '2';
667 $form_factor = $this->params->mobile_device ? 'square' : 'leaderboard';
668 $snippet = $this->get_dynamic_ad_snippet( $section_id, $form_factor, $spot );
669 } elseif ( 'belowpost' === $spot ) {
670 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '1';
671 $snippet = $this->get_dynamic_ad_snippet( $section_id, 'square', $spot );
672 } elseif ( 'inline' === $spot ) {
673 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '5';
674 $snippet = $this->get_dynamic_ad_snippet( $section_id, 'square', $spot );
675 } elseif ( 'top_amp' === $spot ) {
676 // Ad unit which can safely be inserted below title, above content in a variety of themes.
677 $width = 300;
678 $height = 250;
679 $snippet = $this->get_ad_div( $spot, $this->get_amp_snippet( $height, $width ) );
680 }
681 } elseif ( 'house' === $type ) {
682 $leaderboard = 'top' === $spot && ! $this->params->mobile_device;
683 $snippet = $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
684 if ( 'belowpost' === $spot && $this->option( 'wordads_second_belowpost', true ) ) {
685 $snippet .= $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
686 }
687 }
688
689 return $snippet;
690 }
691
692 /**
693 * Returns the AMP snippet to be inserted
694 *
695 * @param int $height Height.
696 * @param int $width Width.
697 * @return string
698 *
699 * @since 8.7
700 */
701 public function get_amp_snippet( $height, $width ) {
702 $height = esc_attr( $height + 15 ); // this will ensure enough padding for "Report this ad".
703 $width = esc_attr( $width );
704 $amp_section_id = esc_attr( self::get_amp_section_id() );
705 $site_id = esc_attr( $this->params->blog_id );
706 return <<<HTML
707 <amp-ad width="$width" height="$height"
708 type="pubmine"
709 data-siteid="$site_id"
710 data-section="$amp_section_id">
711 </amp-ad>
712 HTML;
713 }
714
715 /**
716 * Compatibility function -- main functionality replaced with get_dynamic_ad_snippet
717 *
718 * @param int $section_id Ad section.
719 * @param int $height Ad height.
720 * @param int $width Ad width.
721 * @param string $location Location.
722 * @param string $css CSS.
723 *
724 * @return string
725 *
726 * @since 5.7
727 */
728 public function get_ad_snippet( $section_id, $height, $width, $location = '', $css = '' ) {
729 if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
730 return $this->get_amp_snippet( $height, $width );
731 }
732
733 $this->ads[] = array(
734 'location' => $location,
735 'width' => $width,
736 'height' => $height,
737 );
738
739 if ( 'gutenberg' === $location ) {
740 $ad_number = count( $this->ads ) . '-' . uniqid();
741 $data_tags = $this->params->cloudflare ? ' data-cfasync="false"' : '';
742 $css = esc_attr( $css );
743
744 $loc_id = 100;
745 if ( ! empty( self::$ad_location_ids[ $location ] ) ) {
746 $loc_id = self::$ad_location_ids[ $location ];
747 }
748
749 $loc_id = esc_js( $loc_id );
750
751 // Determine supported Gutenberg format by width and height.
752 $format = WordAds_Formats::get_format_slug( (int) $width, (int) $height );
753 if ( $format === '' ) {
754 return ''; // When format is not supported, ignore placement.
755 }
756
757 // For a while return elements for both IPONWEB (__ATA) and Aditude (tudeMappings).
758 // We will remove using IPONWEB after partnership termination on June 30, 2025.
759 return <<<HTML
760 <div style="padding-bottom:15px;width:{$width}px;height:{$height}px;$css">
761 <div id="atatags-{$ad_number}">
762 <script$data_tags type="text/javascript">
763 window.getAdSnippetCallback = function () {
764 if ( true === ( window.isWatlV1 ?? false ) ) {
765 // Use IPONWEB scripts.
766 window.__ATA = window.__ATA || {};
767 window.__ATA.cmd = __ATA.cmd || [];
768 window.__ATA.cmd.push(function() {
769 window.__ATA.initSlot('atatags-{$ad_number}', {
770 collapseEmpty: 'before',
771 sectionId: '{$section_id}',
772 location: {$loc_id},
773 width: {$width},
774 height: {$height}
775 });
776 });
777 } else {
778 // Use Aditude scripts.
779 window.tudeMappings = window.tudeMappings || [];
780 window.tudeMappings.push( {
781 divId: 'atatags-{$ad_number}',
782 format: '{$format}',
783 width: {$width},
784 height: {$height},
785 } );
786 }
787 }
788
789 if ( document.readyState === 'loading' ) {
790 document.addEventListener( 'DOMContentLoaded', window.getAdSnippetCallback );
791 } else {
792 window.getAdSnippetCallback();
793 }
794 </script>
795 </div>
796 </div>
797 HTML;
798 }
799
800 $form_factor = 'square';
801 if ( 250 > $width ) {
802 $form_factor = 'skyscraper';
803 } elseif ( 300 < $width ) {
804 $form_factor = 'leaderboard';
805 }
806
807 return $this->get_dynamic_ad_snippet( $section_id, $form_factor, $location );
808 }
809
810 /**
811 * Returns the dynamic snippet to be inserted into the ad unit
812 *
813 * @param int $section_id section_id.
814 * @param string $form_factor form_factor.
815 * @param string $location location.
816 * @param string $relocate location to be moved after the fact for themes without required hook.
817 * @param string | null $id A unique string ID or placeholder.
818 *
819 * @return string
820 *
821 * @since 8.7
822 */
823 public function get_dynamic_ad_snippet( $section_id, $form_factor = 'square', $location = '', $relocate = '', $id = null ) {
824 $is_location_enabled = in_array( $location, array( 'top', 'belowpost', 'inline' ), true );
825
826 if ( $is_location_enabled ) {
827 return self::get_watl_ad_html_tag( $location );
828 }
829
830 return $this->get_fallback_ad_snippet( $section_id, $form_factor, $location, $relocate, $id );
831 }
832
833 /**
834 * Returns the fallback dynamic snippet to be inserted into the ad unit
835 *
836 * @param int $section_id section_id.
837 * @param string $form_factor form_factor.
838 * @param string $location location.
839 * @param string $relocate location to be moved after the fact for themes without required hook.
840 * @param string | null $id A unique string ID or placeholder.
841 *
842 * @return string
843 *
844 * @since 8.7
845 */
846 public function get_fallback_ad_snippet( $section_id, $form_factor = 'square', $location = '', $relocate = '', $id = null ) {
847 $div_id = 'atatags-' . $section_id . '-' . ( $id ?? uniqid() );
848 $div_id = esc_attr( $div_id );
849
850 // Default form factor.
851 $form_factor_id = self::$form_factor_ids['square'];
852 if ( isset( self::$form_factor_ids[ $form_factor ] ) ) {
853 $form_factor_id = self::$form_factor_ids[ $form_factor ];
854 }
855
856 $loc_id = 100;
857 if ( isset( self::$ad_location_ids[ $location ] ) ) {
858 $loc_id = self::$ad_location_ids[ $location ];
859 }
860
861 $form_factor_id = esc_js( $form_factor_id );
862 $advertisements_text = esc_js( __( 'Advertisements', 'jetpack' ) );
863 $report_ad_text = esc_js( __( 'Report this ad', 'jetpack' ) );
864 $privacy_settings_text = esc_js( __( 'Privacy settings', 'jetpack' ) );
865
866 $relocate_script = '';
867 if ( ! empty( $relocate ) ) {
868 $selector = wp_json_encode( $relocate );
869 $relocate_script = <<<JS
870 <script type="text/javascript">
871 var adNode = document.getElementById( '{$div_id}' );
872 var selector = {$selector};
873 var relocateNode = document.querySelector( selector );
874 relocateNode.parentNode.insertBefore( adNode, relocateNode );
875 </script>
876 JS;
877 }
878
879 return <<<HTML
880 <div id="{$div_id}"></div>
881 {$relocate_script}
882 <script>
883 __ATA.cmd.push(function() {
884 __ATA.initDynamicSlot({
885 id: '{$div_id}',
886 location: {$loc_id},
887 formFactor: '{$form_factor_id}',
888 label: {
889 text: '{$advertisements_text}',
890 },
891 creative: {
892 reportAd: {
893 text: '{$report_ad_text}',
894 },
895 privacySettings: {
896 text: '{$privacy_settings_text}',
897 onClick: function() { window.__tcfapi && window.__tcfapi('showUi'); },
898 }
899 }
900 });
901 });
902 </script>
903 HTML;
904 }
905
906 /**
907 * Returns the complete ad div with snippet to be inserted into the page
908 *
909 * @param string $spot top, side, inline, or belowpost.
910 * @param string $snippet The snippet to insert into the div.
911 * @param array $css_classes CSS classes.
912 * @return string The supporting ad unit div.
913 *
914 * @since 7.1
915 */
916 public function get_ad_div( $spot, $snippet, array $css_classes = array() ) {
917 if ( strpos( strtolower( $spot ), 'amp' ) === false && ! 'inline' === $spot ) {
918 return $snippet; // we don't want dynamic ads to be inserted for AMP & Gutenberg.
919 }
920
921 if ( empty( $css_classes ) ) {
922 $css_classes = array();
923 }
924
925 $css_classes[] = 'wpcnt';
926 if ( 'top' === $spot ) {
927 $css_classes[] = 'wpcnt-header';
928 }
929
930 $spot = esc_attr( $spot );
931 $classes = esc_attr( implode( ' ', $css_classes ) );
932 $about = esc_html__( 'Advertisements', 'jetpack' );
933 return <<<HTML
934 <div class="$classes">
935 <div class="wpa">
936 <span class="wpa-about">$about</span>
937 <div class="u $spot">
938 $snippet
939 </div>
940 </div>
941 </div>
942 HTML;
943 }
944
945 /**
946 * Check the reasons to bail before we attempt to insert ads.
947 *
948 * @return true if we should bail (don't insert ads)
949 *
950 * @since 4.5.0
951 */
952 public function should_bail() {
953 return ! $this->option( 'wordads_approved' ) || (bool) $this->option( 'wordads_unsafe' );
954 }
955
956 /**
957 * Returns markup for HTML5 house ad base on unit
958 *
959 * @param string $unit mrec, widesky, or leaderboard.
960 * @return string markup for HTML5 house ad
961 *
962 * @since 4.7.0
963 */
964 public function get_house_ad( $unit = 'mrec' ) {
965
966 switch ( $unit ) {
967 case 'widesky':
968 $width = 160;
969 $height = 600;
970 break;
971 case 'leaderboard':
972 $width = 728;
973 $height = 90;
974 break;
975 case 'mrec':
976 default:
977 $width = 300;
978 $height = 250;
979 break;
980 }
981
982 return <<<HTML
983 <iframe
984 src="https://s0.wp.com/wp-content/blog-plugins/wordads/house/html5/$unit/index.html"
985 width="$width"
986 height="$height"
987 frameborder="0"
988 scrolling="no"
989 marginheight="0"
990 marginwidth="0">
991 </iframe>
992 HTML;
993 }
994
995 /**
996 * Returns the html ad tag used by WordAds Tag Library
997 *
998 * @param string $slot_type e.g belowpost, gutenberg_rectangle.
999 *
1000 * @return string
1001 *
1002 * @since 8.7
1003 */
1004 public static function get_watl_ad_html_tag( string $slot_type ): string {
1005 $uid = uniqid( 'atatags-dynamic-' . $slot_type . '-' );
1006
1007 return <<<HTML
1008 <div style="padding-bottom:15px;" class="wordads-tag" data-slot-type="{$slot_type}">
1009 <div id="{$uid}">
1010 <script type="text/javascript">
1011 window.getAdSnippetCallback = function () {
1012 if ( false === ( window.isWatlV1 ?? false ) ) {
1013 // Use Aditude scripts.
1014 window.tudeMappings = window.tudeMappings || [];
1015 window.tudeMappings.push( {
1016 divId: '{$uid}',
1017 format: '{$slot_type}',
1018 } );
1019 }
1020 }
1021
1022 if ( document.readyState === 'loading' ) {
1023 document.addEventListener( 'DOMContentLoaded', window.getAdSnippetCallback );
1024 } else {
1025 window.getAdSnippetCallback();
1026 }
1027 </script>
1028 </div>
1029 </div>
1030 HTML;
1031 }
1032
1033 /**
1034 * Activation hook actions
1035 *
1036 * @since 4.5.0
1037 */
1038 public static function activate() {
1039 WordAds_API::update_wordads_status_from_api();
1040 }
1041
1042 /**
1043 * Registers the widgets.
1044 */
1045 public function widget_callback() {
1046 register_widget( 'WordAds_Sidebar_Widget' );
1047
1048 $ccpa_enabled = get_option( 'wordads_ccpa_enabled' );
1049
1050 if ( $ccpa_enabled ) {
1051 register_widget( 'WordAds_Ccpa_Do_Not_Sell_Link_Widget' );
1052 }
1053 }
1054 }
1055
1056 add_action( 'jetpack_activate_module_wordads', array( 'WordAds', 'activate' ) );
1057 add_action( 'jetpack_activate_module_wordads', array( 'WordAds_Cron', 'activate' ) );
1058 add_action( 'jetpack_deactivate_module_wordads', array( 'WordAds_Cron', 'deactivate' ) );
1059
1060 global $wordads;
1061 $wordads = new WordAds();
1062