WordPress.org

Make WordPress Core

Ticket #34115: 34115.2.diff

File 34115.2.diff, 16.2 KB (added by swissspidy, 3 years ago)
  • src/wp-includes/class-wp-embed.php

    diff --git src/wp-includes/class-wp-embed.php src/wp-includes/class-wp-embed.php
    index 888dcd3..adc375d 100644
    class WP_Embed { 
    186186                }
    187187
    188188                $post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null;
    189                 if ( ! empty( $this->post_ID ) ) // Potentially set by WP_Embed::cache_oembed()
     189
     190                // Potentially set by WP_Embed::cache_oembed()
     191                if ( ! empty( $this->post_ID ) ) {
    190192                        $post_ID = $this->post_ID;
     193                }
     194
     195                // Check for a cached result (stored in the post meta)
     196                $key_suffix = md5( $url . serialize( $attr ) );
     197                $cachekey = '_oembed_' . $key_suffix;
     198                $cachekey_time = '_oembed_time_' . $key_suffix;
     199
     200                /**
     201                 * Filters the oEmbed TTL value (time to live).
     202                 *
     203                 * @since 4.0.0
     204                 *
     205                 * @param int    $time    Time to live (in seconds).
     206                 * @param string $url     The attempted embed URL.
     207                 * @param array  $attr    An array of shortcode attributes.
     208                 * @param int    $post_ID Post ID.
     209                 */
     210                $ttl = apply_filters( 'oembed_ttl', DAY_IN_SECONDS, $url, $attr, $post_ID );
    191211
    192212                // Unknown URL format. Let oEmbed have a go.
    193213                if ( $post_ID ) {
    194 
    195                         // Check for a cached result (stored in the post meta)
    196                         $key_suffix = md5( $url . serialize( $attr ) );
    197                         $cachekey = '_oembed_' . $key_suffix;
    198                         $cachekey_time = '_oembed_time_' . $key_suffix;
    199 
    200                         /**
    201                          * Filters the oEmbed TTL value (time to live).
    202                          *
    203                          * @since 4.0.0
    204                          *
    205                          * @param int    $time    Time to live (in seconds).
    206                          * @param string $url     The attempted embed URL.
    207                          * @param array  $attr    An array of shortcode attributes.
    208                          * @param int    $post_ID Post ID.
    209                          */
    210                         $ttl = apply_filters( 'oembed_ttl', DAY_IN_SECONDS, $url, $attr, $post_ID );
    211 
    212                         $cache = get_post_meta( $post_ID, $cachekey, true );
     214                        $cache      = get_post_meta( $post_ID, $cachekey, true );
    213215                        $cache_time = get_post_meta( $post_ID, $cachekey_time, true );
    214216
    215217                        if ( ! $cache_time ) {
    216218                                $cache_time = 0;
    217219                        }
     220                } else {
     221                        $cache      = get_transient( $cachekey );
     222                        $cache_time = 0;
     223                }
    218224
    219                         $cached_recently = ( time() - $cache_time ) < $ttl;
    220 
    221                         if ( $this->usecache || $cached_recently ) {
    222                                 // Failures are cached. Serve one if we're using the cache.
    223                                 if ( '{{unknown}}' === $cache )
    224                                         return $this->maybe_make_link( $url );
    225 
    226                                 if ( ! empty( $cache ) ) {
    227                                         /**
    228                                          * Filters the cached oEmbed HTML.
    229                                          *
    230                                          * @since 2.9.0
    231                                          *
    232                                          * @see WP_Embed::shortcode()
    233                                          *
    234                                          * @param mixed  $cache   The cached HTML result, stored in post meta.
    235                                          * @param string $url     The attempted embed URL.
    236                                          * @param array  $attr    An array of shortcode attributes.
    237                                          * @param int    $post_ID Post ID.
    238                                          */
    239                                         return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_ID );
    240                                 }
     225                $cached_recently = ( time() - $cache_time ) < $ttl;
     226
     227                if ( $this->usecache || $cached_recently ) {
     228                        // Failures are cached. Serve one if we're using the cache.
     229                        if ( '{{unknown}}' === $cache ) {
     230                                return $this->maybe_make_link( $url );
    241231                        }
    242232
    243                         /**
    244                          * Filters whether to inspect the given URL for discoverable link tags.
    245                          *
    246                          * @since 2.9.0
    247                          * @since 4.4.0 The default value changed to true.
    248                          *
    249                          * @see WP_oEmbed::discover()
    250                          *
    251                          * @param bool $enable Whether to enable `<link>` tag discovery. Default true.
    252                          */
    253                         $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) );
    254 
    255                         // Use oEmbed to get the HTML
    256                         $html = wp_oembed_get( $url, $attr );
     233                        if ( ! empty( $cache ) ) {
     234                                /**
     235                                 * Filters the cached oEmbed HTML.
     236                                 *
     237                                 * @since 2.9.0
     238                                 *
     239                                 * @see WP_Embed::shortcode()
     240                                 *
     241                                 * @param mixed    $cache   The cached HTML result, stored in post meta.
     242                                 * @param string   $url     The attempted embed URL.
     243                                 * @param array    $attr    An array of shortcode attributes.
     244                                 * @param int|null $post_ID Post ID or null if there is no post
     245                                 */
     246                                return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_ID );
     247                        }
     248                }
    257249
     250                /**
     251                 * Filters whether to inspect the given URL for discoverable link tags.
     252                 *
     253                 * @since 2.9.0
     254                 * @since 4.4.0 The default value changed to true.
     255                 *
     256                 * @see WP_oEmbed::discover()
     257                 *
     258                 * @param bool $enable Whether to enable `<link>` tag discovery. Default true.
     259                 */
     260                $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) );
     261
     262                // Use oEmbed to get the HTML
     263                $html = wp_oembed_get( $url, $attr );
     264
     265                if ( $post_ID ) {
    258266                        // Maybe cache the result
    259267                        if ( $html ) {
    260268                                update_post_meta( $post_ID, $cachekey, $html );
    class WP_Embed { 
    262270                        } elseif ( ! $cache ) {
    263271                                update_post_meta( $post_ID, $cachekey, '{{unknown}}' );
    264272                        }
    265 
    266                         // If there was a result, return it
     273                } else {
     274                        // There is no post, maybe cache the result as transient instead.
    267275                        if ( $html ) {
    268                                 /** This filter is documented in wp-includes/class-wp-embed.php */
    269                                 return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_ID );
     276                                set_transient( $cachekey, $html, $ttl );
     277                        } elseif ( ! $cache ) {
     278                                set_transient( $cachekey, '{{unknown}}', $ttl );
    270279                        }
    271280                }
    272281
     282                // If there was a result, return it
     283                if ( $html ) {
     284                        /** This filter is documented in wp-includes/class-wp-embed.php */
     285                        return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_ID );
     286                }
     287
    273288                // Still unknown
    274289                return $this->maybe_make_link( $url );
    275290        }
  • new file tests/phpunit/tests/oembed/WpEmbed.php

    diff --git tests/phpunit/tests/oembed/WpEmbed.php tests/phpunit/tests/oembed/WpEmbed.php
    new file mode 100644
    index 0000000..c2abd0e
    - +  
     1<?php
     2
     3/**
     4 * @group oembed
     5 */
     6class Tests_WP_Embed extends WP_UnitTestCase {
     7        /**
     8         * @var WP_Embed
     9         */
     10        protected $wp_embed;
     11
     12        public function setUp() {
     13                $this->wp_embed = new WP_Embed();
     14        }
     15
     16        public function _embed_handler_callback( $matches, $attr, $url, $rawattr ) {
     17                return sprintf( 'Embedded %s', $url );
     18        }
     19
     20        public function _pre_oembed_result_callback() {
     21                return '<b>Embedded content</b>';
     22        }
     23
     24        public function test_maybe_run_ajax_cache_should_return_nothing_if_there_is_no_post() {
     25                $this->expectOutputString('');
     26                $this->wp_embed->maybe_run_ajax_cache();
     27        }
     28
     29        public function test_maybe_run_ajax_cache_should_return_nothing_if_there_is_no_message() {
     30                $GLOBALS['post'] = $this->factory()->post->create_and_get( array(
     31                        'post_title' => 'Hello World',
     32                ) );
     33
     34                $this->expectOutputString('');
     35
     36                $this->wp_embed->maybe_run_ajax_cache();
     37                unset( $GLOBALS['post'] );
     38        }
     39
     40        public function test_maybe_run_ajax_cache_should_return_javascript() {
     41                $GLOBALS['post'] = $this->factory()->post->create_and_get( array(
     42                        'post_title' => 'Hello World',
     43                ) );
     44                $_GET['message'] = 'foo';
     45
     46                $url    = admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $GLOBALS['post']->ID, 'relative' );
     47                $actual = get_echo( array( $this->wp_embed, 'maybe_run_ajax_cache' ) );
     48
     49                unset( $GLOBALS['post'] );
     50                unset( $GLOBALS['message'] );
     51
     52                $this->assertContains( $url, $actual );
     53        }
     54
     55        public function test_wp_maybe_load_embeds() {
     56                $this->assertEqualSets( array( 10, 9999 ), array_keys( $GLOBALS['wp_embed']->handlers ) );
     57                $this->assertEqualSets( array(
     58                        'youtube_embed_url',
     59                        'googlevideo',
     60                ), array_keys( $GLOBALS['wp_embed']->handlers[10] ) );
     61                $this->assertEqualSets( array(
     62                        'audio',
     63                        'video',
     64                ), array_keys( $GLOBALS['wp_embed']->handlers[9999] ) );
     65        }
     66
     67        public function test_wp_embed_register_handler() {
     68                $handle   = rand_str();
     69                $regex    = '#https?://example\.com/embed/([^/]+)#i';
     70                $callback = array( $this, '_embed_handler_callback' );
     71
     72                wp_embed_register_handler( $handle, $regex, $callback );
     73
     74                $expected = array(
     75                        'regex'    => $regex,
     76                        'callback' => $callback,
     77                );
     78                $actual   = $GLOBALS['wp_embed']->handlers[10];
     79
     80                wp_embed_unregister_handler( $handle );
     81
     82                $this->assertContains( $expected, $actual );
     83        }
     84
     85        public function test_wp_embed_unregister_handler() {
     86                $this->assertArrayHasKey( 'youtube_embed_url', $GLOBALS['wp_embed']->handlers[10] );
     87
     88                wp_embed_unregister_handler( 'youtube_embed_url' );
     89
     90                $handlers = $GLOBALS['wp_embed']->handlers[10];
     91
     92                // Restore.
     93                wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
     94
     95                $this->assertArrayNotHasKey( 'youtube_embed_url', $handlers );
     96        }
     97
     98        public function test_autoembed_should_do_nothing_without_matching_handler() {
     99                $content = "\nhttp://example.com/embed/foo\n";
     100
     101                $actual = $this->wp_embed->autoembed( $content );
     102                $this->assertEquals( $content, $actual );
     103        }
     104
     105        public function test_autoembed_should_return_modified_content() {
     106                $handle   = rand_str();
     107                $regex    = '#https?://example\.com/embed/([^/]+)#i';
     108                $callback = array( $this, '_embed_handler_callback' );
     109
     110                wp_embed_register_handler( $handle, $regex, $callback );
     111
     112                $content = "\nhttp://example.com/embed/foo\n";
     113
     114                $actual = $GLOBALS['wp_embed']->autoembed( $content );
     115                wp_embed_unregister_handler( $handle );
     116
     117                $this->assertEquals( "\nEmbedded http://example.com/embed/foo\n", $actual );
     118        }
     119
     120        public function test_delete_oembed_caches() {
     121                $post_id = $this->factory()->post->create();
     122
     123                add_post_meta( $post_id, '_oembed_foo', 'bar' );
     124                add_post_meta( $post_id, '_oembed_foo', 'baz' );
     125                add_post_meta( $post_id, '_oembed_baz', 'foobar', true );
     126
     127                $this->wp_embed->delete_oembed_caches( $post_id );
     128
     129                $this->assertEquals( array(), get_post_meta( $post_id, '_oembed_foo' ) );
     130                $this->assertEquals( array(), get_post_meta( $post_id, '_oembed_baz' ) );
     131        }
     132
     133        public function test_cache_oembed_invalid_post_type() {
     134                $post_id = $this->factory()->post->create( array( 'post_type' => 'nav_menu_item' ) );
     135
     136                $this->wp_embed->cache_oembed( $post_id );
     137                $this->assertNotSame( $post_id, $this->wp_embed->post_ID );
     138        }
     139
     140        public function test_cache_oembed_empty_content() {
     141                $post_id = $this->factory()->post->create( array( 'post_content' => '' ) );
     142
     143                $this->wp_embed->cache_oembed( $post_id );
     144                $this->assertNotSame( $post_id, $this->wp_embed->post_ID );
     145        }
     146
     147        public function test_cache_oembed_for_post() {
     148                $url           = 'https://example.com/';
     149                $expected      = '<b>Embedded content</b>';
     150                $key_suffix    = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     151                $cachekey      = '_oembed_' . $key_suffix;
     152                $cachekey_time = '_oembed_time_' . $key_suffix;
     153
     154                $post_id = $this->factory()->post->create( array( 'post_content' => 'https://example.com/' ) );
     155
     156                add_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     157                $this->wp_embed->cache_oembed( $post_id );
     158                remove_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     159
     160                $this->assertSame( $post_id, $this->wp_embed->post_ID );
     161                $this->assertEquals( $expected, get_post_meta( $post_id, $cachekey, true ) );
     162                $this->assertNotEmpty( get_post_meta( $post_id, $cachekey_time, true ) );
     163        }
     164
     165        public function test_shortcode_should_cache_data_in_post_meta_for_known_post() {
     166                $GLOBALS['post'] = $this->factory()->post->create_and_get();
     167                $url             = 'https://example.com/';
     168                $expected        = '<b>Embedded content</b>';
     169                $key_suffix      = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     170                $cachekey        = '_oembed_' . $key_suffix;
     171                $cachekey_time   = '_oembed_time_' . $key_suffix;
     172
     173                add_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     174                $actual = $this->wp_embed->shortcode( array(), $url );
     175                remove_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     176
     177                $this->assertEquals( $expected, $actual );
     178
     179                $this->assertEquals( $expected, get_post_meta( $GLOBALS['post']->ID, $cachekey, true ) );
     180                $this->assertNotEmpty( get_post_meta( $GLOBALS['post']->ID, $cachekey_time, true ) );
     181
     182                // Result should be cached.
     183                $actual = $this->wp_embed->shortcode( array(), $url );
     184                $this->assertEquals( $expected, $actual );
     185        }
     186
     187        public function test_shortcode_should_cache_failure_in_post_meta_for_known_post() {
     188                $GLOBALS['post'] = $this->factory()->post->create_and_get();
     189                $url             = 'https://example.com/';
     190                $expected        = '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>';
     191                $key_suffix      = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     192                $cachekey        = '_oembed_' . $key_suffix;
     193                $cachekey_time   = '_oembed_time_' . $key_suffix;
     194
     195                add_filter( 'pre_oembed_result', '__return_empty_string' );
     196                $actual = $this->wp_embed->shortcode( array(), $url );
     197                remove_filter( 'pre_oembed_result', '__return_empty_string' );
     198
     199                $this->assertEquals( $expected, $actual );
     200
     201                $this->assertEquals( '{{unknown}}', get_post_meta( $GLOBALS['post']->ID, $cachekey, true ) );
     202                $this->assertEmpty( get_post_meta( $GLOBALS['post']->ID, $cachekey_time, true ) );
     203
     204                // Result should be cached.
     205                $actual = $this->wp_embed->shortcode( array(), $url );
     206                $this->assertEquals( $expected, $actual );
     207        }
     208
     209        public function test_shortcode_should_cache_data_in_transient_if_there_is_no_post() {
     210                $url           = 'https://example.com/';
     211                $expected      = '<b>Embedded content</b>';
     212                $key_suffix    = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     213                $cachekey      = '_oembed_' . $key_suffix;
     214
     215                add_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     216                $actual = $this->wp_embed->shortcode( array(), $url );
     217                remove_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     218
     219                $this->assertEquals( $expected, $actual );
     220
     221                $this->assertEquals( $expected, get_transient( $cachekey ) );
     222
     223                // Result should be cached.
     224                $actual = $this->wp_embed->shortcode( array(), $url );
     225
     226                // Cleanup.
     227                delete_transient( $cachekey );
     228
     229                $this->assertEquals( $expected, $actual );
     230        }
     231
     232        public function test_shortcode_should_cache_failure_in_transient_if_there_is_no_post() {
     233                $url           = 'https://example.com/';
     234                $expected        = '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>';
     235                $key_suffix    = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     236                $cachekey      = '_oembed_' . $key_suffix;
     237
     238                add_filter( 'pre_oembed_result', '__return_empty_string' );
     239                $actual = $this->wp_embed->shortcode( array(), $url );
     240                remove_filter( 'pre_oembed_result', '__return_empty_string' );
     241
     242                $this->assertEquals( $expected, $actual );
     243
     244                $this->assertEquals( '{{unknown}}', get_transient( $cachekey ) );
     245
     246                // Result should be cached.
     247                $actual = $this->wp_embed->shortcode( array(), $url );
     248
     249                // Cleanup.
     250                delete_transient( $cachekey );
     251
     252                $this->assertEquals( $expected, $actual );
     253        }
     254
     255        public function test_shortcode_should_get_url_from_src_attribute() {
     256                $url    = 'http://example.com/embed/foo';
     257                $actual = $this->wp_embed->shortcode( array( 'src' => $url ) );
     258
     259                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     260        }
     261
     262        public function test_shortcode_should_return_empty_string_for_missing_url() {
     263                $this->assertEmpty( $this->wp_embed->shortcode( array() ) );
     264        }
     265
     266        public function test_shortcode_should_make_link_for_unknown_url() {
     267                $url    = 'http://example.com/embed/foo';
     268                $actual = $this->wp_embed->shortcode( array(), $url );
     269
     270                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     271        }
     272
     273        public function test_run_shortcode_url_only() {
     274                $url    = 'http://example.com/embed/foo';
     275                $actual = $this->wp_embed->run_shortcode( '[embed]' . $url . '[/embed]' );
     276                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     277        }
     278
     279        public function test_maybe_make_link() {
     280                $url    = 'http://example.com/embed/foo';
     281                $actual = $this->wp_embed->maybe_make_link( $url );
     282
     283                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     284        }
     285
     286        public function test_maybe_make_link_return_false_on_fail() {
     287                $this->wp_embed->return_false_on_fail = true;
     288                $this->assertFalse( $this->wp_embed->maybe_make_link( 'http://example.com/' ) );
     289        }
     290
     291        public function test_maybe_make_link_do_not_link_if_unknown() {
     292                $url = 'http://example.com/';
     293
     294                $this->wp_embed->linkifunknown = false;
     295                $this->assertEquals( $url, $this->wp_embed->maybe_make_link( $url ) );
     296        }
     297}