Completed
Push — add/debugger-blog-token ( 149038...c1053a )
by
unknown
33:02 queued 25:29
created

modules/wordads/class-wordads.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Main WordAds file.
4
 *
5
 * @package Jetpack
6
 */
7
8
define( 'WORDADS_ROOT', dirname( __FILE__ ) );
9
define( 'WORDADS_BASENAME', plugin_basename( __FILE__ ) );
10
define( 'WORDADS_FILE_PATH', WORDADS_ROOT . '/' . basename( __FILE__ ) );
11
define( 'WORDADS_URL', plugins_url( '/', __FILE__ ) );
12
define( 'WORDADS_API_TEST_ID', '26942' );
13
define( 'WORDADS_API_TEST_ID2', '114160' );
14
15
require_once WORDADS_ROOT . '/php/class-wordads-sidebar-widget.php';
16
require_once WORDADS_ROOT . '/php/class-wordads-api.php';
17
require_once WORDADS_ROOT . '/php/class-wordads-cron.php';
18
require_once WORDADS_ROOT . '/php/class-wordads-california-privacy.php';
19
require_once WORDADS_ROOT . '/php/class-wordads-ccpa-do-not-sell-link-widget.php';
20
21
/**
22
 * Primary WordAds class.
23
 */
24
class WordAds {
25
26
	/**
27
	 * Ads parameters.
28
	 *
29
	 * @var null
30
	 */
31
	public $params = null;
32
33
	/**
34
	 * Ads.
35
	 *
36
	 * @var array
37
	 */
38
	public $ads = array();
39
40
	/**
41
	 * Array of supported ad types.
42
	 *
43
	 * @var array
44
	 */
45
	public static $ad_tag_ids = array(
46
		'mrec'               => array(
47
			'tag'    => '300x250_mediumrectangle',
48
			'height' => '250',
49
			'width'  => '300',
50
		),
51
		'leaderboard'        => array(
52
			'tag'    => '728x90_leaderboard',
53
			'height' => '90',
54
			'width'  => '728',
55
		),
56
		'mobile_leaderboard' => array(
57
			'tag'    => '320x50_mobileleaderboard',
58
			'height' => '50',
59
			'width'  => '320',
60
		),
61
		'wideskyscraper'     => array(
62
			'tag'    => '160x600_wideskyscraper',
63
			'height' => '600',
64
			'width'  => '160',
65
		),
66
	);
67
68
	/**
69
	 * Mapping array of location slugs to placement ids
70
	 *
71
	 * @var array
72
	 */
73
	public static $ad_location_ids = array(
74
		'top'           => 110,
75
		'belowpost'     => 120,
76
		'belowpost2'    => 130,
77
		'sidebar'       => 140,
78
		'widget'        => 150,
79
		'gutenberg'     => 200,
80
		'inline'        => 310,
81
		'inline-plugin' => 320,
82
	);
83
84
	/**
85
	 * Counter to enable unique, sequential section IDs for all amp-ad units
86
	 *
87
	 * @var int
88
	 */
89
	public static $amp_section_id = 1;
90
91
	/**
92
	 * Solo unit CSS string.
93
	 *
94
	 * @var string
95
	 */
96
	public static $solo_unit_css = 'float:left;margin-right:5px;margin-top:0px;';
97
98
	/**
99
	 * Checks for AMP support and returns true iff active & AMP request
100
	 *
101
	 * @return boolean True if supported AMP request
102
	 *
103
	 * @since 7.5.0
104
	 */
105
	public static function is_amp() {
106
		return class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
107
	}
108
109
	/**
110
	 * Increment the AMP section ID and return the value
111
	 *
112
	 * @return int
113
	 */
114
	public static function get_amp_section_id() {
115
		return self::$amp_section_id++;
116
	}
117
118
	/**
119
	 * Convenience function for grabbing options from params->options
120
	 *
121
	 * @param  string $option the option to grab.
122
	 * @param  mixed  $default (optional).
123
	 * @return option or $default if not set
124
	 *
125
	 * @since 4.5.0
126
	 */
127
	public function option( $option, $default = false ) {
128
		if ( ! isset( $this->params->options[ $option ] ) ) {
129
			return $default;
130
		}
131
132
		return $this->params->options[ $option ];
133
	}
134
135
	/**
136
	 * Returns the ad tag property array for supported ad types.
137
	 *
138
	 * @return array      array with ad tags
139
	 *
140
	 * @since 7.1.0
141
	 */
142
	public function get_ad_tags() {
143
		return self::$ad_tag_ids;
144
	}
145
146
	/**
147
	 * Returns the solo css for unit
148
	 *
149
	 * @return string the special css for solo units
150
	 *
151
	 * @since 7.1.0
152
	 */
153
	public function get_solo_unit_css() {
154
		return self::$solo_unit_css;
155
	}
156
157
	/**
158
	 * Instantiate the plugin
159
	 *
160
	 * @since 4.5.0
161
	 */
162
	public function __construct() {
163
		add_action( 'wp', array( $this, 'init' ) );
164
		add_action( 'rest_api_init', array( $this, 'init' ) );
165
		add_action( 'widgets_init', array( $this, 'widget_callback' ) );
166
167
		if ( is_admin() ) {
168
			WordAds_California_Privacy::init_ajax_actions();
169
		}
170
	}
171
172
	/**
173
	 * Code to run on WordPress 'init' hook
174
	 *
175
	 * @since 4.5.0
176
	 */
177
	public function init() {
178
		require_once WORDADS_ROOT . '/php/class-wordads-params.php';
179
		$this->params = new WordAds_Params();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \WordAds_Params() of type object<WordAds_Params> is incompatible with the declared type null of property $params.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
180
181
		if ( $this->should_bail() || self::is_infinite_scroll() ) {
182
			return;
183
		}
184
185
		if ( is_admin() ) {
186
			require_once WORDADS_ROOT . '/php/class-wordads-admin.php';
187
			return;
188
		}
189
190
		$this->insert_adcode();
191
192
		// Include California Privacy Act related features if enabled.
193
		if ( $this->params->options['wordads_ccpa_enabled'] ) {
0 ignored issues
show
The property options does not seem to exist in WordAds_Params.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
194
			WordAds_California_Privacy::init();
195
		}
196
197
		if ( '/ads.txt' === $_SERVER['REQUEST_URI'] ) {
198
199
			$ads_txt_transient = get_transient( 'jetpack_ads_txt' );
200
201
			if ( false === ( $ads_txt_transient ) ) {
202
				$ads_txt_transient = ! is_wp_error( WordAds_API::get_wordads_ads_txt() ) ? WordAds_API::get_wordads_ads_txt() : '';
203
				set_transient( 'jetpack_ads_txt', $ads_txt_transient, DAY_IN_SECONDS );
204
			}
205
206
			/**
207
			 * Provide plugins a way of modifying the contents of the automatically-generated ads.txt file.
208
			 *
209
			 * @module wordads
210
			 *
211
			 * @since 6.1.0
212
			 *
213
			 * @param string WordAds_API::get_wordads_ads_txt() The contents of the ads.txt file.
214
			 */
215
			$ads_txt_content = apply_filters( 'wordads_ads_txt', $ads_txt_transient );
216
217
			http_response_code( 200 );
218
			header( 'Content-Type: text/plain; charset=utf-8' );
219
			echo esc_html( $ads_txt_content );
220
			die();
221
		}
222
	}
223
224
	/**
225
	 * Check for Jetpack's The_Neverending_Home_Page and use got_infinity
226
	 *
227
	 * @return boolean true if load came from infinite scroll
228
	 *
229
	 * @since 4.5.0
230
	 */
231
	public static function is_infinite_scroll() {
232
		return class_exists( 'The_Neverending_Home_Page' ) && The_Neverending_Home_Page::got_infinity();
233
	}
234
235
	/**
236
	 * Add the actions/filters to insert the ads. Checks for mobile or desktop.
237
	 *
238
	 * @since 4.5.0
239
	 */
240
	private function insert_adcode() {
241
		add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
242
		add_action( 'wp_head', array( $this, 'insert_head_meta' ), 20 );
243
		add_action( 'wp_head', array( $this, 'insert_head_iponweb' ), 30 );
244
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
245
		add_filter( 'wordads_ads_txt', array( $this, 'insert_custom_adstxt' ) );
246
247
		/**
248
		 * Filters enabling ads in `the_content` filter
249
		 *
250
		 * @see https://jetpack.com/support/ads/
251
		 *
252
		 * @module wordads
253
		 *
254
		 * @since 5.8.0
255
		 *
256
		 * @param bool True to disable ads in `the_content`
257
		 */
258
		if ( ! apply_filters( 'wordads_content_disable', false ) ) {
259
			add_filter( 'the_content', array( $this, 'insert_ad' ) );
260
		}
261
262
		/**
263
		 * Filters enabling ads in `the_excerpt` filter
264
		 *
265
		 * @see https://jetpack.com/support/ads/
266
		 *
267
		 * @module wordads
268
		 *
269
		 * @since 5.8.0
270
		 *
271
		 * @param bool True to disable ads in `the_excerpt`
272
		 */
273
		if ( ! apply_filters( 'wordads_excerpt_disable', false ) ) {
274
			add_filter( 'the_excerpt', array( $this, 'insert_ad' ) );
275
		}
276
277
		if ( $this->option( 'enable_header_ad', true ) ) {
278
			if ( self::is_amp() ) {
279
				add_filter( 'the_content', array( $this, 'insert_header_ad_amp' ) );
280
			} else {
281
				switch ( get_stylesheet() ) {
282
					case 'twentyseventeen':
283
					case 'twentyfifteen':
284
					case 'twentyfourteen':
285
						add_action( 'wp_footer', array( $this, 'insert_header_ad_special' ) );
286
						break;
287
					default:
288
						add_action( 'wp_head', array( $this, 'insert_header_ad' ), 100 );
289
						break;
290
				}
291
			}
292
		}
293
	}
294
295
	/**
296
	 * Register desktop scripts and styles
297
	 *
298
	 * @since 4.5.0
299
	 */
300
	public function enqueue_scripts() {
301
		wp_enqueue_style(
302
			'wordads',
303
			WORDADS_URL . 'css/style.css',
304
			array(),
305
			'2015-12-18'
306
		);
307
	}
308
309
	/**
310
	 * Add the IPW resource hints
311
	 *
312
	 * @since 7.9
313
	 *
314
	 * @param array  $hints Domains for hinting.
315
	 * @param string $relation_type Resource type.
316
	 *
317
	 * @return array Domains for hinting.
318
	 */
319
	public function resource_hints( $hints, $relation_type ) {
320
		if ( 'dns-prefetch' === $relation_type ) {
321
			$hints[] = '//s.pubmine.com';
322
			$hints[] = '//x.bidswitch.net';
323
			$hints[] = '//static.criteo.net';
324
			$hints[] = '//ib.adnxs.com';
325
			$hints[] = '//aax.amazon-adsystem.com';
326
			$hints[] = '//bidder.criteo.com';
327
			$hints[] = '//cas.criteo.com';
328
			$hints[] = '//gum.criteo.com';
329
			$hints[] = '//ads.pubmatic.com';
330
			$hints[] = '//gads.pubmatic.com';
331
			$hints[] = '//tpc.googlesyndication.com';
332
			$hints[] = '//ad.doubleclick.net';
333
			$hints[] = '//googleads.g.doubleclick.net';
334
			$hints[] = '//www.googletagservices.com';
335
			$hints[] = '//cdn.switchadhub.com';
336
			$hints[] = '//delivery.g.switchadhub.com';
337
			$hints[] = '//delivery.swid.switchadhub.com';
338
		}
339
340
		return $hints;
341
	}
342
343
	/**
344
	 * IPONWEB metadata used by the various scripts
345
	 *
346
	 * @return [type] [description]
347
	 */
348
	public function insert_head_meta() {
349
		if ( self::is_amp() ) {
350
			return;
351
		}
352
		$pagetype  = intval( $this->params->get_page_type_ipw() );
0 ignored issues
show
The method get_page_type_ipw cannot be called on $this->params (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
353
		$data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
354
		$site_id   = $this->params->blog_id;
355
		$consent   = intval( isset( $_COOKIE['personalized-ads-consent'] ) );
356
		?>
357
		<script<?php echo esc_attr( $data_tags ); ?> type="text/javascript">
358
			var __ATA_PP = { pt: <?php echo esc_js( $pagetype ); ?>, ht: 2, tn: '<?php echo esc_js( get_stylesheet() ); ?>', amp: false, siteid: <?php echo esc_js( $site_id ); ?>, consent: <?php echo esc_js( $consent ); ?> };
359
			var __ATA = __ATA || {};
360
			__ATA.cmd = __ATA.cmd || [];
361
			__ATA.criteo = __ATA.criteo || {};
362
			__ATA.criteo.cmd = __ATA.criteo.cmd || [];
363
		</script>
364
		<?php
365
	}
366
367
	/**
368
	 * IPONWEB scripts in <head>
369
	 *
370
	 * @since 4.5.0
371
	 */
372
	public function insert_head_iponweb() {
373
		if ( self::is_amp() ) {
374
			return;
375
		}
376
		$data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
377
		?>
378
		<script<?php echo esc_attr( $data_tags ); ?> type="text/javascript">
379
		(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("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}
380
		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;v.rid=u;v.createdAt=g();var w=window.__ATA||{},x="s.pubmine.com";
381
		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},"",".");
382
		(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);
383
		</script>
384
		<?php
385
	}
386
387
	/**
388
	 * Insert the ad onto the page
389
	 *
390
	 * @since 4.5.0
391
	 *
392
	 * @param string $content HTML content.
393
	 */
394
	public function insert_ad( $content ) {
395
		// Don't insert ads in feeds, or for anything but the main display. (This is required for compatibility with the Publicize module).
396
		if ( is_feed() || ! is_main_query() || ! in_the_loop() ) {
397
			return $content;
398
		}
399
		/**
400
		 * Allow third-party tools to disable the display of in post ads.
401
		 *
402
		 * @module wordads
403
		 *
404
		 * @since 4.5.0
405
		 *
406
		 * @param bool true Should the in post unit be disabled. Default to false.
407
		 */
408
		$disable = apply_filters( 'wordads_inpost_disable', false );
409
		if ( ! $this->params->should_show() || $disable ) {
0 ignored issues
show
The method should_show cannot be called on $this->params (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
410
			return $content;
411
		}
412
413
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
414
		return $content . $this->get_ad( 'belowpost', $ad_type );
415
	}
416
417
	/**
418
	 * Insert an inline ad into a post content
419
	 * Used for rendering the `wordads` shortcode.
420
	 *
421
	 * @since 6.1.0
422
	 *
423
	 * @param string $content HTML content.
424
	 */
425
	public function insert_inline_ad( $content ) {
426
		// Ad JS won't work in XML feeds.
427
		if ( is_feed() ) {
428
			return $content;
429
		}
430
		/**
431
		 * Allow third-party tools to disable the display of in post ads.
432
		 *
433
		 * @module wordads
434
		 *
435
		 * @since 4.5.0
436
		 *
437
		 * @param bool true Should the in post unit be disabled. Default to false.
438
		 */
439
		$disable = apply_filters( 'wordads_inpost_disable', false );
440
		if ( $disable ) {
441
			return $content;
442
		}
443
444
		$ad_type  = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
445
		$content .= $this->get_ad( 'inline', $ad_type );
446
		return $content;
447
	}
448
449
	/**
450
	 * Inserts ad into header
451
	 *
452
	 * @since 4.5.0
453
	 */
454
	public function insert_header_ad() {
455
		/**
456
		 * Allow third-party tools to disable the display of header ads.
457
		 *
458
		 * @module wordads
459
		 *
460
		 * @since 4.5.0
461
		 *
462
		 * @param bool true Should the header unit be disabled. Default to false.
463
		 */
464
		if ( apply_filters( 'wordads_header_disable', false ) ) {
465
			return;
466
		}
467
468
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
469
		echo $this->get_ad( 'top', $ad_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
470
	}
471
472
	/**
473
	 * Special cases for inserting header unit via JS
474
	 *
475
	 * @since 4.5.0
476
	 */
477
	public function insert_header_ad_special() {
478
		/**
479
		 * Allow third-party tools to disable the display of header ads.
480
		 *
481
		 * @module wordads
482
		 *
483
		 * @since 4.5.0
484
		 *
485
		 * @param bool true Should the header unit be disabled. Default to false.
486
		 */
487
		if ( apply_filters( 'wordads_header_disable', false ) ) {
488
			return;
489
		}
490
491
		$selector = '#content';
492
		switch ( get_stylesheet() ) {
493
			case 'twentyseventeen':
494
				$selector = '#content';
495
				break;
496
			case 'twentyfifteen':
497
				$selector = '#main';
498
				break;
499
			case 'twentyfourteen':
500
				$selector = 'article';
501
				break;
502
		}
503
504
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
505
		echo $this->get_ad( 'top', $ad_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
506
		if ( ! self::is_amp() ) {
507
			?>
508
		<script type="text/javascript">
509
			(function ( selector ) {
510
				var main = document.querySelector( selector );
511
				var headerAd = document.querySelector('.wpcnt-header');
512
513
				if ( main ) {
514
					main.parentNode.insertBefore( headerAd, main );
515
				}
516
			})( '<?php echo esc_js( $selector ); ?>' );
517
518
		</script>
519
			<?php
520
		}
521
	}
522
523
	/**
524
	 * Header unit for AMP
525
	 *
526
	 * @param string $content Content of the page.
527
	 *
528
	 * @since 7.5.0
529
	 */
530
	public function insert_header_ad_amp( $content ) {
531
532
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
533
		if ( 'house' === $ad_type ) {
534
			return $content;
535
		}
536
		return $this->get_ad( 'top_amp', $ad_type ) . $content;
537
538
	}
539
540
	/**
541
	 * Filter the latest ads.txt to include custom user entries. Strips any tags or whitespace.
542
	 *
543
	 * @param  string $adstxt The ads.txt being filtered.
544
	 * @return string         Filtered ads.txt with custom entries, if applicable.
545
	 *
546
	 * @since 6.5.0
547
	 */
548
	public function insert_custom_adstxt( $adstxt ) {
549
		if ( ! $this->option( 'wordads_custom_adstxt_enabled' ) ) {
550
			return $adstxt;
551
		}
552
553
		$custom_adstxt = trim( wp_strip_all_tags( $this->option( 'wordads_custom_adstxt' ) ) );
554
		if ( $custom_adstxt ) {
555
			$adstxt .= "\n\n#Jetpack - User Custom Entries\n";
556
			$adstxt .= $custom_adstxt . "\n";
557
		}
558
559
		return $adstxt;
560
	}
561
562
	/**
563
	 * Get the ad for the spot and type.
564
	 *
565
	 * @param  string $spot top, side, inline, or belowpost.
566
	 * @param  string $type iponweb or adsense.
567
	 */
568
	public function get_ad( $spot, $type = 'iponweb' ) {
569
		$snippet = '';
570
		if ( 'iponweb' === $type ) {
571
			// Default to mrec.
572
			$width  = 300;
573
			$height = 250;
574
575
			$section_id = WORDADS_API_TEST_ID;
576
			$snippet    = '';
577
			if ( 'top' === $spot ) {
578
				// mrec for mobile, leaderboard for desktop.
579
				$section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '2';
580
				$width      = $this->params->mobile_device ? 300 : 728;
581
				$height     = $this->params->mobile_device ? 250 : 90;
582
				$snippet    = $this->get_ad_snippet( $section_id, $height, $width, $spot );
583
			} elseif ( 'belowpost' === $spot ) {
584
				$section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '1';
585
				$width      = 300;
586
				$height     = 250;
587
588
				$snippet = $this->get_ad_snippet( $section_id, $height, $width, $spot, self::$solo_unit_css );
589
				if ( $this->option( 'wordads_second_belowpost', true ) ) {
590
					$section_id2 = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID2 : $this->params->blog_id . '4';
591
					$snippet    .= $this->get_ad_snippet( $section_id2, $height, $width, $spot . '2', 'float:left;margin-top:0px;' );
592
				}
593
			} elseif ( 'inline' === $spot ) {
594
				$section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '5';
595
				$snippet    = $this->get_ad_snippet( $section_id, $height, $width, $spot, self::$solo_unit_css );
596
			} elseif ( 'top_amp' === $spot ) {
597
				// Ad unit which can safely be inserted below title, above content in a variety of themes.
598
				$width   = $this->params->mobile_device ? 320 : 300;
599
				$height  = $this->params->mobile_device ? 50 : 250;
600
				$snippet = $this->get_ad_snippet( null, $height, $width );
601
			}
602
		} elseif ( 'house' === $type ) {
603
			$leaderboard = 'top' === $spot && ! $this->params->mobile_device;
604
			$snippet     = $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
605
			if ( 'belowpost' === $spot && $this->option( 'wordads_second_belowpost', true ) ) {
606
				$snippet .= $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
607
			}
608
		}
609
610
		return $this->get_ad_div( $spot, $snippet );
611
	}
612
613
614
	/**
615
	 * Returns the snippet to be inserted into the ad unit
616
	 *
617
	 * @param  int    $section_id Ad section.
618
	 * @param  int    $height Ad height.
619
	 * @param  int    $width Ad width.
620
	 * @param  string $location Location.
621
	 * @param  string $css CSS.
622
	 *
623
	 * @return string
624
	 *
625
	 * @since 5.7
626
	 */
627
	public function get_ad_snippet( $section_id, $height, $width, $location = '', $css = '' ) {
628
		$this->ads[] = array(
629
			'location' => $location,
630
			'width'    => $width,
631
			'height'   => $height,
632
		);
633
634
		if ( self::is_amp() ) {
635
			$height         = esc_attr( $height + 15 ); // this will ensure enough padding for "Report this ad".
636
			$width          = esc_attr( $width );
637
			$amp_section_id = esc_attr( self::get_amp_section_id() );
638
			$site_id        = esc_attr( $this->params->blog_id );
639
			return <<<HTML
640
			<amp-ad width="$width" height="$height"
641
			    type="pubmine"
642
			    data-siteid="$site_id"
643
			    data-section="$amp_section_id">
644
			</amp-ad>
645
HTML;
646
		}
647
648
		$ad_number = count( $this->ads ) . '-' . uniqid();
649
		$data_tags = $this->params->cloudflare ? ' data-cfasync="false"' : '';
650
		$css       = esc_attr( $css );
651
652
		$loc_id = 100;
653
		if ( ! empty( self::$ad_location_ids[ $location ] ) ) {
654
			$loc_id = self::$ad_location_ids[ $location ];
655
		}
656
657
		return <<<HTML
658
		<div style="padding-bottom:15px;width:{$width}px;height:{$height}px;$css">
659
			<div id="atatags-{$ad_number}">
660
				<script$data_tags type="text/javascript">
661
				__ATA.cmd.push(function() {
662
					__ATA.initSlot('atatags-{$ad_number}',  {
663
						collapseEmpty: 'before',
664
						sectionId: '{$section_id}',
665
						location: {$loc_id},
666
						width: {$width},
667
						height: {$height}
668
					});
669
				});
670
				</script>
671
			</div>
672
		</div>
673
HTML;
674
	}
675
676
	/**
677
	 * Returns the complete ad div with snippet to be inserted into the page
678
	 *
679
	 * @param  string $spot top, side, inline, or belowpost.
680
	 * @param  string $snippet The snippet to insert into the div.
681
	 * @param  array  $css_classes CSS classes.
682
	 * @return string The supporting ad unit div.
683
	 *
684
	 * @since 7.1
685
	 */
686
	public function get_ad_div( $spot, $snippet, array $css_classes = array() ) {
687
		if ( empty( $css_classes ) ) {
688
			$css_classes = array();
689
		}
690
691
		$css_classes[] = 'wpcnt';
692
		if ( 'top' === $spot ) {
693
			$css_classes[] = 'wpcnt-header';
694
		}
695
696
		$spot    = esc_attr( $spot );
697
		$classes = esc_attr( implode( ' ', $css_classes ) );
698
		$about   = esc_html__( 'Advertisements', 'jetpack' );
699
		return <<<HTML
700
		<div class="$classes">
701
			<div class="wpa">
702
				<span class="wpa-about">$about</span>
703
				<div class="u $spot">
704
					$snippet
705
				</div>
706
			</div>
707
		</div>
708
HTML;
709
	}
710
711
	/**
712
	 * Check the reasons to bail before we attempt to insert ads.
713
	 *
714
	 * @return true if we should bail (don't insert ads)
715
	 *
716
	 * @since 4.5.0
717
	 */
718
	public function should_bail() {
719
		return ! $this->option( 'wordads_approved' ) || (bool) $this->option( 'wordads_unsafe' );
720
	}
721
722
	/**
723
	 * Returns markup for HTML5 house ad base on unit
724
	 *
725
	 * @param  string $unit mrec, widesky, or leaderboard.
726
	 * @return string       markup for HTML5 house ad
727
	 *
728
	 * @since 4.7.0
729
	 */
730
	public function get_house_ad( $unit = 'mrec' ) {
731
732
		switch ( $unit ) {
733
			case 'widesky':
734
				$width  = 160;
735
				$height = 600;
736
				break;
737
			case 'leaderboard':
738
				$width  = 728;
739
				$height = 90;
740
				break;
741
			case 'mrec':
742
			default:
743
				$width  = 300;
744
				$height = 250;
745
				break;
746
		}
747
748
		return <<<HTML
749
		<iframe
750
			src="https://s0.wp.com/wp-content/blog-plugins/wordads/house/html5/$unit/index.html"
751
			width="$width"
752
			height="$height"
753
			frameborder="0"
754
			scrolling="no"
755
			marginheight="0"
756
			marginwidth="0">
757
		</iframe>
758
HTML;
759
	}
760
761
	/**
762
	 * Activation hook actions
763
	 *
764
	 * @since 4.5.0
765
	 */
766
	public static function activate() {
767
		WordAds_API::update_wordads_status_from_api();
768
	}
769
770
	/**
771
	 * Registers the widgets.
772
	 */
773
	public function widget_callback() {
774
			register_widget( 'WordAds_Sidebar_Widget' );
775
776
			$ccpa_enabled = get_option( 'wordads_ccpa_enabled' );
777
778
		if ( $ccpa_enabled ) {
779
			register_widget( 'WordAds_Ccpa_Do_Not_Sell_Link_Widget' );
780
		}
781
	}
782
}
783
784
add_action( 'jetpack_activate_module_wordads', array( 'WordAds', 'activate' ) );
785
add_action( 'jetpack_activate_module_wordads', array( 'WordAds_Cron', 'activate' ) );
786
add_action( 'jetpack_deactivate_module_wordads', array( 'WordAds_Cron', 'deactivate' ) );
787
788
global $wordads;
789
$wordads = new WordAds();
790