PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.6.2
Jetpack – WP Security, Backup, Speed, & Growth v13.6.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 5 years ago js 2 years ago php 2 years ago class-wordads.php 2 years ago
class-wordads.php
900 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-smart.php';
24
25 /**
26 * Primary WordAds class.
27 */
28 class WordAds {
29
30 /**
31 * Ads parameters.
32 *
33 * @var null
34 */
35 public $params = null;
36
37 /**
38 * Ads.
39 *
40 * @var array
41 */
42 public $ads = array();
43
44 /**
45 * Array of supported ad types.
46 *
47 * @var array
48 */
49 public static $ad_tag_ids = array(
50 'mrec' => array(
51 'tag' => '300x250_mediumrectangle',
52 'height' => '250',
53 'width' => '300',
54 ),
55 'leaderboard' => array(
56 'tag' => '728x90_leaderboard',
57 'height' => '90',
58 'width' => '728',
59 ),
60 'mobile_leaderboard' => array(
61 'tag' => '320x50_mobileleaderboard',
62 'height' => '50',
63 'width' => '320',
64 ),
65 'wideskyscraper' => array(
66 'tag' => '160x600_wideskyscraper',
67 'height' => '600',
68 'width' => '160',
69 ),
70 );
71
72 /**
73 * Mapping array of location slugs to placement ids
74 *
75 * @var array
76 */
77 public static $ad_location_ids = array(
78 'top' => 110,
79 'belowpost' => 120,
80 'belowpost2' => 130,
81 'sidebar' => 140,
82 'widget' => 150,
83 'gutenberg' => 200,
84 'inline' => 310,
85 'inline-plugin' => 320,
86 );
87
88 /**
89 * Mapping array of form factor slugs to form factor ids
90 *
91 * @var array
92 */
93 public static $form_factor_ids = array(
94 'square' => '001', // 250x250
95 'leaderboard' => '002', // 728x90
96 'skyscraper' => '003', // 120x600
97 );
98
99 /**
100 * Counter to enable unique, sequential section IDs for all amp-ad units
101 *
102 * @var int
103 */
104 public static $amp_section_id = 1;
105
106 /**
107 * Solo unit CSS string.
108 *
109 * @var string
110 */
111 public static $solo_unit_css = 'float:left;margin-right:5px;margin-top:0px;';
112
113 /**
114 * Checks for AMP support and returns true iff active & AMP request
115 *
116 * @return boolean True if supported AMP request
117 *
118 * @since 7.5.0
119 */
120 public static function is_amp() {
121 return class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
122 }
123
124 /**
125 * Increment the AMP section ID and return the value
126 *
127 * @return int
128 */
129 public static function get_amp_section_id() {
130 return self::$amp_section_id++;
131 }
132
133 /**
134 * Convenience function for grabbing options from params->options
135 *
136 * @param string $option the option to grab.
137 * @param mixed $default (optional).
138 * @return mixed option or $default if not set
139 *
140 * @since 4.5.0
141 */
142 public function option( $option, $default = false ) {
143 if ( ! isset( $this->params->options[ $option ] ) ) {
144 return $default;
145 }
146
147 return $this->params->options[ $option ];
148 }
149
150 /**
151 * Returns the ad tag property array for supported ad types.
152 *
153 * @return array array with ad tags
154 *
155 * @since 7.1.0
156 */
157 public function get_ad_tags() {
158 return self::$ad_tag_ids;
159 }
160
161 /**
162 * Returns the solo css for unit
163 *
164 * @return string the special css for solo units
165 *
166 * @since 7.1.0
167 */
168 public function get_solo_unit_css() {
169 return self::$solo_unit_css;
170 }
171
172 /**
173 * Instantiate the plugin
174 *
175 * @since 4.5.0
176 */
177 public function __construct() {
178 add_action( 'wp', array( $this, 'init' ) );
179 add_action( 'rest_api_init', array( $this, 'init' ) );
180 add_action( 'widgets_init', array( $this, 'widget_callback' ) );
181
182 if ( is_admin() ) {
183 WordAds_California_Privacy::init_ajax_actions();
184 WordAds_Consent_Management_Provider::init_ajax_actions();
185 }
186 }
187
188 /**
189 * Code to run on WordPress 'init' hook
190 *
191 * @since 4.5.0
192 */
193 public function init() {
194 require_once WORDADS_ROOT . '/php/class-wordads-params.php';
195 $this->params = new WordAds_Params();
196
197 if ( $this->should_bail() || self::is_infinite_scroll() ) {
198 return;
199 }
200
201 if ( is_admin() ) {
202 require_once WORDADS_ROOT . '/php/class-wordads-admin.php';
203 return;
204 }
205
206 $this->insert_adcode();
207
208 // Include California Privacy Act related features if enabled.
209 if ( $this->params->options['wordads_ccpa_enabled'] ) {
210 WordAds_California_Privacy::init();
211 }
212
213 // Initialize CMP if enabled.
214 if ( isset( $this->params->options['wordads_cmp_enabled'] ) && $this->params->options['wordads_cmp_enabled'] ) {
215 WordAds_Consent_Management_Provider::init();
216 }
217
218 // Initialize Smart.
219 WordAds_Smart::instance()->init( $this->params );
220
221 if ( ( isset( $_SERVER['REQUEST_URI'] ) && '/ads.txt' === $_SERVER['REQUEST_URI'] )
222 || ( site_url( 'ads.txt', 'relative' ) === $_SERVER['REQUEST_URI'] ) ) {
223
224 $ads_txt_transient = get_transient( 'wordads_ads_txt' );
225
226 if ( false === ( $ads_txt_transient ) ) {
227 $wordads_ads_txt = WordAds_API::get_wordads_ads_txt();
228 $ads_txt_transient = is_wp_error( $wordads_ads_txt ) ? '' : $wordads_ads_txt;
229 set_transient( 'wordads_ads_txt', $ads_txt_transient, DAY_IN_SECONDS );
230 }
231
232 /**
233 * Provide plugins a way of modifying the contents of the automatically-generated ads.txt file.
234 *
235 * @module wordads
236 *
237 * @since 6.1.0
238 *
239 * @param string WordAds_API::get_wordads_ads_txt() The contents of the ads.txt file.
240 */
241 $ads_txt_content = apply_filters( 'wordads_ads_txt', $ads_txt_transient );
242
243 http_response_code( 200 );
244 header( 'Content-Type: text/plain; charset=utf-8' );
245 echo esc_html( $ads_txt_content );
246 die();
247 }
248 }
249
250 /**
251 * Check for Jetpack's The_Neverending_Home_Page and use got_infinity
252 *
253 * @return boolean true if load came from infinite scroll
254 *
255 * @since 4.5.0
256 */
257 public static function is_infinite_scroll() {
258 return class_exists( 'The_Neverending_Home_Page' ) && The_Neverending_Home_Page::got_infinity();
259 }
260
261 /**
262 * Add the actions/filters to insert the ads. Checks for mobile or desktop.
263 *
264 * @since 4.5.0
265 */
266 private function insert_adcode() {
267 add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
268 add_action( 'wp_head', array( $this, 'insert_head_meta' ), 20 );
269 add_action( 'wp_head', array( $this, 'insert_head_iponweb' ), 30 );
270 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
271 add_filter( 'wordads_ads_txt', array( $this, 'insert_custom_adstxt' ) );
272
273 /**
274 * Filters enabling ads in `the_content` filter
275 *
276 * @see https://jetpack.com/support/ads/
277 *
278 * @module wordads
279 *
280 * @since 5.8.0
281 *
282 * @param bool True to disable ads in `the_content`
283 */
284 if ( ! apply_filters( 'wordads_content_disable', false ) ) {
285 add_filter( 'the_content', array( $this, 'insert_ad' ) );
286 }
287
288 /**
289 * Filters enabling ads in `the_excerpt` filter
290 *
291 * @see https://jetpack.com/support/ads/
292 *
293 * @module wordads
294 *
295 * @since 5.8.0
296 *
297 * @param bool True to disable ads in `the_excerpt`
298 */
299 if ( ! apply_filters( 'wordads_excerpt_disable', false ) ) {
300 add_filter( 'the_excerpt', array( $this, 'insert_ad' ) );
301 }
302
303 if ( $this->option( 'enable_header_ad', true ) ) {
304 if ( self::is_amp() ) {
305 add_filter( 'the_content', array( $this, 'insert_header_ad_amp' ) );
306 } else {
307 add_action( 'wordads_header_ad', array( $this, 'insert_header_ad' ), 100 );
308 add_action( 'wp_footer', array( $this, 'insert_header_ad' ), 100 );
309 }
310 }
311 }
312
313 /**
314 * Register desktop scripts and styles
315 *
316 * @since 4.5.0
317 */
318 public function enqueue_scripts() {
319 wp_enqueue_style(
320 'wordads',
321 WORDADS_URL . 'css/style.css',
322 array(),
323 '2015-12-18'
324 );
325 }
326
327 /**
328 * Add the IPW resource hints
329 *
330 * @since 7.9
331 *
332 * @param array $hints Domains for hinting.
333 * @param string $relation_type Resource type.
334 *
335 * @return array Domains for hinting.
336 */
337 public function resource_hints( $hints, $relation_type ) {
338 if ( 'dns-prefetch' === $relation_type ) {
339 $hints[] = '//s.pubmine.com';
340 $hints[] = '//x.bidswitch.net';
341 $hints[] = '//static.criteo.net';
342 $hints[] = '//ib.adnxs.com';
343 $hints[] = '//aax.amazon-adsystem.com';
344 $hints[] = '//bidder.criteo.com';
345 $hints[] = '//cas.criteo.com';
346 $hints[] = '//gum.criteo.com';
347 $hints[] = '//ads.pubmatic.com';
348 $hints[] = '//gads.pubmatic.com';
349 $hints[] = '//tpc.googlesyndication.com';
350 $hints[] = '//ad.doubleclick.net';
351 $hints[] = '//googleads.g.doubleclick.net';
352 $hints[] = '//www.googletagservices.com';
353 $hints[] = '//cdn.switchadhub.com';
354 $hints[] = '//delivery.g.switchadhub.com';
355 $hints[] = '//delivery.swid.switchadhub.com';
356 }
357
358 return $hints;
359 }
360
361 /**
362 * IPONWEB metadata used by the various scripts
363 */
364 public function insert_head_meta() {
365 if ( self::is_amp() ) {
366 return;
367 }
368 $hosting_type = ( new Host() )->is_woa_site() ? 1 : 2; // 1 = WPCOM, 2 = Jetpack.
369 $pagetype = (int) $this->params->get_page_type_ipw();
370 $data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
371 $site_id = $this->params->blog_id;
372 $consent = (int) isset( $_COOKIE['personalized-ads-consent'] );
373 $is_logged_in = is_user_logged_in() ? '1' : '0';
374 ?>
375 <script<?php echo esc_attr( $data_tags ); ?> type="text/javascript">
376 var __ATA_PP = { pt: <?php echo esc_js( $pagetype ); ?>, ht: <?php echo esc_js( $hosting_type ); ?>, tn: '<?php echo esc_js( get_stylesheet() ); ?>', uloggedin: <?php echo esc_js( $is_logged_in ); ?>, amp: false, siteid: <?php echo esc_js( $site_id ); ?>, consent: <?php echo esc_js( $consent ); ?>, ad: { label: { text: '<?php echo esc_js( __( 'Advertisements', 'jetpack' ) ); ?>' }, reportAd: { text: '<?php echo esc_js( __( 'Report this ad', 'jetpack' ) ); ?>' }, privacySettings: { text: '<?php echo esc_js( __( 'Privacy', 'jetpack' ) ); ?>', onClick: function() { window.__tcfapi && window.__tcfapi('showUi'); } } } };
377 var __ATA = __ATA || {};
378 __ATA.cmd = __ATA.cmd || [];
379 __ATA.criteo = __ATA.criteo || {};
380 __ATA.criteo.cmd = __ATA.criteo.cmd || [];
381 </script>
382 <?php
383
384 // Get an inline tag with a macro as id handled on JS side to use as a fallback.
385 $tag_inline = $this->get_dynamic_ad_snippet( $this->params->blog_id . 5, 'square', 'inline', '', '{{unique_id}}' );
386
387 // Remove linebreaks and sanitize.
388 $tag_inline = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_inline ) );
389
390 // phpcs:disable WordPress.Security.EscapeOutput.HeredocOutputNotEscaped
391 echo <<<HTML
392 <script>
393 var sas_fallback = sas_fallback || [];
394 sas_fallback.push(
395 { tag: "$tag_inline", type: 'inline' }
396 );
397 </script>
398 HTML;
399 }
400
401 /**
402 * IPONWEB scripts in <head>
403 *
404 * @since 4.5.0
405 */
406 public function insert_head_iponweb() {
407 if ( self::is_amp() ) {
408 return;
409 }
410
411 $data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
412 ?>
413 <script<?php echo esc_attr( $data_tags ); ?> type="text/javascript">
414 (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}
415 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";
416 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},"",".");
417 (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);
418 </script>
419 <?php
420 }
421
422 /**
423 * Insert the ad onto the page
424 *
425 * @since 4.5.0
426 *
427 * @param string $content HTML content.
428 */
429 public function insert_ad( $content ) {
430 // Don't insert ads in feeds, or for anything but the main display. (This is required for compatibility with the Publicize module).
431 if ( is_feed() || ! is_main_query() || ! in_the_loop() ) {
432 return $content;
433 }
434 /**
435 * Allow third-party tools to disable the display of in post ads.
436 *
437 * @module wordads
438 *
439 * @since 4.5.0
440 *
441 * @param bool true Should the in post unit be disabled. Default to false.
442 */
443 $disable = apply_filters( 'wordads_inpost_disable', false );
444 if ( ! $this->params->should_show() || $disable ) {
445 return $content;
446 }
447
448 $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
449 return $content . $this->get_ad( 'belowpost', $ad_type );
450 }
451
452 /**
453 * Insert an inline ad into a post content
454 * Used for rendering the `wordads` shortcode.
455 *
456 * @since 6.1.0
457 *
458 * @param string $content HTML content.
459 */
460 public function insert_inline_ad( $content ) {
461 // Ad JS won't work in XML feeds.
462 if ( is_feed() ) {
463 return $content;
464 }
465 /**
466 * Allow third-party tools to disable the display of in post ads.
467 *
468 * @module wordads
469 *
470 * @since 4.5.0
471 *
472 * @param bool true Should the in post unit be disabled. Default to false.
473 */
474 $disable = apply_filters( 'wordads_inpost_disable', false );
475 if ( $disable ) {
476 return $content;
477 }
478
479 $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
480 $content .= $this->get_ad( 'inline', $ad_type );
481 return $content;
482 }
483
484 /**
485 * Inserts ad into header
486 *
487 * @since 4.5.0
488 */
489 public function insert_header_ad() {
490 /**
491 * Allow third-party tools to disable the display of header ads.
492 *
493 * @module wordads
494 *
495 * @since 4.5.0
496 *
497 * @param bool true Should the header unit be disabled. Default to false.
498 */
499 if ( apply_filters( 'wordads_header_disable', false ) ) {
500 return;
501 }
502
503 // Prevent multiple manual ads.
504 if ( 2 <= did_action( 'wordads_header_ad' ) ) {
505 return;
506 }
507
508 // Prevent placing an automatic ad if a manual ad has already been placed.
509 if ( doing_action( 'wp_footer' ) && did_action( 'wordads_header_ad' ) ) {
510 return;
511 }
512
513 // Prevent placing a manual ad if an automatic ad has already been placed.
514 if ( doing_action( 'wordads_header_ad' ) && did_action( 'wp_footer' ) ) {
515 return;
516 }
517
518 // Default ad placement to just after the <body> tag.
519 $selector = 'body > :first-child';
520
521 // Special theme cases.
522 switch ( get_stylesheet() ) {
523 case 'twentyseventeen':
524 $selector = '#content';
525 break;
526 case 'twentyfifteen':
527 $selector = '#main';
528 break;
529 case 'twentyfourteen':
530 $selector = 'article';
531 break;
532 }
533
534 // Don't relocate if the ad is being placed manually.
535 if ( doing_action( 'wordads_header_ad' ) ) {
536 $selector = '';
537 }
538
539 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '2';
540 $form_factor = $this->params->mobile_device ? 'square' : 'leaderboard';
541 echo $this->get_dynamic_ad_snippet( $section_id, $form_factor, 'top', $selector ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
542 }
543
544 /**
545 * Header unit for AMP
546 *
547 * @param string $content Content of the page.
548 *
549 * @since 7.5.0
550 */
551 public function insert_header_ad_amp( $content ) {
552
553 $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
554 if ( 'house' === $ad_type ) {
555 return $content;
556 }
557 return $this->get_ad( 'top_amp', $ad_type ) . $content;
558 }
559
560 /**
561 * Filter the latest ads.txt to include custom user entries. Strips any tags or whitespace.
562 *
563 * @param string $adstxt The ads.txt being filtered.
564 * @return string Filtered ads.txt with custom entries, if applicable.
565 *
566 * @since 6.5.0
567 */
568 public function insert_custom_adstxt( $adstxt ) {
569 if ( ! $this->option( 'wordads_custom_adstxt_enabled' ) ) {
570 return $adstxt;
571 }
572
573 $custom_adstxt = trim( wp_strip_all_tags( $this->option( 'wordads_custom_adstxt' ) ) );
574 if ( $custom_adstxt ) {
575 $adstxt .= "\n\n#Jetpack - User Custom Entries\n";
576 $adstxt .= $custom_adstxt . "\n";
577 }
578
579 return $adstxt;
580 }
581
582 /**
583 * Get the ad for the spot and type.
584 *
585 * @param string $spot top, side, inline, or belowpost.
586 * @param string $type iponweb or adsense.
587 */
588 public function get_ad( $spot, $type = 'iponweb' ) {
589 $snippet = '';
590 if ( 'iponweb' === $type ) {
591 $section_id = WORDADS_API_TEST_ID;
592 $snippet = '';
593
594 if ( 'top' === $spot ) {
595 // mrec for mobile, leaderboard for desktop.
596 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '2';
597 $form_factor = $this->params->mobile_device ? 'square' : 'leaderboard';
598 $snippet = $this->get_dynamic_ad_snippet( $section_id, $form_factor, $spot );
599 } elseif ( 'belowpost' === $spot ) {
600 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '1';
601 $snippet = $this->get_dynamic_ad_snippet( $section_id, 'square', $spot );
602 } elseif ( 'inline' === $spot ) {
603 $section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '5';
604 $snippet = $this->get_dynamic_ad_snippet( $section_id, 'square', $spot );
605 } elseif ( 'top_amp' === $spot ) {
606 // Ad unit which can safely be inserted below title, above content in a variety of themes.
607 $width = 300;
608 $height = 250;
609 $snippet = $this->get_ad_div( $spot, $this->get_amp_snippet( $height, $width ) );
610 }
611 } elseif ( 'house' === $type ) {
612 $leaderboard = 'top' === $spot && ! $this->params->mobile_device;
613 $snippet = $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
614 if ( 'belowpost' === $spot && $this->option( 'wordads_second_belowpost', true ) ) {
615 $snippet .= $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
616 }
617 }
618
619 return $snippet;
620 }
621
622 /**
623 * Returns the AMP snippet to be inserted
624 *
625 * @param int $height Height.
626 * @param int $width Width.
627 * @return string
628 *
629 * @since 8.7
630 */
631 public function get_amp_snippet( $height, $width ) {
632 $height = esc_attr( $height + 15 ); // this will ensure enough padding for "Report this ad".
633 $width = esc_attr( $width );
634 $amp_section_id = esc_attr( self::get_amp_section_id() );
635 $site_id = esc_attr( $this->params->blog_id );
636 return <<<HTML
637 <amp-ad width="$width" height="$height"
638 type="pubmine"
639 data-siteid="$site_id"
640 data-section="$amp_section_id">
641 </amp-ad>
642 HTML;
643 }
644
645 /**
646 * Compatibility function -- main functionality replaced with get_dynamic_ad_snippet
647 *
648 * @param int $section_id Ad section.
649 * @param int $height Ad height.
650 * @param int $width Ad width.
651 * @param string $location Location.
652 * @param string $css CSS.
653 *
654 * @return string
655 *
656 * @since 5.7
657 */
658 public function get_ad_snippet( $section_id, $height, $width, $location = '', $css = '' ) {
659 if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
660 return $this->get_amp_snippet( $height, $width );
661 }
662
663 $this->ads[] = array(
664 'location' => $location,
665 'width' => $width,
666 'height' => $height,
667 );
668
669 if ( 'gutenberg' === $location ) {
670 $ad_number = count( $this->ads ) . '-' . uniqid();
671 $data_tags = $this->params->cloudflare ? ' data-cfasync="false"' : '';
672 $css = esc_attr( $css );
673
674 $loc_id = 100;
675 if ( ! empty( self::$ad_location_ids[ $location ] ) ) {
676 $loc_id = self::$ad_location_ids[ $location ];
677 }
678
679 $loc_id = esc_js( $loc_id );
680 return <<<HTML
681 <div style="padding-bottom:15px;width:{$width}px;height:{$height}px;$css">
682 <div id="atatags-{$ad_number}">
683 <script$data_tags type="text/javascript">
684 __ATA.cmd.push(function() {
685 __ATA.initSlot('atatags-{$ad_number}', {
686 collapseEmpty: 'before',
687 sectionId: '{$section_id}',
688 location: {$loc_id},
689 width: {$width},
690 height: {$height}
691 });
692 });
693 </script>
694 </div>
695 </div>
696 HTML;
697 }
698
699 $form_factor = 'square';
700 if ( 250 > $width ) {
701 $form_factor = 'skyscraper';
702 } elseif ( 300 < $width ) {
703 $form_factor = 'leaderboard';
704 }
705
706 return $this->get_dynamic_ad_snippet( $section_id, $form_factor, $location );
707 }
708
709 /**
710 * Returns the dynamic snippet to be inserted into the ad unit
711 *
712 * @param int $section_id section_id.
713 * @param string $form_factor form_factor.
714 * @param string $location location.
715 * @param string $relocate location to be moved after the fact for themes without required hook.
716 * @param string | null $id A unique string ID or placeholder.
717 *
718 * @return string
719 *
720 * @since 8.7
721 */
722 public function get_dynamic_ad_snippet( $section_id, $form_factor = 'square', $location = '', $relocate = '', $id = null ) {
723 $div_id = 'atatags-' . $section_id . '-' . ( $id ?? uniqid() );
724 $div_id = esc_attr( $div_id );
725
726 // Default form factor.
727 $form_factor_id = self::$form_factor_ids['square'];
728 if ( isset( self::$form_factor_ids[ $form_factor ] ) ) {
729 $form_factor_id = self::$form_factor_ids[ $form_factor ];
730 }
731
732 $loc_id = 100;
733 if ( isset( self::$ad_location_ids[ $location ] ) ) {
734 $loc_id = self::$ad_location_ids[ $location ];
735 }
736
737 $form_factor_id = esc_js( $form_factor_id );
738 $advertisements_text = esc_js( __( 'Advertisements', 'jetpack' ) );
739 $report_ad_text = esc_js( __( 'Report this ad', 'jetpack' ) );
740 $privacy_settings_text = esc_js( __( 'Privacy settings', 'jetpack' ) );
741
742 $relocate_script = '';
743 if ( ! empty( $relocate ) ) {
744 $selector = wp_json_encode( $relocate );
745 $relocate_script = <<<JS
746 <script type="text/javascript">
747 var adNode = document.getElementById( '{$div_id}' );
748 var selector = {$selector};
749 var relocateNode = document.querySelector( selector );
750 relocateNode.parentNode.insertBefore( adNode, relocateNode );
751 </script>
752 JS;
753 }
754
755 return <<<HTML
756 <div id="{$div_id}"></div>
757 {$relocate_script}
758 <script>
759 __ATA.cmd.push(function() {
760 __ATA.initDynamicSlot({
761 id: '{$div_id}',
762 location: {$loc_id},
763 formFactor: '{$form_factor_id}',
764 label: {
765 text: '{$advertisements_text}',
766 },
767 creative: {
768 reportAd: {
769 text: '{$report_ad_text}',
770 },
771 privacySettings: {
772 text: '{$privacy_settings_text}',
773 onClick: function() { window.__tcfapi && window.__tcfapi('showUi'); },
774 }
775 }
776 });
777 });
778 </script>
779 HTML;
780 }
781
782 /**
783 * Returns the complete ad div with snippet to be inserted into the page
784 *
785 * @param string $spot top, side, inline, or belowpost.
786 * @param string $snippet The snippet to insert into the div.
787 * @param array $css_classes CSS classes.
788 * @return string The supporting ad unit div.
789 *
790 * @since 7.1
791 */
792 public function get_ad_div( $spot, $snippet, array $css_classes = array() ) {
793 if ( strpos( strtolower( $spot ), 'amp' ) === false && ! 'inline' === $spot ) {
794 return $snippet; // we don't want dynamic ads to be inserted for AMP & Gutenberg.
795 }
796
797 if ( empty( $css_classes ) ) {
798 $css_classes = array();
799 }
800
801 $css_classes[] = 'wpcnt';
802 if ( 'top' === $spot ) {
803 $css_classes[] = 'wpcnt-header';
804 }
805
806 $spot = esc_attr( $spot );
807 $classes = esc_attr( implode( ' ', $css_classes ) );
808 $about = esc_html__( 'Advertisements', 'jetpack' );
809 return <<<HTML
810 <div class="$classes">
811 <div class="wpa">
812 <span class="wpa-about">$about</span>
813 <div class="u $spot">
814 $snippet
815 </div>
816 </div>
817 </div>
818 HTML;
819 }
820
821 /**
822 * Check the reasons to bail before we attempt to insert ads.
823 *
824 * @return true if we should bail (don't insert ads)
825 *
826 * @since 4.5.0
827 */
828 public function should_bail() {
829 return ! $this->option( 'wordads_approved' ) || (bool) $this->option( 'wordads_unsafe' );
830 }
831
832 /**
833 * Returns markup for HTML5 house ad base on unit
834 *
835 * @param string $unit mrec, widesky, or leaderboard.
836 * @return string markup for HTML5 house ad
837 *
838 * @since 4.7.0
839 */
840 public function get_house_ad( $unit = 'mrec' ) {
841
842 switch ( $unit ) {
843 case 'widesky':
844 $width = 160;
845 $height = 600;
846 break;
847 case 'leaderboard':
848 $width = 728;
849 $height = 90;
850 break;
851 case 'mrec':
852 default:
853 $width = 300;
854 $height = 250;
855 break;
856 }
857
858 return <<<HTML
859 <iframe
860 src="https://s0.wp.com/wp-content/blog-plugins/wordads/house/html5/$unit/index.html"
861 width="$width"
862 height="$height"
863 frameborder="0"
864 scrolling="no"
865 marginheight="0"
866 marginwidth="0">
867 </iframe>
868 HTML;
869 }
870
871 /**
872 * Activation hook actions
873 *
874 * @since 4.5.0
875 */
876 public static function activate() {
877 WordAds_API::update_wordads_status_from_api();
878 }
879
880 /**
881 * Registers the widgets.
882 */
883 public function widget_callback() {
884 register_widget( 'WordAds_Sidebar_Widget' );
885
886 $ccpa_enabled = get_option( 'wordads_ccpa_enabled' );
887
888 if ( $ccpa_enabled ) {
889 register_widget( 'WordAds_Ccpa_Do_Not_Sell_Link_Widget' );
890 }
891 }
892 }
893
894 add_action( 'jetpack_activate_module_wordads', array( 'WordAds', 'activate' ) );
895 add_action( 'jetpack_activate_module_wordads', array( 'WordAds_Cron', 'activate' ) );
896 add_action( 'jetpack_deactivate_module_wordads', array( 'WordAds_Cron', 'deactivate' ) );
897
898 global $wordads;
899 $wordads = new WordAds();
900