Completed
Push — add/gdpr-ads-compliance ( a4f9cb...147584 )
by
unknown
35:40 queued 23:31
created

WordAds::insert_ad()   C

Complexity

Conditions 7
Paths 4

Size

Total Lines 22
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 8
nc 4
nop 1
dl 0
loc 22
rs 6.9811
c 0
b 0
f 0
1
<?php
2
3
define( 'WORDADS_ROOT', dirname( __FILE__ ) );
4
define( 'WORDADS_BASENAME', plugin_basename( __FILE__ ) );
5
define( 'WORDADS_FILE_PATH', WORDADS_ROOT . '/' . basename( __FILE__ ) );
6
define( 'WORDADS_URL', plugins_url( '/', __FILE__ ) );
7
define( 'WORDADS_API_TEST_ID', '26942' );
8
define( 'WORDADS_API_TEST_ID2', '114160' );
9
10
require_once( WORDADS_ROOT . '/php/widgets.php' );
11
require_once( WORDADS_ROOT . '/php/api.php' );
12
require_once( WORDADS_ROOT . '/php/cron.php' );
13
14
class WordAds {
15
16
	public $params = null;
17
18
	public $ads = array();
19
20
	/**
21
	 * Array of supported ad types.
22
	 *
23
	 * @var array
24
	 */
25
	public static $ad_tag_ids = array(
26
		'mrec' => array(
27
			'tag'       => '300x250_mediumrectangle',
28
			'height'    => '250',
29
			'width'     => '300',
30
		),
31
		'lrec' => array(
32
			'tag'       => '336x280_largerectangle',
33
			'height'    => '280',
34
			'width'     => '336',
35
		),
36
		'leaderboard' => array(
37
			'tag'       => '728x90_leaderboard',
38
			'height'    => '90',
39
			'width'     => '728',
40
		),
41
		'wideskyscraper' => array(
42
			'tag'       => '160x600_wideskyscraper',
43
			'height'    => '600',
44
			'width'     => '160',
45
		),
46
	);
47
48
	/**
49
	 * Convenience function for grabbing options from params->options
50
	 *
51
	 * @param  string $option the option to grab
52
	 * @param  mixed  $default (optional)
53
	 * @return option or $default if not set
54
	 *
55
	 * @since 4.5.0
56
	 */
57
	function option( $option, $default = false ) {
58
		if ( ! isset( $this->params->options[ $option ] ) ) {
59
			return $default;
60
		}
61
62
		return $this->params->options[ $option ];
63
	}
64
65
	/**
66
	 * Instantiate the plugin
67
	 *
68
	 * @since 4.5.0
69
	 */
70
	function __construct() {
71
		add_action( 'init', array( $this, 'init' ) );
72
	}
73
74
	/**
75
	 * Code to run on WordPress 'init' hook
76
	 *
77
	 * @since 4.5.0
78
	 */
79
	function init() {
80
		// bail on infinite scroll
81
		if ( self::is_infinite_scroll() ) {
82
			return;
83
		}
84
85
		require_once( WORDADS_ROOT . '/php/params.php' );
86
		$this->params = new WordAds_Params();
87
88
		if ( is_admin() ) {
89
			require_once( WORDADS_ROOT . '/php/admin.php' );
90
			return;
91
		}
92
93
		if ( $this->should_bail() ) {
94
			return;
95
		}
96
97
		$this->insert_adcode();
98
99
		if ( '/ads.txt' === $_SERVER['REQUEST_URI'] ) {
100
101
			if ( false === ( $ads_txt_transient = get_transient( 'jetpack_ads_txt' ) ) ) {
102
				$ads_txt_transient = ! is_wp_error( WordAds_API::get_wordads_ads_txt() ) ? WordAds_API::get_wordads_ads_txt() : '';
103
				set_transient( 'jetpack_ads_txt', $ads_txt_transient, DAY_IN_SECONDS );
104
			}
105
106
			/**
107
			 * Provide plugins a way of modifying the contents of the automatically-generated ads.txt file.
108
			 *
109
			 * @module wordads
110
			 *
111
			 * @since 6.1.0
112
			 *
113
			 * @param string WordAds_API::get_wordads_ads_txt() The contents of the ads.txt file.
114
			 */
115
			$ads_txt_content = apply_filters( 'wordads_ads_txt', $ads_txt_transient );
116
117
			header( 'Content-Type: text/plain; charset=utf-8' );
118
			echo esc_html( $ads_txt_content );
119
			die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
120
		}
121
	}
122
123
	/**
124
	 * Check for Jetpack's The_Neverending_Home_Page and use got_infinity
125
	 *
126
	 * @return boolean true if load came from infinite scroll
127
	 *
128
	 * @since 4.5.0
129
	 */
130
	public static function is_infinite_scroll() {
131
		return class_exists( 'The_Neverending_Home_Page' ) && The_Neverending_Home_Page::got_infinity();
132
	}
133
134
	/**
135
	 * Add the actions/filters to insert the ads. Checks for mobile or desktop.
136
	 *
137
	 * @since 4.5.0
138
	 */
139
	private function insert_adcode() {
140
		add_action( 'wp_head',              array( $this, 'insert_head_meta' ), 20 );
141
		add_action( 'wp_head',              array( $this, 'insert_head_iponweb' ), 30 );
142
		add_action( 'wp_enqueue_scripts',   array( $this, 'enqueue_scripts' ) );
143
144
		/**
145
		 * Filters enabling ads in `the_content` filter
146
		 *
147
		 * @see https://jetpack.com/support/ads/
148
		 *
149
		 * @module wordads
150
		 *
151
		 * @since 5.8.0
152
		 *
153
		 * @param bool True to disable ads in `the_content`
154
		 */
155
		if ( ! apply_filters( 'wordads_content_disable', false ) ) {
156
			add_filter( 'the_content', array( $this, 'insert_ad' ) );
157
		}
158
159
		/**
160
		 * Filters enabling ads in `the_excerpt` filter
161
		 *
162
		 * @see https://jetpack.com/support/ads/
163
		 *
164
		 * @module wordads
165
		 *
166
		 * @since 5.8.0
167
		 *
168
		 * @param bool True to disable ads in `the_excerpt`
169
		 */
170
		if ( ! apply_filters( 'wordads_excerpt_disable', false ) ) {
171
			add_filter( 'the_excerpt', array( $this, 'insert_ad' ) );
172
		}
173
174
		if ( $this->option( 'enable_header_ad', true ) ) {
175
			switch ( get_stylesheet() ) {
176
				case 'twentyseventeen':
177
				case 'twentyfifteen':
178
				case 'twentyfourteen':
179
					add_action( 'wp_footer', array( $this, 'insert_header_ad_special' ) );
180
					break;
181
				default:
182
					add_action( 'wp_head', array( $this, 'insert_header_ad' ), 100 );
183
					break;
184
			}
185
		}
186
	}
187
188
	/**
189
	 * Register desktop scripts and styles
190
	 *
191
	 * @since 4.5.0
192
	 */
193
	function enqueue_scripts() {
194
		wp_enqueue_style(
195
			'wordads',
196
			WORDADS_URL . 'css/style.css',
197
			array(),
198
			'2015-12-18'
199
		);
200
	}
201
202
	/**
203
	 * IPONWEB metadata used by the various scripts
204
	 * @return [type] [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
205
	 */
206
	function insert_head_meta() {
207
		$themename = esc_js( get_stylesheet() );
208
		$pagetype = intval( $this->params->get_page_type_ipw() );
209
		$data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
210
		$site_id = $this->params->blog_id;
211
		$consent = intval( isset( $_COOKIE['personalized-ads-consent'] ) );
212
		echo <<<HTML
213
		<script$data_tags type="text/javascript">
214
			var __ATA_PP = { pt: $pagetype, ht: 2, tn: '$themename', amp: false, siteid: $site_id, consent: $consent };
215
			var __ATA = __ATA || {};
216
			__ATA.cmd = __ATA.cmd || [];
217
			__ATA.criteo = __ATA.criteo || {};
218
			__ATA.criteo.cmd = __ATA.criteo.cmd || [];
219
		</script>
220
HTML;
221
	}
222
223
	/**
224
	 * IPONWEB scripts in <head>
225
	 *
226
	 * @since 4.5.0
227
	 */
228
	function insert_head_iponweb() {
229
		$data_tags = ( $this->params->cloudflare ) ? ' data-cfasync="false"' : '';
230
		echo <<<HTML
231
		<link rel='dns-prefetch' href='//s.pubmine.com' />
232
		<link rel='dns-prefetch' href='//x.bidswitch.net' />
233
		<link rel='dns-prefetch' href='//static.criteo.net' />
234
		<link rel='dns-prefetch' href='//ib.adnxs.com' />
235
		<link rel='dns-prefetch' href='//aax.amazon-adsystem.com' />
236
		<link rel='dns-prefetch' href='//bidder.criteo.com' />
237
		<link rel='dns-prefetch' href='//cas.criteo.com' />
238
		<link rel='dns-prefetch' href='//gum.criteo.com' />
239
		<link rel='dns-prefetch' href='//ads.pubmatic.com' />
240
		<link rel='dns-prefetch' href='//gads.pubmatic.com' />
241
		<link rel='dns-prefetch' href='//tpc.googlesyndication.com' />
242
		<link rel='dns-prefetch' href='//ad.doubleclick.net' />
243
		<link rel='dns-prefetch' href='//googleads.g.doubleclick.net' />
244
		<link rel='dns-prefetch' href='//www.googletagservices.com' />
245
		<script$data_tags async type="text/javascript" src="//s.pubmine.com/head.js"></script>
246
HTML;
247
	}
248
249
	/**
250
	 * Insert the ad onto the page
251
	 *
252
	 * @since 4.5.0
253
	 */
254
	function insert_ad( $content ) {
255
		// Don't insert ads in feeds, or for anything but the main display. (This is required for compatibility with the Publicize module).
256
		if ( is_feed() || ! is_main_query() || ! in_the_loop() ) {
257
			return $content;
258
		}
259
		/**
260
		 * Allow third-party tools to disable the display of in post ads.
261
		 *
262
		 * @module wordads
263
		 *
264
		 * @since 4.5.0
265
		 *
266
		 * @param bool true Should the in post unit be disabled. Default to false.
267
		 */
268
		$disable = apply_filters( 'wordads_inpost_disable', false );
269
		if ( ! $this->params->should_show() || $disable ) {
270
			return $content;
271
		}
272
273
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
274
		return $content . $this->get_ad( 'belowpost', $ad_type );
275
	}
276
277
	/**
278
	 * Insert an inline ad into a post content
279
	 * Used for rendering the `wordads` shortcode.
280
	 *
281
	 * @since 6.1.0
282
	 */
283
	function insert_inline_ad( $content ) {
284
		// Ad JS won't work in XML feeds.
285
		if ( is_feed() ) {
286
			return $content;
287
		}
288
		/**
289
		 * Allow third-party tools to disable the display of in post ads.
290
		 *
291
		 * @module wordads
292
		 *
293
		 * @since 4.5.0
294
		 *
295
		 * @param bool true Should the in post unit be disabled. Default to false.
296
		 */
297
		$disable = apply_filters( 'wordads_inpost_disable', false );
298
		if ( $disable ) {
299
			return $content;
300
		}
301
302
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
303
		$content .= $this->get_ad( 'inline', $ad_type );
304
		return $content;
305
	}
306
307
	/**
308
	 * Inserts ad into header
309
	 *
310
	 * @since 4.5.0
311
	 */
312
	function insert_header_ad() {
313
		/**
314
		 * Allow third-party tools to disable the display of header ads.
315
		 *
316
		 * @module wordads
317
		 *
318
		 * @since 4.5.0
319
		 *
320
		 * @param bool true Should the header unit be disabled. Default to false.
321
		 */
322
		if ( apply_filters( 'wordads_header_disable', false ) ) {
323
			return;
324
		}
325
326
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
327
		echo $this->get_ad( 'top', $ad_type );
328
	}
329
330
	/**
331
	 * Special cases for inserting header unit via jQuery
332
	 *
333
	 * @since 4.5.0
334
	 */
335
	function insert_header_ad_special() {
336
		/**
337
		 * Allow third-party tools to disable the display of header ads.
338
		 *
339
		 * @module wordads
340
		 *
341
		 * @since 4.5.0
342
		 *
343
		 * @param bool true Should the header unit be disabled. Default to false.
344
		 */
345
		if ( apply_filters( 'wordads_header_disable', false ) ) {
346
			return;
347
		}
348
349
		$selector = '#content';
350
		switch ( get_stylesheet() ) {
351
			case 'twentyseventeen':
352
				$selector = '#content';
353
				break;
354
			case 'twentyfifteen':
355
				$selector = '#main';
356
				break;
357
			case 'twentyfourteen':
358
				$selector = 'article:first';
359
				break;
360
		}
361
362
		$ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb';
363
		echo $this->get_ad( 'top', $ad_type );
364
		echo <<<HTML
365
		<script type="text/javascript">
366
			jQuery('.wpcnt-header').insertBefore('$selector');
367
		</script>
368
HTML;
369
	}
370
371
	/**
372
	 * Get the ad for the spot and type.
373
	 * @param  string $spot top, side, inline, or belowpost
374
	 * @param  string $type iponweb or adsense
375
	 */
376
	function get_ad( $spot, $type = 'iponweb' ) {
377
		$snippet = '';
378
		if ( 'iponweb' == $type ) {
379
			// Default to mrec
380
			$width = 300;
381
			$height = 250;
382
383
			$section_id = WORDADS_API_TEST_ID;
0 ignored issues
show
Unused Code introduced by
$section_id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
384
			$second_belowpost = '';
0 ignored issues
show
Unused Code introduced by
$second_belowpost is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
385
			$snippet = '';
386
			if ( 'top' == $spot ) {
387
				// mrec for mobile, leaderboard for desktop
388
				$section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '2';
389
				$width = $this->params->mobile_device ? 300 : 728;
390
				$height = $this->params->mobile_device ? 250 : 90;
391
				$snippet = $this->get_ad_snippet( $section_id, $height, $width, $spot );
392
			} else if ( 'belowpost' == $spot ) {
393
				$section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '1';
394
				$width = 300;
395
				$height = 250;
396
397
				$snippet = $this->get_ad_snippet( $section_id, $height, $width, $spot, 'float:left;margin-right:5px;margin-top:0px;' );
398
				if ( $this->option( 'wordads_second_belowpost', true ) ) {
399
					$section_id2 = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID2 : $this->params->blog_id . '4';
400
					$snippet .= $this->get_ad_snippet( $section_id2, $height, $width, $spot, 'float:left;margin-top:0px;' );
401
				}
402
			} else if ( 'inline' === $spot ) {
403
				$section_id = 0 === $this->params->blog_id ? WORDADS_API_TEST_ID : $this->params->blog_id . '5';
404
				$snippet = $this->get_ad_snippet( $section_id, $height, $width, $spot, 'mrec', 'float:left;margin-right:5px;margin-top:0px;' );
0 ignored issues
show
Unused Code introduced by
The call to WordAds::get_ad_snippet() has too many arguments starting with 'float:left;margin-right:5px;margin-top:0px;'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
405
			}
406
		} else if ( 'house' == $type ) {
407
			$leaderboard = 'top' == $spot && ! $this->params->mobile_device;
408
			$snippet = $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
409
			if ( 'belowpost' == $spot && $this->option( 'wordads_second_belowpost', true ) ) {
410
				$snippet .= $this->get_house_ad( $leaderboard ? 'leaderboard' : 'mrec' );
411
			}
412
		}
413
414
		$header = 'top' == $spot ? 'wpcnt-header' : '';
415
		$about = __( 'Advertisements', 'jetpack' );
416
		return <<<HTML
417
		<div class="wpcnt $header">
418
			<div class="wpa">
419
				<span class="wpa-about">$about</span>
420
				<div class="u $spot">
421
					$snippet
422
				</div>
423
			</div>
424
		</div>
425
HTML;
426
	}
427
428
429
	/**
430
	 * Returns the snippet to be inserted into the ad unit
431
	 * @param  int $section_id
432
	 * @param  int $height
433
	 * @param  int $width
434
	 * @param  int $location
0 ignored issues
show
Documentation introduced by
Should the type for parameter $location not be string|integer?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
435
	 * @param  string $css
436
	 * @return string
437
	 *
438
	 * @since 5.7
439
	 */
440
	function get_ad_snippet( $section_id, $height, $width, $location = '', $css = '' ) {
441
		$this->ads[] = array( 'location' => $location, 'width' => $width, 'height' => $height );
442
		$ad_number = count( $this->ads );
443
		// Max 6 ads per page.
444
		if ( $ad_number > 5 && 'top' !== $location ) {
445
			return;
446
		}
447
		$data_tags = $this->params->cloudflare ? ' data-cfasync="false"' : '';
448
449
		return <<<HTML
450
		<div style="padding-bottom:15px;width:{$width}px;height:{$height}px;$css">
451
			<div id="atatags-{$ad_number}">
452
				<script$data_tags type="text/javascript">
453
				__ATA.cmd.push(function() {
454
					__ATA.initSlot('atatags-{$ad_number}',  {
455
						collapseEmpty: 'before',
456
						sectionId: '{$section_id}',
457
						location: '{$location}',
458
						width: {$width},
459
						height: {$height}
460
					});
461
				});
462
				</script>
463
			</div>
464
		</div>
465
HTML;
466
	}
467
468
	/**
469
	 * Check the reasons to bail before we attempt to insert ads.
470
	 * @return true if we should bail (don't insert ads)
471
	 *
472
	 * @since 4.5.0
473
	 */
474
	public function should_bail() {
475
		return ! $this->option( 'wordads_approved' );
476
	}
477
478
	/**
479
	 * Returns markup for HTML5 house ad base on unit
480
	 * @param  string $unit mrec, widesky, or leaderboard
481
	 * @return string       markup for HTML5 house ad
482
	 *
483
	 * @since 4.7.0
484
	 */
485
	public function get_house_ad( $unit = 'mrec' ) {
486
487
		switch ( $unit ) {
488
			case 'widesky':
489
				$width  = 160;
490
				$height = 600;
491
				break;
492
			case 'leaderboard':
493
				$width  = 728;
494
				$height = 90;
495
				break;
496
			case 'mrec':
497
			default:
498
				$width  = 300;
499
				$height = 250;
500
				break;
501
		}
502
503
		return <<<HTML
504
		<iframe
505
			src="https://s0.wp.com/wp-content/blog-plugins/wordads/house/html5/$unit/index.html"
506
			width="$width"
507
			height="$height"
508
			frameborder="0"
509
			scrolling="no"
510
			marginheight="0"
511
			marginwidth="0">
512
		</iframe>
513
HTML;
514
	}
515
516
	/**
517
	 * Activation hook actions
518
	 *
519
	 * @since 4.5.0
520
	 */
521
	public static function activate() {
522
		WordAds_API::update_wordads_status_from_api();
523
	}
524
}
525
526
add_action( 'jetpack_activate_module_wordads', array( 'WordAds', 'activate' ) );
527
add_action( 'jetpack_activate_module_wordads', array( 'WordAds_Cron', 'activate' ) );
528
add_action( 'jetpack_deactivate_module_wordads', array( 'WordAds_Cron', 'deactivate' ) );
529
530
global $wordads;
531
$wordads = new WordAds();
532