WordPress.org

Make WordPress Core

Ticket #34115: 34115.diff

File 34115.diff, 17.2 KB (added by swissspidy, 4 years ago)
  • src/wp-includes/class-oembed.php

    diff --git src/wp-includes/class-oembed.php src/wp-includes/class-oembed.php
    index b60a4f4..2b7ca43 100644
    class WP_oEmbed { 
    286286        public function get_html( $url, $args = '' ) {
    287287                $provider = $this->get_provider( $url, $args );
    288288
    289                 if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) )
     289                /**
     290                 * Filters whether to return the HTML early.
     291                 *
     292                 * @since 4.6.0
     293                 *
     294                 * @param string $data The oEmbed HTML. Default null.
     295                 * @param string $url  URL of the content to be embedded.
     296                 * @param array  $args Optional arguments, usually passed from a shortcode.
     297                 */
     298                $pre_result = apply_filters( 'pre_oembed_result', null, $url, $args );
     299
     300                if ( null !== $pre_result ) {
     301                        return $pre_result;
     302                }
     303
     304                if ( ! $provider || false === $data = $this->fetch( $provider, $url, $args ) ) {
    290305                        return false;
     306                }
    291307
    292308                /**
    293309                 * Filter the HTML returned by the oEmbed provider.
  • src/wp-includes/class-wp-embed.php

    diff --git src/wp-includes/class-wp-embed.php src/wp-includes/class-wp-embed.php
    index 730fc4f..b1655ae 100644
    class WP_Embed { 
    175175                }
    176176
    177177                $post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null;
    178                 if ( ! empty( $this->post_ID ) ) // Potentially set by WP_Embed::cache_oembed()
     178
     179                // Potentially set by WP_Embed::cache_oembed()
     180                if ( ! empty( $this->post_ID ) ) {
    179181                        $post_ID = $this->post_ID;
     182                }
    180183
    181                 // Unknown URL format. Let oEmbed have a go.
    182                 if ( $post_ID ) {
     184                // Check for a cached result (stored in the post meta)
     185                $key_suffix = md5( $url . serialize( $attr ) );
     186                $cachekey = '_oembed_' . $key_suffix;
     187                $cachekey_time = '_oembed_time_' . $key_suffix;
    183188
    184                         // Check for a cached result (stored in the post meta)
    185                         $key_suffix = md5( $url . serialize( $attr ) );
    186                         $cachekey = '_oembed_' . $key_suffix;
    187                         $cachekey_time = '_oembed_time_' . $key_suffix;
    188 
    189                         /**
    190                          * Filter the oEmbed TTL value (time to live).
    191                          *
    192                          * @since 4.0.0
    193                          *
    194                          * @param int    $time    Time to live (in seconds).
    195                          * @param string $url     The attempted embed URL.
    196                          * @param array  $attr    An array of shortcode attributes.
    197                          * @param int    $post_ID Post ID.
    198                          */
    199                         $ttl = apply_filters( 'oembed_ttl', DAY_IN_SECONDS, $url, $attr, $post_ID );
     189                /**
     190                 * Filter the oEmbed TTL value (time to live).
     191                 *
     192                 * @since 4.0.0
     193                 *
     194                 * @param int    $time    Time to live (in seconds).
     195                 * @param string $url     The attempted embed URL.
     196                 * @param array  $attr    An array of shortcode attributes.
     197                 * @param int    $post_ID Post ID.
     198                 */
     199                $ttl = apply_filters( 'oembed_ttl', DAY_IN_SECONDS, $url, $attr, $post_ID );
    200200
     201                // Unknown URL format. Let oEmbed have a go.
     202
     203                if ( $post_ID ) {
    201204                        $cache = get_post_meta( $post_ID, $cachekey, true );
    202205                        $cache_time = get_post_meta( $post_ID, $cachekey_time, true );
    203206
    204207                        if ( ! $cache_time ) {
    205208                                $cache_time = 0;
    206209                        }
     210                } else {
     211                        $cache = get_transient( $cachekey );
     212                        $cache_time = 0;
     213                }
    207214
    208                         $cached_recently = ( time() - $cache_time ) < $ttl;
    209 
    210                         if ( $this->usecache || $cached_recently ) {
    211                                 // Failures are cached. Serve one if we're using the cache.
    212                                 if ( '{{unknown}}' === $cache )
    213                                         return $this->maybe_make_link( $url );
    214 
    215                                 if ( ! empty( $cache ) ) {
    216                                         /**
    217                                          * Filter the cached oEmbed HTML.
    218                                          *
    219                                          * @since 2.9.0
    220                                          *
    221                                          * @see WP_Embed::shortcode()
    222                                          *
    223                                          * @param mixed  $cache   The cached HTML result, stored in post meta.
    224                                          * @param string $url     The attempted embed URL.
    225                                          * @param array  $attr    An array of shortcode attributes.
    226                                          * @param int    $post_ID Post ID.
    227                                          */
    228                                         return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_ID );
    229                                 }
     215                $cached_recently = ( time() - $cache_time ) < $ttl;
     216
     217                if ( $this->usecache || $cached_recently ) {
     218                        // Failures are cached. Serve one if we're using the cache.
     219                        if ( '{{unknown}}' === $cache ) {
     220                                return $this->maybe_make_link( $url );
    230221                        }
    231222
    232                         /**
    233                          * Filter whether to inspect the given URL for discoverable link tags.
    234                          *
    235                          * @since 2.9.0
    236                          * @since 4.4.0 The default value changed to true.
    237                          *
    238                          * @see WP_oEmbed::discover()
    239                          *
    240                          * @param bool $enable Whether to enable `<link>` tag discovery. Default true.
    241                          */
    242                         $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) );
    243 
    244                         // Use oEmbed to get the HTML
    245                         $html = wp_oembed_get( $url, $attr );
     223                        if ( ! empty( $cache ) ) {
     224                                /**
     225                                 * Filter the cached oEmbed HTML.
     226                                 *
     227                                 * @since 2.9.0
     228                                 *
     229                                 * @see   WP_Embed::shortcode()
     230                                 *
     231                                 * @param mixed    $cache   The cached HTML result, stored in post meta.
     232                                 * @param string   $url     The attempted embed URL.
     233                                 * @param array    $attr    An array of shortcode attributes.
     234                                 * @param int|null $post_ID Post ID or null if there is no post.
     235                                 */
     236                                return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_ID );
     237                        }
     238                }
     239
     240                /**
     241                 * Filter whether to inspect the given URL for discoverable link tags.
     242                 *
     243                 * @since 2.9.0
     244                 * @since 4.4.0 The default value changed to true.
     245                 *
     246                 * @see WP_oEmbed::discover()
     247                 *
     248                 * @param bool $enable Whether to enable `<link>` tag discovery. Default true.
     249                 */
     250                $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) );
     251
     252                // Use oEmbed to get the HTML
     253                $html = wp_oembed_get( $url, $attr );
    246254
     255                if ( $post_ID ) {
    247256                        // Maybe cache the result
    248257                        if ( $html ) {
    249258                                update_post_meta( $post_ID, $cachekey, $html );
    class WP_Embed { 
    251260                        } elseif ( ! $cache ) {
    252261                                update_post_meta( $post_ID, $cachekey, '{{unknown}}' );
    253262                        }
    254 
    255                         // If there was a result, return it
     263                } else {
     264                        // There is no post, maybe cache the result as transient instead.
    256265                        if ( $html ) {
    257                                 /** This filter is documented in wp-includes/class-wp-embed.php */
    258                                 return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_ID );
     266                                set_transient( $cachekey, $html, $ttl );
     267                        } elseif ( ! $cache ) {
     268                                set_transient( $cachekey, '{{unknown}}', $ttl );
    259269                        }
    260270                }
    261271
     272                // If there was a result, return it
     273                if ( $html ) {
     274                        /** This filter is documented in wp-includes/class-wp-embed.php */
     275                        return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_ID );
     276                }
     277
    262278                // Still unknown
    263279                return $this->maybe_make_link( $url );
    264280        }
  • 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..6d60ebc
    - +  
     1<?php
     2
     3/**
     4 * @group oembed
     5 */
     6class Tests_WP_Embed_Cache 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->assertNull( $this->wp_embed->maybe_run_ajax_cache() );
     26        }
     27
     28        public function test_maybe_run_ajax_cache_should_return_nothing_if_there_is_no_message() {
     29                $GLOBALS['post'] = $this->factory()->post->create_and_get( array(
     30                        'post_title' => 'Hello World',
     31                ) );
     32
     33                $actual = $this->wp_embed->maybe_run_ajax_cache();
     34                unset( $GLOBALS['post'] );
     35
     36                $this->assertNull( $actual );
     37        }
     38
     39        public function test_maybe_run_ajax_cache_should_return_javascript() {
     40                $GLOBALS['post'] = $this->factory()->post->create_and_get( array(
     41                        'post_title' => 'Hello World',
     42                ) );
     43                $_GET['message'] = 'foo';
     44
     45                $url    = admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $GLOBALS['post']->ID, 'relative' );
     46                $actual = get_echo( array( $this->wp_embed, 'maybe_run_ajax_cache' ) );
     47
     48                unset( $GLOBALS['post'] );
     49                unset( $GLOBALS['message'] );
     50
     51                $this->assertContains( $url, $actual );
     52        }
     53
     54        public function test_wp_maybe_load_embeds() {
     55                $this->assertEqualSets( array( 10, 9999 ), array_keys( $GLOBALS['wp_embed']->handlers ) );
     56                $this->assertEqualSets( array(
     57                        'youtube_embed_url',
     58                        'googlevideo',
     59                ), array_keys( $GLOBALS['wp_embed']->handlers[10] ) );
     60                $this->assertEqualSets( array(
     61                        'audio',
     62                        'video',
     63                ), array_keys( $GLOBALS['wp_embed']->handlers[9999] ) );
     64        }
     65
     66        public function test_wp_embed_register_handler() {
     67                $handle   = rand_str();
     68                $regex    = '#https?://example\.com/embed/([^/]+)#i';
     69                $callback = array( $this, '_embed_handler_callback' );
     70
     71                wp_embed_register_handler( $handle, $regex, $callback );
     72
     73                $expected = array(
     74                        'regex'    => $regex,
     75                        'callback' => $callback,
     76                );
     77                $actual   = $GLOBALS['wp_embed']->handlers[10];
     78
     79                wp_embed_unregister_handler( $handle );
     80
     81                $this->assertContains( $expected, $actual );
     82        }
     83
     84        public function test_wp_embed_unregister_handler() {
     85                $this->assertArrayHasKey( 'youtube_embed_url', $GLOBALS['wp_embed']->handlers[10] );
     86
     87                wp_embed_unregister_handler( 'youtube_embed_url' );
     88
     89                $handlers = $GLOBALS['wp_embed']->handlers[10];
     90
     91                // Restore.
     92                wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
     93
     94                $this->assertArrayNotHasKey( 'youtube_embed_url', $handlers );
     95        }
     96
     97        public function test_autoembed_should_do_nothing_without_matching_handler() {
     98                $content = "\nhttp://example.com/embed/foo\n";
     99
     100                $actual = $this->wp_embed->autoembed( $content );
     101                $this->assertEquals( $content, $actual );
     102        }
     103
     104        public function test_autoembed_should_return_modified_content() {
     105                $handle   = rand_str();
     106                $regex    = '#https?://example\.com/embed/([^/]+)#i';
     107                $callback = array( $this, '_embed_handler_callback' );
     108
     109                wp_embed_register_handler( $handle, $regex, $callback );
     110
     111                $content = "\nhttp://example.com/embed/foo\n";
     112
     113                $actual = $GLOBALS['wp_embed']->autoembed( $content );
     114                wp_embed_unregister_handler( $handle );
     115
     116                $this->assertEquals( "\nEmbedded http://example.com/embed/foo\n", $actual );
     117        }
     118
     119        public function test_delete_oembed_caches() {
     120                $post_id = $this->factory()->post->create();
     121
     122                add_post_meta( $post_id, '_oembed_foo', 'bar' );
     123                add_post_meta( $post_id, '_oembed_foo', 'baz' );
     124                add_post_meta( $post_id, '_oembed_baz', 'foobar', true );
     125
     126                $this->wp_embed->delete_oembed_caches( $post_id );
     127
     128                $this->assertEquals( array(), get_post_meta( $post_id, '_oembed_foo' ) );
     129                $this->assertEquals( array(), get_post_meta( $post_id, '_oembed_baz' ) );
     130        }
     131
     132        public function test_cache_oembed_invalid_post_type() {
     133                $post_id = $this->factory()->post->create( array( 'post_type' => 'nav_menu_item' ) );
     134
     135                $this->wp_embed->cache_oembed( $post_id );
     136                $this->assertNotSame( $post_id, $this->wp_embed->post_ID );
     137        }
     138
     139        public function test_cache_oembed_empty_content() {
     140                $post_id = $this->factory()->post->create( array( 'post_content' => '' ) );
     141
     142                $this->wp_embed->cache_oembed( $post_id );
     143                $this->assertNotSame( $post_id, $this->wp_embed->post_ID );
     144        }
     145
     146        public function test_cache_oembed_for_post() {
     147                $url           = 'https://example.com/';
     148                $expected      = '<b>Embedded content</b>';
     149                $key_suffix    = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     150                $cachekey      = '_oembed_' . $key_suffix;
     151                $cachekey_time = '_oembed_time_' . $key_suffix;
     152
     153                $post_id = $this->factory()->post->create( array( 'post_content' => 'https://example.com/' ) );
     154
     155                add_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     156                $this->wp_embed->cache_oembed( $post_id );
     157                remove_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     158
     159                $this->assertSame( $post_id, $this->wp_embed->post_ID );
     160                $this->assertEquals( $expected, get_post_meta( $post_id, $cachekey, true ) );
     161                $this->assertNotEmpty( get_post_meta( $post_id, $cachekey_time, true ) );
     162        }
     163
     164        public function test_shortcode_should_cache_data_in_post_meta_for_known_post() {
     165                $GLOBALS['post'] = $this->factory()->post->create_and_get();
     166                $url             = 'https://example.com/';
     167                $expected        = '<b>Embedded content</b>';
     168                $key_suffix      = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     169                $cachekey        = '_oembed_' . $key_suffix;
     170                $cachekey_time   = '_oembed_time_' . $key_suffix;
     171
     172                add_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     173                $actual = $this->wp_embed->shortcode( array(), $url );
     174                remove_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     175
     176                $this->assertEquals( $expected, $actual );
     177
     178                $this->assertEquals( $expected, get_post_meta( $GLOBALS['post']->ID, $cachekey, true ) );
     179                $this->assertNotEmpty( get_post_meta( $GLOBALS['post']->ID, $cachekey_time, true ) );
     180
     181                // Result should be cached.
     182                $actual = $this->wp_embed->shortcode( array(), $url );
     183                $this->assertEquals( $expected, $actual );
     184        }
     185
     186        public function test_shortcode_should_cache_failure_in_post_meta_for_known_post() {
     187                $GLOBALS['post'] = $this->factory()->post->create_and_get();
     188                $url             = 'https://example.com/';
     189                $expected        = '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>';
     190                $key_suffix      = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     191                $cachekey        = '_oembed_' . $key_suffix;
     192                $cachekey_time   = '_oembed_time_' . $key_suffix;
     193
     194                add_filter( 'pre_oembed_result', '__return_empty_string' );
     195                $actual = $this->wp_embed->shortcode( array(), $url );
     196                remove_filter( 'pre_oembed_result', '__return_empty_string' );
     197
     198                $this->assertEquals( $expected, $actual );
     199
     200                $this->assertEquals( '{{unknown}}', get_post_meta( $GLOBALS['post']->ID, $cachekey, true ) );
     201                $this->assertEmpty( get_post_meta( $GLOBALS['post']->ID, $cachekey_time, true ) );
     202
     203                // Result should be cached.
     204                $actual = $this->wp_embed->shortcode( array(), $url );
     205                $this->assertEquals( $expected, $actual );
     206        }
     207
     208        public function test_shortcode_should_cache_data_in_transient_if_there_is_no_post() {
     209                $url           = 'https://example.com/';
     210                $expected      = '<b>Embedded content</b>';
     211                $key_suffix    = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     212                $cachekey      = '_oembed_' . $key_suffix;
     213
     214                add_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     215                $actual = $this->wp_embed->shortcode( array(), $url );
     216                remove_filter( 'pre_oembed_result', array( $this, '_pre_oembed_result_callback' ) );
     217
     218                $this->assertEquals( $expected, $actual );
     219
     220                $this->assertEquals( $expected, get_transient( $cachekey ) );
     221
     222                // Result should be cached.
     223                $actual = $this->wp_embed->shortcode( array(), $url );
     224
     225                // Cleanup.
     226                delete_transient( $cachekey );
     227
     228                $this->assertEquals( $expected, $actual );
     229        }
     230
     231        public function test_shortcode_should_cache_failure_in_transient_if_there_is_no_post() {
     232                $url           = 'https://example.com/';
     233                $expected        = '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>';
     234                $key_suffix    = md5( $url . serialize( wp_embed_defaults( $url ) ) );
     235                $cachekey      = '_oembed_' . $key_suffix;
     236
     237                add_filter( 'pre_oembed_result', '__return_empty_string' );
     238                $actual = $this->wp_embed->shortcode( array(), $url );
     239                remove_filter( 'pre_oembed_result', '__return_empty_string' );
     240
     241                $this->assertEquals( $expected, $actual );
     242
     243                $this->assertEquals( '{{unknown}}', get_transient( $cachekey ) );
     244
     245                // Result should be cached.
     246                $actual = $this->wp_embed->shortcode( array(), $url );
     247
     248                // Cleanup.
     249                delete_transient( $cachekey );
     250
     251                $this->assertEquals( $expected, $actual );
     252        }
     253
     254        public function test_shortcode_should_get_url_from_src_attribute() {
     255                $url    = 'http://example.com/embed/foo';
     256                $actual = $this->wp_embed->shortcode( array( 'src' => $url ) );
     257
     258                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     259        }
     260
     261        public function test_shortcode_should_return_empty_string_for_missing_url() {
     262                $this->assertEmpty( $this->wp_embed->shortcode( array() ) );
     263        }
     264
     265        public function test_shortcode_should_make_link_for_unknown_url() {
     266                $url    = 'http://example.com/embed/foo';
     267                $actual = $this->wp_embed->shortcode( array(), $url );
     268
     269                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     270        }
     271
     272        public function test_run_shortcode_url_only() {
     273                $url    = 'http://example.com/embed/foo';
     274                $actual = $this->wp_embed->run_shortcode( '[embed]' . $url . '[/embed]' );
     275                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     276        }
     277
     278        public function test_maybe_make_link() {
     279                $url    = 'http://example.com/embed/foo';
     280                $actual = $this->wp_embed->maybe_make_link( $url );
     281
     282                $this->assertEquals( '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>', $actual );
     283        }
     284
     285        public function test_maybe_make_link_return_false_on_fail() {
     286                $this->wp_embed->return_false_on_fail = true;
     287                $this->assertFalse( $this->wp_embed->maybe_make_link( 'http://example.com/' ) );
     288        }
     289
     290        public function test_maybe_make_link_do_not_link_if_unknown() {
     291                $url = 'http://example.com/';
     292
     293                $this->wp_embed->linkifunknown = false;
     294                $this->assertEquals( $url, $this->wp_embed->maybe_make_link( $url ) );
     295        }
     296}