diff --git a/projects/plugins/jetpack/.phan/baseline.php b/projects/plugins/jetpack/.phan/baseline.php index 741c58a413969..26ebb777f9d7f 100644 --- a/projects/plugins/jetpack/.phan/baseline.php +++ b/projects/plugins/jetpack/.phan/baseline.php @@ -380,7 +380,6 @@ 'modules/shortcodes/ustream.php' => ['PhanTypeMismatchArgument'], 'modules/shortcodes/vimeo.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeMismatchArgument'], 'modules/shortcodes/vr.php' => ['PhanPluginDuplicateConditionalNullCoalescing'], - 'modules/shortcodes/wordads.php' => ['PhanNoopNew'], 'modules/shortcodes/youtube.php' => ['PhanRedefineFunction'], 'modules/shortlinks.php' => ['PhanPluginDuplicateExpressionAssignmentOperation', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentProbablyReal'], 'modules/simple-payments/simple-payments.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchReturn'], diff --git a/projects/plugins/jetpack/changelog/update-iponweb-to-watl-migration b/projects/plugins/jetpack/changelog/update-iponweb-to-watl-migration new file mode 100644 index 0000000000000..c66b2abb063ef --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-iponweb-to-watl-migration @@ -0,0 +1,5 @@ +Significance: patch +Type: other + +Migration of ad formats from IPONWEB to WATL + diff --git a/projects/plugins/jetpack/extensions/blocks/wordads/wordads.php b/projects/plugins/jetpack/extensions/blocks/wordads/wordads.php index 511b6a2c27015..e1d4b6ce3b8cc 100644 --- a/projects/plugins/jetpack/extensions/blocks/wordads/wordads.php +++ b/projects/plugins/jetpack/extensions/blocks/wordads/wordads.php @@ -20,6 +20,18 @@ * @since 7.1.0 */ class WordAds { + /** + * Mapping array of gutenberg ad snippet with the WordAds_Smart formats. + * + * @var array + */ + private static $gutenberg_ad_snippet_x_smart_format = array( + 'gutenberg_300x250' => 'gutenberg_rectangle', + 'gutenberg_728x90' => 'gutenberg_leaderboard', + 'gutenberg_320x50' => 'gutenberg_mobile_leaderboard', + 'gutenberg_160x600' => 'gutenberg_skyscraper', + ); + /** * Check if site is on WP.com Simple. * @@ -127,10 +139,35 @@ public static function gutenblock_render( $attr ) { $format = $attr['format']; } - $height = $ad_tag_ids[ $format ]['height']; - $width = $ad_tag_ids[ $format ]['width']; - $snippet = $wordads->get_ad_snippet( $section_id, $height, $width, 'gutenberg', $wordads->get_solo_unit_css() ); - return $wordads->get_ad_div( 'inline', $snippet, array( $align ) ); + $height = $ad_tag_ids[ $format ]['height']; + $width = $ad_tag_ids[ $format ]['width']; + $location = 'gutenberg'; + $snippet = $wordads->get_ad_snippet( $section_id, $height, $width, $location, $wordads->get_solo_unit_css() ); + + $key = "{$location}_{$width}x{$height}"; + $smart_format = self::$gutenberg_ad_snippet_x_smart_format[ $key ] ?? null; + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $is_watl_enabled = $smart_format && ( isset( $_GET[ $smart_format ] ) && 'true' === $_GET[ $smart_format ] ); + $ad_div = $wordads->get_ad_div( 'inline', $snippet, array( $align ) ); + // Render IPW div if WATL is not enabled. + if ( ! $is_watl_enabled ) { + return $ad_div; + } + + // Remove linebreaks and sanitize. + $snippet = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $ad_div ) ); + + // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped + $fallback_snippet = << + var sas_fallback = sas_fallback || []; + sas_fallback.push( + { tag: "$snippet", type: '$smart_format' } + ); + +HTML; + + return $fallback_snippet . $wordads->get_watl_ad_html_tag( $smart_format ); } } diff --git a/projects/plugins/jetpack/modules/shortcodes/wordads.php b/projects/plugins/jetpack/modules/shortcodes/wordads.php deleted file mode 100644 index 5f91213e3a241..0000000000000 --- a/projects/plugins/jetpack/modules/shortcodes/wordads.php +++ /dev/null @@ -1,80 +0,0 @@ -' . __( 'The WordAds module is not active', 'jetpack' ) . ''; - } - - $html = '
'; - $html = $wordads->insert_inline_ad( $html ); - - return $html; - } -} - -new Jetpack_WordAds_Shortcode(); diff --git a/projects/plugins/jetpack/modules/wordads/class-wordads.php b/projects/plugins/jetpack/modules/wordads/class-wordads.php index 851b093d750b3..c02922d44d055 100644 --- a/projects/plugins/jetpack/modules/wordads/class-wordads.php +++ b/projects/plugins/jetpack/modules/wordads/class-wordads.php @@ -21,6 +21,7 @@ require_once WORDADS_ROOT . '/php/class-wordads-ccpa-do-not-sell-link-widget.php'; require_once WORDADS_ROOT . '/php/class-wordads-consent-management-provider.php'; require_once WORDADS_ROOT . '/php/class-wordads-smart.php'; +require_once WORDADS_ROOT . '/php/class-wordads-shortcode.php'; /** * Primary WordAds class. @@ -215,6 +216,9 @@ public function init() { WordAds_Consent_Management_Provider::init(); } + // Initialize [wordads] shortcode. + WordAds_Shortcode::init(); + // Initialize Smart. WordAds_Smart::instance()->init( $this->params ); @@ -371,9 +375,43 @@ public function insert_head_meta() { $site_id = $this->params->blog_id; $consent = (int) isset( $_COOKIE['personalized-ads-consent'] ); $is_logged_in = is_user_logged_in() ? '1' : '0'; + + $disabled_slot_formats = apply_filters( 'wordads_disabled_slot_formats', array() ); + + if ( apply_filters( 'wordads_iponweb_bottom_sticky_ad_disable', false ) ) { + $disabled_slot_formats[] = 'MTS'; + } + + if ( apply_filters( 'wordads_iponweb_sidebar_sticky_right_ad_disable', false ) ) { + $disabled_slot_formats[] = 'DPR'; + } + + $config = array( + 'pt' => $pagetype, + 'ht' => $hosting_type, + 'tn' => get_stylesheet(), + 'uloggedin' => $is_logged_in, + 'amp' => false, + 'siteid' => $site_id, + 'consent' => $consent, + 'ad' => array( + 'label' => array( + 'text' => __( 'Advertisements', 'jetpack' ), + ), + 'reportAd' => array( + 'text' => __( 'Report this ad', 'jetpack' ), + ), + 'privacySettings' => array( + 'text' => __( 'Privacy', 'jetpack' ), + 'onClick' => 'js:function() { window.__tcfapi && window.__tcfapi(\'showUi\'); }', + ), + ), + 'disabled_slot_formats' => $disabled_slot_formats, + ); + $js_config = WordAds_Array_Utils::array_to_js_object( $config ); ?> params->blog_id . 5; + + // Get below post tag. + $tag_belowpost = $this->get_fallback_ad_snippet( $section_id, 'square', 'belowpost', '', '{{unique_id}}' ); + + // Remove linebreaks and sanitize. + $tag_belowpost = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_belowpost ) ); + // Get an inline tag with a macro as id handled on JS side to use as a fallback. - $tag_inline = $this->get_dynamic_ad_snippet( $this->params->blog_id . 5, 'square', 'inline', '', '{{unique_id}}' ); + $tag_inline = $this->get_fallback_ad_snippet( $section_id, 'square', 'inline', '', '{{unique_id}}' ); // Remove linebreaks and sanitize. $tag_inline = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_inline ) ); + // Get top tag. + $tag_top = $this->get_fallback_ad_snippet( $section_id, 'leaderboard', 'top', '', '{{unique_id}}' ); + + // Remove linebreaks and sanitize. + $tag_top = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $tag_top ) ); + // phpcs:disable WordPress.Security.EscapeOutput.HeredocOutputNotEscaped echo << + HTML; @@ -477,8 +531,15 @@ public function insert_inline_ad( $content ) { } $ad_type = $this->option( 'wordads_house' ) ? 'house' : 'iponweb'; - $content .= $this->get_ad( 'inline', $ad_type ); - return $content; + $location = 'shortcode'; + + // Not house ad and WATL enabled. + // phpcs:disable WordPress.Security.NonceVerification.Recommended + if ( 'house' !== $ad_type && ( isset( $_GET['wordads-logging'] ) && isset( $_GET[ $location ] ) && 'true' === $_GET[ $location ] ) ) { + return $content . $this->get_watl_ad_html_tag( $location ); + } + + return $content . $this->get_ad( 'inline', $ad_type ); } /** @@ -720,6 +781,32 @@ public function get_ad_snippet( $section_id, $height, $width, $location = '', $c * @since 8.7 */ public function get_dynamic_ad_snippet( $section_id, $form_factor = 'square', $location = '', $relocate = '', $id = null ) { + + // Allow overriding and printing of the tag parsed by the WATL. + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $is_location_enabled = isset( $_GET['wordads-logging'] ) && isset( $_GET[ $location ] ) && 'true' === $_GET[ $location ]; + + if ( ( 'top' === $location || 'belowpost' === $location ) && $is_location_enabled ) { + return self::get_watl_ad_html_tag( $location ); + } + + return $this->get_fallback_ad_snippet( $section_id, $form_factor, $location, $relocate, $id ); + } + + /** + * Returns the fallback dynamic snippet to be inserted into the ad unit + * + * @param int $section_id section_id. + * @param string $form_factor form_factor. + * @param string $location location. + * @param string $relocate location to be moved after the fact for themes without required hook. + * @param string | null $id A unique string ID or placeholder. + * + * @return string + * + * @since 8.7 + */ + public function get_fallback_ad_snippet( $section_id, $form_factor = 'square', $location = '', $relocate = '', $id = null ) { $div_id = 'atatags-' . $section_id . '-' . ( $id ?? uniqid() ); $div_id = esc_attr( $div_id ); @@ -868,6 +955,19 @@ public function get_house_ad( $unit = 'mrec' ) { HTML; } + /** + * Returns the html ad tag used by WordAds Tag Library + * + * @param string $slot_type e.g belowpost, gutenberg_rectangle. + * + * @return string + * + * @since 8.7 + */ + public static function get_watl_ad_html_tag( string $slot_type ): string { + return ""; + } + /** * Activation hook actions * diff --git a/projects/plugins/jetpack/modules/wordads/php/class-wordads-params.php b/projects/plugins/jetpack/modules/wordads/php/class-wordads-params.php index ece3e6488bc51..8707b1d43d871 100644 --- a/projects/plugins/jetpack/modules/wordads/php/class-wordads-params.php +++ b/projects/plugins/jetpack/modules/wordads/php/class-wordads-params.php @@ -71,6 +71,13 @@ class WordAds_Params { */ public $page_type_ipw; + /** + * Is this an AMP request? + * + * @var bool + */ + public $is_amp; + /** * Setup parameters for serving the ads * @@ -79,22 +86,24 @@ class WordAds_Params { public function __construct() { // WordAds setting => default. $settings = array( - 'wordads_approved' => false, - 'wordads_active' => false, - 'wordads_house' => true, - 'wordads_unsafe' => false, - 'enable_header_ad' => true, - 'wordads_second_belowpost' => true, - 'wordads_inline_enabled' => true, - 'wordads_display_front_page' => true, - 'wordads_display_post' => true, - 'wordads_display_page' => true, - 'wordads_display_archive' => true, - 'wordads_custom_adstxt' => '', - 'wordads_custom_adstxt_enabled' => false, - 'wordads_ccpa_enabled' => false, - 'wordads_ccpa_privacy_policy_url' => get_option( 'wp_page_for_privacy_policy' ) ? get_permalink( (int) get_option( 'wp_page_for_privacy_policy' ) ) : '', - 'wordads_cmp_enabled' => false, + 'wordads_approved' => false, + 'wordads_active' => false, + 'wordads_house' => true, + 'wordads_unsafe' => false, + 'enable_header_ad' => true, + 'wordads_second_belowpost' => true, + 'wordads_inline_enabled' => true, + 'wordads_bottom_sticky_enabled' => false, + 'wordads_sidebar_sticky_right_enabled' => false, + 'wordads_display_front_page' => true, + 'wordads_display_post' => true, + 'wordads_display_page' => true, + 'wordads_display_archive' => true, + 'wordads_custom_adstxt' => '', + 'wordads_custom_adstxt_enabled' => false, + 'wordads_ccpa_enabled' => false, + 'wordads_ccpa_privacy_policy_url' => get_option( 'wp_page_for_privacy_policy' ) ? get_permalink( (int) get_option( 'wp_page_for_privacy_policy' ) ) : '', + 'wordads_cmp_enabled' => false, ); // Grab settings, or set as default if it doesn't exist. @@ -136,6 +145,7 @@ public function __construct() { 'LangId' => str_contains( get_bloginfo( 'language' ), 'en' ) ? 1 : 0, // TODO something else? 'AdSafe' => 1, // TODO. ); + $this->is_amp = function_exists( 'amp_is_request' ) && amp_is_request(); } /** diff --git a/projects/plugins/jetpack/modules/wordads/php/class-wordads-shortcode.php b/projects/plugins/jetpack/modules/wordads/php/class-wordads-shortcode.php new file mode 100644 index 0000000000000..0f7a9a5d48ec5 --- /dev/null +++ b/projects/plugins/jetpack/modules/wordads/php/class-wordads-shortcode.php @@ -0,0 +1,48 @@ +' . __( 'The WordAds module is not active', 'jetpack' ) . ''; + } + + $html = ''; + + return $wordads->insert_inline_ad( $html ); + } +} diff --git a/projects/plugins/jetpack/modules/wordads/php/class-wordads-sidebar-widget.php b/projects/plugins/jetpack/modules/wordads/php/class-wordads-sidebar-widget.php index 7b1b7b5f6de77..63cb75ceebe3b 100644 --- a/projects/plugins/jetpack/modules/wordads/php/class-wordads-sidebar-widget.php +++ b/projects/plugins/jetpack/modules/wordads/php/class-wordads-sidebar-widget.php @@ -19,6 +19,17 @@ class WordAds_Sidebar_Widget extends WP_Widget { */ private static $allowed_tags = array( 'mrec', 'wideskyscraper', 'leaderboard' ); + /** + * Mapping array of widget sizes with the WordAds_Smart formats. + * + * @var string[] + */ + private static $sizes_x_smart_format = array( + '300x250' => 'sidebar_widget_mediumrectangle', + '728x90' => 'sidebar_widget_leaderboard', + '160x600' => 'sidebar_widget_wideskyscraper', + ); + /** * Number of widgets. * @@ -74,7 +85,6 @@ public function widget( $args, $instance ) { } ++self::$num_widgets; - $about = __( 'Advertisements', 'jetpack' ); $width = WordAds::$ad_tag_ids[ $instance['unit'] ]['width']; $height = WordAds::$ad_tag_ids[ $instance['unit'] ]['height']; $unit_id = 1 === self::$num_widgets ? 3 : self::$num_widgets + 3; // 2nd belowpost is '4' @@ -82,7 +92,50 @@ public function widget( $args, $instance ) { WORDADS_API_TEST_ID : $wordads->params->blog_id . $unit_id; - $snippet = ''; + $smart_format = self::$sizes_x_smart_format[ "{$width}x{$height}" ]; + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $is_watl_enabled = isset( $_GET['wordads-logging'] ) && isset( $_GET[ $smart_format ] ) && 'true' === $_GET[ $smart_format ]; + + // Get the widget snippet. + $widget_snippet = $this->get_widget_snippet( $instance, $section_id, $height, $width ); + + // Render the IPW or house ad if WATL is disabled. + if ( ! $is_watl_enabled ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $widget_snippet; + return; + } + + // Remove linebreaks and sanitize. + $tag = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $widget_snippet ) ); + + // Add the fallback to be processed by WATL. + $fallback_snippet = << + var sas_fallback = sas_fallback || []; + sas_fallback.push( + { tag: "$tag", type: '$smart_format' } + ); + +HTML; + + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $fallback_snippet . $wordads::get_watl_ad_html_tag( $smart_format ); + } + + /** + * The widget snippet. + * + * @param array $instance The widget instance. + * @param string $section_id The section id. + * @param int $height The ad height. + * @param int $width The ad width. + * + * @return string + */ + private function get_widget_snippet( $instance, $section_id, $height, $width ) { + global $wordads; + if ( $wordads->option( 'wordads_house', true ) ) { $unit = 'mrec'; if ( 'leaderboard' === $instance['unit'] && ! $this->params->mobile_device ) { @@ -93,21 +146,22 @@ public function widget( $args, $instance ) { $snippet = $wordads->get_house_ad( $unit ); } else { - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo $wordads->get_ad_snippet( $section_id, $height, $width, 'widget' ); - return; + return $wordads->get_ad_snippet( $section_id, $height, $width, 'widget' ); } - ?> + $about = __( 'Advertisements', 'jetpack' ); + $unit = esc_attr( $instance['unit'] ); + + return <<