Changeset 56693
- Timestamp:
- 09/26/2023 12:11:06 AM (18 months ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/default-filters.php
r56682 r56693 196 196 add_filter( 'the_content', 'shortcode_unautop' ); 197 197 add_filter( 'the_content', 'prepend_attachment' ); 198 add_filter( 'the_content', 'wp_filter_content_tags' );199 198 add_filter( 'the_content', 'wp_replace_insecure_home_url' ); 199 add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop(). 200 add_filter( 'the_content', 'wp_filter_content_tags', 12 ); // Runs after do_shortcode(). 200 201 201 202 add_filter( 'the_excerpt', 'wptexturize' ); … … 204 205 add_filter( 'the_excerpt', 'wpautop' ); 205 206 add_filter( 'the_excerpt', 'shortcode_unautop' ); 206 add_filter( 'the_excerpt', 'wp_filter_content_tags' );207 207 add_filter( 'the_excerpt', 'wp_replace_insecure_home_url' ); 208 add_filter( 'the_excerpt', 'wp_filter_content_tags', 12 ); 208 209 add_filter( 'get_the_excerpt', 'wp_trim_excerpt', 10, 2 ); 209 210 … … 231 232 add_filter( 'widget_text_content', 'wpautop' ); 232 233 add_filter( 'widget_text_content', 'shortcode_unautop' ); 233 add_filter( 'widget_text_content', 'wp_filter_content_tags' );234 234 add_filter( 'widget_text_content', 'wp_replace_insecure_home_url' ); 235 235 add_filter( 'widget_text_content', 'do_shortcode', 11 ); // Runs after wpautop(); note that $post global will be null when shortcodes run. 236 add_filter( 'widget_text_content', 'wp_filter_content_tags', 12 ); // Runs after do_shortcode(). 236 237 237 238 add_filter( 'widget_block_content', 'do_blocks', 9 ); 238 add_filter( 'widget_block_content', 'wp_filter_content_tags' );239 239 add_filter( 'widget_block_content', 'do_shortcode', 11 ); 240 add_filter( 'widget_block_content', 'wp_filter_content_tags', 12 ); // Runs after do_shortcode(). 240 241 241 242 add_filter( 'block_type_metadata', 'wp_migrate_old_typography_shape' ); … … 626 627 add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 ); 627 628 628 // Shortcodes.629 add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop().630 631 629 // Media. 632 630 add_action( 'wp_playlist_scripts', 'wp_playlist_scripts' ); -
trunk/src/wp-includes/formatting.php
r56682 r56693 3981 3981 * is wasteful and can lead to bugs in the image counting logic. 3982 3982 */ 3983 $filter_image_removed = remove_filter( 'the_content', 'wp_filter_content_tags' );3983 $filter_image_removed = remove_filter( 'the_content', 'wp_filter_content_tags', 12 ); 3984 3984 3985 3985 /* … … 4004 4004 */ 4005 4005 if ( $filter_image_removed ) { 4006 add_filter( 'the_content', 'wp_filter_content_tags' );4006 add_filter( 'the_content', 'wp_filter_content_tags', 12 ); 4007 4007 } 4008 4008 -
trunk/src/wp-includes/media.php
r56690 r56693 5650 5650 5651 5651 /* 5652 * Skip programmatically created images within post contentas they need to be handled together with the other5653 * images within the post content .5652 * Skip programmatically created images within content blobs as they need to be handled together with the other 5653 * images within the post content or widget content. 5654 5654 * Without this clause, they would already be considered within their own context which skews the image count and 5655 5655 * can result in the first post content image being lazy-loaded or an image further down the page being marked as a 5656 5656 * high priority. 5657 5657 */ 5658 // TODO: Handle shortcode images together with the content (see https://core.trac.wordpress.org/ticket/58853). 5659 if ( 'the_content' !== $context && 'do_shortcode' !== $context && doing_filter( 'the_content' ) ) { 5658 if ( 5659 'the_content' !== $context && doing_filter( 'the_content' ) || 5660 'widget_text_content' !== $context && doing_filter( 'widget_text_content' ) || 5661 'widget_block_content' !== $context && doing_filter( 'widget_block_content' ) 5662 ) { 5660 5663 /** This filter is documented in wp-includes/media.php */ 5661 5664 return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context ); 5665 5662 5666 } 5663 5667 -
trunk/tests/phpunit/tests/formatting/wpTrimExcerpt.php
r56598 r56693 130 130 wp_trim_excerpt( '', $post ); 131 131 132 $this->assertSame( 1 0, has_filter( 'the_content', 'wp_filter_content_tags' ), 'wp_filter_content_tags() was not restored in wp_trim_excerpt()' );132 $this->assertSame( 12, has_filter( 'the_content', 'wp_filter_content_tags' ), 'wp_filter_content_tags() was not restored in wp_trim_excerpt()' ); 133 133 } 134 134 … … 142 142 143 143 // Remove wp_filter_content_tags() from 'the_content' filter generally. 144 remove_filter( 'the_content', 'wp_filter_content_tags' );144 remove_filter( 'the_content', 'wp_filter_content_tags', 12 ); 145 145 146 146 wp_trim_excerpt( '', $post ); -
trunk/tests/phpunit/tests/media.php
r56690 r56693 4959 4959 } 4960 4960 4961 /** 4962 * Tests that wp_filter_content_tags() and more specifically wp_get_loading_optimization_attributes() correctly 4963 * handle shortcodes images together with the content that it is part of. 4964 * 4965 * Images within shortcodes as part of the content should be ignored by wp_get_loading_optimization_attributes() to 4966 * avoid double processing. They should instead only be processed together with any other images as part of the 4967 * content, to correctly count the original sequencing of those images. 4968 * 4969 * @ticket 58853 4970 * 4971 * @covers ::wp_filter_content_tags 4972 * @covers ::wp_get_loading_optimization_attributes 4973 */ 4974 public function test_wp_filter_content_tags_handles_shortcode_image_together_with_the_content() { 4975 global $wp_query, $wp_the_query; 4976 4977 // Add shortcode that prints a large image, and a block type that wraps it. 4978 add_shortcode( 4979 'full_image', 4980 static function ( $atts ) { 4981 $atts = shortcode_atts( 4982 array( 4983 'id' => 0, 4984 ), 4985 $atts, 4986 'full_image' 4987 ); 4988 return wp_get_attachment_image( (int) $atts['id'], 'full' ); 4989 } 4990 ); 4991 4992 /* 4993 * Even though `do_shortcode()` runs before `wp_filter_content_tags()`, the image from the shortcode should not 4994 * receive any loading optimization attributes because it needs to be considered together with the rest of the 4995 * post content, within `wp_filter_content_tags()`. 4996 * Since the hard-coded image appears before the shortcode image, it should receive `fetchpriority="high"`, 4997 * despite the shortcode image being parsed before it. 4998 */ 4999 $post_content = '<img src="example.jpg" width="800" height="600">' . "\n"; 5000 $post_content .= '[full_image id="' . self::$large_id . '"]'; 5001 $post_content = wpautop( $post_content ); 5002 5003 /* 5004 * Prepare the expected output: 5005 * 1. On the first image (hard-coded in the content), expect `fetchpriority="high"`. 5006 * 2. Replace the shortcode with its expected output, i.e. the full image. Expect neither 5007 * `fetchpriority="high"` nor `loading="lazy"`. 5008 */ 5009 $expected_content = $post_content; 5010 $expected_content = str_replace( 5011 '<img src="example.jpg"', 5012 '<img fetchpriority="high" decoding="async" src="example.jpg"', 5013 $expected_content 5014 ); 5015 $expected_content = str_replace( 5016 '[full_image id="' . self::$large_id . '"]', 5017 str_replace( 5018 '<img ', 5019 '<img decoding="async" ', 5020 wp_get_attachment_image( 5021 self::$large_id, 5022 'full', 5023 false, 5024 array( 5025 'decoding' => false, 5026 'fetchpriority' => false, 5027 'loading' => false, 5028 ) 5029 ) 5030 ), 5031 $expected_content 5032 ); 5033 5034 // Create post with the content. 5035 $post_id = self::factory()->post->create( 5036 array( 5037 'post_content' => $post_content, 5038 'post_excerpt' => '', 5039 ) 5040 ); 5041 5042 // We have to run a main query loop so that the first 'the_content' context images are not lazy-loaded. 5043 $wp_query = new WP_Query( array( 'post__in' => array( $post_id ) ) ); 5044 $wp_the_query = $wp_query; 5045 5046 $content = ''; 5047 while ( have_posts() ) { 5048 the_post(); 5049 $content = get_echo( 'the_content' ); 5050 } 5051 5052 // Cleanup. 5053 remove_shortcode( 'full_image' ); 5054 5055 $this->assertSame( $expected_content, $content ); 5056 } 5057 5058 /** 5059 * Tests that wp_filter_content_tags() and more specifically wp_get_loading_optimization_attributes() correctly 5060 * handle shortcodes images within the content, including within a block. 5061 * 5062 * Images within shortcodes as part of the content should be ignored by wp_get_loading_optimization_attributes() to 5063 * avoid double processing. They should instead only be processed together with any other images as part of the 5064 * content, to correctly count the original sequencing of those images. 5065 * 5066 * @ticket 58853 5067 * 5068 * @covers ::wp_filter_content_tags 5069 * @covers ::wp_get_loading_optimization_attributes 5070 */ 5071 public function test_wp_filter_content_tags_handles_shortcode_images_also_in_blocks_within_the_content() { 5072 global $wp_query, $wp_the_query; 5073 5074 // Disable addition of `decoding="async"` as it is irrelevant for this test. 5075 add_filter( 5076 'wp_get_loading_optimization_attributes', 5077 static function ( $loading_attrs ) { 5078 if ( isset( $loading_attrs['decoding'] ) ) { 5079 unset( $loading_attrs['decoding'] ); 5080 } 5081 return $loading_attrs; 5082 } 5083 ); 5084 5085 // Add shortcode that prints a large image, and a block type that wraps it. 5086 add_shortcode( 5087 'full_image', 5088 static function ( $atts ) { 5089 $atts = shortcode_atts( 5090 array( 5091 'id' => 0, 5092 ), 5093 $atts, 5094 'full_image' 5095 ); 5096 return wp_get_attachment_image( (int) $atts['id'], 'full' ); 5097 } 5098 ); 5099 register_block_type( 5100 'core/full-image-shortcode', 5101 array( 5102 'render_callback' => static function ( $atts ) { 5103 if ( empty( $atts['id'] ) ) { 5104 return ''; 5105 } 5106 return do_shortcode( '[full_image id="' . $atts['id'] . '"]' ); 5107 }, 5108 ) 5109 ); 5110 5111 /* 5112 * Include the following images: 5113 * 1. Using gallery shortcode. Expected `fetchpriority="high"`. 5114 * 2. Regular hard-coded image. 5115 * 3. Using custom shortcode within block. 5116 * 4. Regular hard-coded image. Expected `loading="lazy"`. 5117 * 5118 * The first image is expected to be prioritized because it is the first (large enough) content image. 5119 * The first three images are expected to not have lazy-loading because that is the default threshold for 5120 * omitting the attribute. 5121 * The fourth image is expected to be lazy-loaded as it is past the default threshold. 5122 * 5123 * The results will only be correct if all images are considered together. For example: 5124 * * If the image within the shortcode would only be parsed after the rest of the content, it would miss the 5125 * `fetchpriority="high"` attribute and instead incorrectly receive `loading="lazy"`. The second image would as 5126 * a result incorrectly receive `fetchpriority="high"`. 5127 * * If the image within the block would be parsed before the rest of the content, it would incorrectly receive 5128 * the `fetchpriority="high"` attribute. Then the first image would no longer receive the attribute. 5129 * 5130 * To ensure that this works: 5131 * * `wp_filter_content_tags()` must run after `do_blocks()` and `do_shortcode()`. 5132 * * `wp_get_loading_optimization_attributes()` must bail early if any images from the content blob are being 5133 * considered under a different context name than 'the_content'. 5134 */ 5135 $post_content = '[gallery ids="' . self::$large_id . '" size="large"]' . "\n"; 5136 $post_content .= '<img src="example.jpg" width="800" height="600">' . "\n"; 5137 $post_content .= '<p>Some text.</p>' . "\n"; 5138 $post_content .= '<!-- wp:core/full-image-shortcode {"id":' . self::$large_id . '} --><!-- /wp:core/full-image-shortcode -->' . "\n"; 5139 $post_content .= '<img src="example2.jpg" width="800" height="600">'; 5140 5141 $post_id = self::factory()->post->create( 5142 array( 5143 'post_content' => $post_content, 5144 'post_excerpt' => '', 5145 ) 5146 ); 5147 5148 /* 5149 * Prepare the expected output: 5150 * 1. Replace the shortcode with its expected output (ID increased by 1 because of static variable within 5151 * the gallery_shortcode() function). Expect `fetchpriority="high"`, but not `loading="lazy"`. 5152 * 2. Do not modify the second image as it is hard-coded in the content and expected to be unchanged. 5153 * 3. Replace the block with its expected output, i.e. the full image from the shortcode within. Expect neither 5154 * `fetchpriority="high"` nor `loading="lazy"`. 5155 * 4. On the fourth image (hard-coded in the content), expect `loading="lazy"`. 5156 */ 5157 $expected_content = $post_content; 5158 $expected_content = str_replace( 5159 '[gallery ids="' . self::$large_id . '" size="large"]', 5160 str_replace( 5161 array( ' loading="lazy"', '<img ' ), 5162 array( '', '<img fetchpriority="high" ' ), 5163 preg_replace_callback( 5164 '/gallery-(\d+)/', 5165 static function ( $match ) { 5166 return 'gallery-' . ( (int) $match[1] + 1 ); 5167 }, 5168 do_shortcode( '[gallery ids="' . self::$large_id . '" size="large" id="' . $post_id . '"]' ) 5169 ) 5170 ), 5171 $expected_content 5172 ); 5173 $expected_content = str_replace( 5174 '<!-- wp:core/full-image-shortcode {"id":' . self::$large_id . '} --><!-- /wp:core/full-image-shortcode -->', 5175 wp_get_attachment_image( 5176 self::$large_id, 5177 'full', 5178 false, 5179 array( 5180 'fetchpriority' => false, 5181 'loading' => false, 5182 ) 5183 ), 5184 $expected_content 5185 ); 5186 $expected_content = str_replace( 5187 '<img src="example2.jpg"', 5188 '<img loading="lazy" src="example2.jpg"', 5189 $expected_content 5190 ); 5191 5192 // We have to run a main query loop so that the first 'the_content' context images are not lazy-loaded. 5193 $wp_query = new WP_Query( array( 'post__in' => array( $post_id ) ) ); 5194 $wp_the_query = $wp_query; 5195 5196 $content = ''; 5197 while ( have_posts() ) { 5198 the_post(); 5199 $content = get_echo( 'the_content' ); 5200 } 5201 5202 // Cleanup. 5203 remove_shortcode( 'full_image' ); 5204 unregister_block_type( 'core/full-image-shortcode' ); 5205 5206 $this->assertSame( $expected_content, $content ); 5207 } 5208 4961 5209 private function reset_content_media_count() { 4962 5210 // Get current value without increasing. … … 5319 5567 5320 5568 /** 5569 * Tests that the `do_shortcode` context results in a lazy-loaded image by default. 5570 * 5321 5571 * @ticket 58681 5322 * 5323 * @dataProvider data_wp_get_loading_optimization_attributes_in_shortcodes 5324 */ 5325 public function test_wp_get_loading_optimization_attributes_in_shortcodes( $setup, $expected, $message ) { 5572 * @ticket 58853 5573 * 5574 * @covers ::wp_get_loading_optimization_attributes 5575 */ 5576 public function test_wp_get_loading_optimization_attributes_in_shortcodes() { 5326 5577 $attr = $this->get_width_height_for_high_priority(); 5327 $setup(); 5328 5329 // The first image processed in a shortcode should have fetchpriority set to high. 5578 5579 // Shortcodes processed outside of content blobs like 'the_content' always get `loading="lazy"`. 5330 5580 $this->assertSameSetsWithIndex( 5331 $expected, 5581 array( 5582 'decoding' => 'async', 5583 'loading' => 'lazy', 5584 ), 5332 5585 wp_get_loading_optimization_attributes( 'img', $attr, 'do_shortcode' ), 5333 $message 5334 ); 5335 } 5336 5337 public function data_wp_get_loading_optimization_attributes_in_shortcodes() { 5338 return array( 5339 'main_shortcode_image_should_have_fetchpriority_high' => array( 5340 'setup' => function () { 5341 global $wp_query; 5342 5343 // Set WP_Query to be in the loop and the main query. 5344 $wp_query->in_the_loop = true; 5345 $this->set_main_query( $wp_query ); 5346 }, 5347 'expected' => array( 5348 'decoding' => 'async', 5349 'fetchpriority' => 'high', 5350 ), 5351 'message' => 'Fetch priority not applied to during shortcode rendering.', 5352 ), 5353 'main_shortcode_image_after_threshold_is_loading_lazy' => array( 5354 'setup' => function () { 5355 global $wp_query; 5356 5357 // Set WP_Query to be in the loop and the main query. 5358 $wp_query->in_the_loop = true; 5359 $this->set_main_query( $wp_query ); 5360 5361 // Set internal flags so lazy should be applied. 5362 wp_high_priority_element_flag( false ); 5363 wp_increase_content_media_count( 3 ); 5364 }, 5365 'expected' => array( 5366 'decoding' => 'async', 5367 'loading' => 'lazy', 5368 ), 5369 'message' => 'Lazy-loading or decoding not applied to during shortcode rendering.', 5370 ), 5371 'shortcode_image_outside_of_the_loop_are_loaded_lazy' => array( 5372 'setup' => function () { 5373 // Avoid setting up the WP_Query object for the loop. 5374 return; 5375 }, 5376 'expected' => array( 5377 'decoding' => 'async', 5378 'loading' => 'lazy', 5379 ), 5380 'message' => 'Lazy-loading or decoding not applied to shortcodes outside the loop.', 5381 ), 5586 'Lazy-loading not applied to shortcodes outside the loop.' 5587 ); 5588 } 5589 5590 /** 5591 * Tests that the `do_shortcode` context does not result in loading optimization changes when used within a content 5592 * blob. 5593 * 5594 * @ticket 58853 5595 * 5596 * @covers ::wp_get_loading_optimization_attributes 5597 * 5598 * @dataProvider data_get_filters_with_do_shortcode_callback 5599 * 5600 * @param string $filter_name The name of the filter to hook. 5601 */ 5602 public function test_wp_get_loading_optimization_attributes_in_shortcodes_within_content_blob( $filter_name ) { 5603 $result = null; 5604 5605 remove_all_filters( $filter_name ); 5606 add_filter( 5607 $filter_name, 5608 function ( $content ) use ( &$result ) { 5609 $attr = $this->get_width_height_for_high_priority(); 5610 $result = wp_get_loading_optimization_attributes( 'img', $attr, 'do_shortcode' ); 5611 return $content; 5612 } 5613 ); 5614 apply_filters( $filter_name, '' ); 5615 5616 // Shortcodes processed within content blobs like 'the_content' should never get any loading optimization attributes. 5617 $this->assertSame( 5618 array(), 5619 $result, 5620 'Loading optimization unexpectedly applied to shortcodes within content blob.' 5621 ); 5622 } 5623 5624 /** 5625 * Gets filters for content blobs that by default have a `do_shortcode()` callback. 5626 * 5627 * @return array[] 5628 */ 5629 public function data_get_filters_with_do_shortcode_callback() { 5630 return self::text_array_to_dataprovider( 5631 array( 5632 'the_content', 5633 'widget_text_content', 5634 'widget_block_content', 5635 ) 5382 5636 ); 5383 5637 }
Note: See TracChangeset
for help on using the changeset viewer.