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