diff --git a/includes/sanitizers/class-amp-img-sanitizer.php b/includes/sanitizers/class-amp-img-sanitizer.php index 77666faa747..9188ac2f05e 100644 --- a/includes/sanitizers/class-amp-img-sanitizer.php +++ b/includes/sanitizers/class-amp-img-sanitizer.php @@ -183,6 +183,26 @@ public function sanitize() { continue; } + // Replace img with amp-pixel when dealing with tracking pixels. + if ( self::is_tracking_pixel_url( $node->getAttribute( Attribute::SRC ) ) ) { + $attributes = [ + Attribute::SRC => $node->getAttribute( Attribute::SRC ), + Attribute::LAYOUT => Layout::NODISPLAY, + ]; + foreach ( [ Attribute::REFERRERPOLICY ] as $allowed_attribute ) { + if ( $node->hasAttribute( $allowed_attribute ) ) { + $attributes[ $allowed_attribute ] = $node->getAttribute( $allowed_attribute ); + } + } + $amp_pixel_node = AMP_DOM_Utils::create_node( + $this->dom, + Extension::PIXEL, + $attributes + ); + $node->parentNode->replaceChild( $amp_pixel_node, $node ); + continue; + } + // Short-circuit emoji images from needing to make requests out to https://s.w.org/. if ( 'wp-smiley' === $node->getAttribute( Attribute::CLASS_ ) ) { $node->setAttribute( Attribute::WIDTH, '72' ); @@ -552,4 +572,27 @@ private function is_gif_url( $url ) { $path = wp_parse_url( $url, PHP_URL_PATH ); return substr( $path, -strlen( $ext ) ) === $ext; } + + /** + * Determines if a URL is a known tracking pixel URL. + * + * Currently, only Facebook tracking pixel URL is detected. + * + * @since 2.2.2 + * + * @param string $url URL to inspect. + * + * @return bool Returns true if $url is a tracking pixel URL. + */ + private static function is_tracking_pixel_url( $url ) { + $parsed_url = wp_parse_url( $url ); + + return ( + isset( $parsed_url['host'], $parsed_url['path'] ) + && + 'facebook.com' === str_replace( 'www.', '', $parsed_url['host'] ) + && + '/tr' === $parsed_url['path'] + ); + } } diff --git a/tests/php/test-amp-img-sanitizer.php b/tests/php/test-amp-img-sanitizer.php index c2d083ac4b2..9742e32fbfb 100644 --- a/tests/php/test-amp-img-sanitizer.php +++ b/tests/php/test-amp-img-sanitizer.php @@ -575,6 +575,16 @@ public function get_data() { AMP_Tag_And_Attribute_Sanitizer::WRONG_PARENT_TAG, ], ], + + 'facebook_pixel_img_to_amp_pixel' => [ + 'fbpx', + '', + ], + + 'facebook_pixel_img_to_amp_pixel_with_referrer' => [ + 'fbpx', + '', + ], ]; } @@ -923,4 +933,48 @@ public function test_process_picture_elements( $input, $args, $expected ) { $this->assertEqualMarkup( $expected, $actual, "Actual content:\n$actual" ); } + + /** + * @return array + */ + public function get_data_for_test_is_tracking_pixel_url() { + return [ + 'facebook_pixel_url_no_ssl_no_www' => [ + 'url' => 'http://facebook.com/tr?id=123456789012345', + 'expected' => true, + ], + 'facebook_pixel_url_no_ssl_www' => [ + 'url' => 'http://www.facebook.com/tr?id=123456789012345', + 'expected' => true, + ], + 'facebook_pixel_url_ssl_no_www' => [ + 'url' => 'https://facebook.com/tr?id=123456789012345', + 'expected' => true, + ], + 'facebook_pixel_url_ssl_www' => [ + 'url' => 'https://www.facebook.com/tr?id=123456789012345', + 'expected' => true, + ], + 'facebook_page_url' => [ + 'url' => 'https://www.facebook.com/traffic?id=123456789012345', + 'expected' => false, + ], + 'relative_url' => [ + 'url' => '/tr?id=123456789012345', + 'expected' => false, + ], + ]; + } + + /** + * @dataProvider get_data_for_test_is_tracking_pixel_url() + * + * @covers ::is_tracking_pixel_url() + */ + public function test_is_tracking_pixel_url( $url, $expected ) { + $this->assertEquals( + $expected, + $this->call_private_static_method( AMP_Img_Sanitizer::class, 'is_tracking_pixel_url', [ $url ] ) + ); + } }