WordPress.org

Make WordPress Core

Ticket #36824: 36824-enclosures.diff

File 36824-enclosures.diff, 12.2 KB (added by boonebgorges, 5 months ago)
  • src/wp-includes/comment.php

    diff --git a/src/wp-includes/comment.php b/src/wp-includes/comment.php
    index 4b192ea02e..084f6c6d78 100644
    a b function do_all_pings() { 
    26392639                pingback( $ping->post_content, $ping->ID );
    26402640        }
    26412641
    2642         // Do Enclosures
    2643         while ( $enclosure = $wpdb->get_row( "SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1" ) ) {
    2644                 delete_metadata_by_mid( 'post', $enclosure->meta_id );
    2645                 do_enclose( $enclosure->post_content, $enclosure->ID );
     2642        // Do enclosures.
     2643        $enclosures = get_posts(
     2644                array(
     2645                        'post_type'        => get_post_types( array( 'publicly_queryable' => true ) ),
     2646                        'suppress_filters' => false,
     2647                        'nopaging'         => true,
     2648                        'meta_key'         => '_encloseme',
     2649                        'fields'           => 'ids',
     2650                )
     2651        );
     2652
     2653        foreach ( $enclosure as $enclosure ) {
     2654                delete_post_meta( $enclosure, '_encloseme' );
     2655                do_enclose( null, $enclosure->ID );
    26462656        }
    26472657
    26482658        // Do Trackbacks
  • src/wp-includes/functions.php

    diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
    index 6961378e4e..365ac4477b 100644
    a b function wp_extract_urls( $content ) { 
    802802 *
    803803 * @global wpdb $wpdb WordPress database abstraction object.
    804804 *
    805  * @param string $content Post Content.
    806  * @param int    $post_ID Post ID.
     805 * @param string         $content Post Content.
     806 * @param int|WP_Post    $post    Post ID or post object.
     807 * @return null|bool Returns false if post is not found.
    807808 */
    808 function do_enclose( $content, $post_ID ) {
     809function do_enclose( $content = null, $post ) {
    809810        global $wpdb;
    810811
    811812        //TODO: Tidy this ghetto code up and make the debug code optional
    812813        include_once( ABSPATH . WPINC . '/class-IXR.php' );
    813814
     815        $post = get_post( $post );
     816        if ( ! $post ) {
     817                return false;
     818        }
     819
     820        if ( null === $content ) {
     821                $content = $post->post_content;
     822        }
     823
    814824        $post_links = array();
    815825
    816         $pung = get_enclosed( $post_ID );
     826        $pung = get_enclosed( $post->ID );
    817827
    818828        $post_links_temp = wp_extract_urls( $content );
    819829
    820830        foreach ( $pung as $link_test ) {
    821831                if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
    822                         $mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $link_test ) . '%' ) );
     832                        $mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $link_test ) . '%' ) );
    823833                        foreach ( $mids as $mid ) {
    824834                                delete_metadata_by_mid( 'post', $mid );
    825835                        }
    function do_enclose( $content, $post_ID ) { 
    851861         * @param array $post_links An array of enclosure links.
    852862         * @param int   $post_ID    Post ID.
    853863         */
    854         $post_links = apply_filters( 'enclosure_links', $post_links, $post_ID );
     864        $post_links = apply_filters( 'enclosure_links', $post_links, $post->ID );
    855865
    856866        foreach ( (array) $post_links as $url ) {
    857                 if ( $url != '' && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
     867                if ( $url != '' && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
    858868
    859869                        $headers = wp_get_http_headers( $url );
    860870                        if ( $headers ) {
    function do_enclose( $content, $post_ID ) { 
    878888                                }
    879889
    880890                                if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types ) ) {
    881                                         add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
     891                                        add_post_meta( $post->ID, 'enclosure', "$url\n$len\n$mime\n" );
    882892                                }
    883893                        }
    884894                }
  • new file tests/phpunit/tests/functions/doEnclose.php

    diff --git a/tests/phpunit/tests/functions/doEnclose.php b/tests/phpunit/tests/functions/doEnclose.php
    new file mode 100644
    index 0000000000..a7034f47c4
    - +  
     1<?php
     2/**
     3 * Test cases for the `do_enclose()` function.
     4 *
     5 * @package WordPress\UnitTests
     6 *
     7 * @since 5.3.0
     8 */
     9
     10/**
     11 * Tests_Functions_DoEnclose class.
     12 *
     13 * @group functions.php
     14 * @group post
     15 * @covers do_enclose
     16 *
     17 * @since 5.3.0
     18 */
     19class Tests_Functions_DoEnclose extends WP_UnitTestCase {
     20
     21        /**
     22         * Setup before each test method.
     23         *
     24         * @since 5.3.0
     25         */
     26        public function setUp() {
     27                parent::setUp();
     28                add_filter( 'pre_http_request', array( $this, 'fake_http_request' ), 10, 3 );
     29        }
     30
     31        /**
     32         * Cleanup after each test method.
     33         *
     34         * @since 5.3.0
     35         */
     36        public function tearDown() {
     37                parent::tearDown();
     38                remove_filter( 'pre_http_request', array( $this, 'fake_http_request' ) );
     39        }
     40
     41        /**
     42         * Test the function with an explicit content input.
     43         *
     44         * @since 5.3.0
     45         *
     46         * @dataProvider data_test_do_enclose
     47         */
     48        public function test_function_with_explicit_content_input( $content, $expected ) {
     49                $post_id = self::factory()->post->create();
     50
     51                do_enclose( $content, $post_id );
     52
     53                $actual = $this->get_enclosed_by_post_id( $post_id );
     54                $this->assertSame( $expected, $actual );
     55        }
     56
     57        /**
     58         * Test the function with an implicit content input.
     59         *
     60         * @since 5.3.0
     61         *
     62         * @dataProvider data_test_do_enclose
     63         */
     64        public function test_function_with_implicit_content_input( $content, $expected ) {
     65                $post_id = self::factory()->post->create(
     66                        array(
     67                                'post_content' => $content,
     68                        )
     69                );
     70
     71                do_enclose( null, $post_id );
     72
     73                $actual = $this->get_enclosed_by_post_id( $post_id );
     74                $this->assertSame( $expected, $actual );
     75        }
     76
     77        /**
     78         * Dataprovider for `test_function_with_explicit_content_input()`
     79         * and `test_function_with_implicit_content_input()`.
     80         *
     81         * @since 5.3.0
     82         *
     83         * @return array {
     84         *     @type array {
     85         *         @type string Post content.
     86         *         @type string Expected values.
     87         *     }
     88         * }
     89         */
     90        public function data_test_do_enclose() {
     91                return array(
     92                        'null'                  => array(
     93                                'content'  => null,
     94                                'expected' => '',
     95                        ),
     96                        'empty'                 => array(
     97                                'content'  => '',
     98                                'expected' => '',
     99                        ),
     100                        'single-bare-movie'     => array(
     101                                'content'  => 'movie.mp4',
     102                                'expected' => '',
     103                        ),
     104                        'single-bare-audio'     => array(
     105                                'content'  => 'audio.ogg',
     106                                'expected' => '',
     107                        ),
     108                        'single-relative-movie' => array(
     109                                'content'  => '/movie.mp4',
     110                                'expected' => "/movie.mp4\n123\nvideo/mp4\n",
     111                        ),
     112                        'single-relative-audio' => array(
     113                                'content'  => '/audio.ogg',
     114                                'expected' => "/audio.ogg\n321\naudio/ogg\n",
     115                        ),
     116                        'single-unknown'        => array(
     117                                'content'  => 'https://example.com/wp-content/uploads/2018/06/file.unknown',
     118                                'expected' => '',
     119                        ),
     120                        'single-movie'          => array(
     121                                'content'  => 'https://example.com/wp-content/uploads/2018/06/movie.mp4',
     122                                'expected' => "https://example.com/wp-content/uploads/2018/06/movie.mp4\n123\nvideo/mp4\n",
     123                        ),
     124                        'single-audio'          => array(
     125                                'content'  => 'https://example.com/wp-content/uploads/2018/06/audio.ogg',
     126                                'expected' => "https://example.com/wp-content/uploads/2018/06/audio.ogg\n321\naudio/ogg\n",
     127                        ),
     128                        'single-movie-query'    => array(
     129                                'content'  => 'https://example.com/wp-content/uploads/2018/06/movie.mp4?test=1',
     130                                'expected' => "https://example.com/wp-content/uploads/2018/06/movie.mp4?test=1\n123\nvideo/mp4\n",
     131                        ),
     132                        'multi'                 => array(
     133                                'content'  => "https://example.com/wp-content/uploads/2018/06/audio.ogg\n" .
     134                                                          'https://example.com/wp-content/uploads/2018/06/movie.mp4',
     135                                'expected' => "https://example.com/wp-content/uploads/2018/06/audio.ogg\n321\naudio/ogg\n" .
     136                                                          "https://example.com/wp-content/uploads/2018/06/movie.mp4\n123\nvideo/mp4\n",
     137                        ),
     138                );
     139        }
     140
     141        /**
     142         * The function should return false when the post ID input is invalid.
     143         *
     144         * @since 5.3.0
     145         */
     146        public function test_function_should_return_false_when_invalid_post_id() {
     147                $post_id = null;
     148                $result  = do_enclose( null, $post_id );
     149                $this->assertFalse( $result );
     150        }
     151
     152        /**
     153         * The function should delete an enclosed link when it's no longer in the post content.
     154         *
     155         * @since 5.3.0
     156         */
     157        public function test_function_should_delete_enclosed_link_when_no_longer_in_post_content() {
     158                $data = $this->data_test_do_enclose();
     159
     160                // Create a post with a single movie link.
     161                $post_id = self::factory()->post->create(
     162                        array(
     163                                'post_content' => $data['single-movie']['content'],
     164                        )
     165                );
     166
     167                do_enclose( null, $post_id );
     168
     169                $actual = $this->get_enclosed_by_post_id( $post_id );
     170                $this->assertSame( $data['single-movie']['expected'], $actual );
     171
     172                // Replace the movie link with an audio link.
     173                wp_update_post(
     174                        array(
     175                                'ID'           => $post_id,
     176                                'post_content' => $data['single-audio']['content'],
     177                        )
     178                );
     179
     180                do_enclose( null, $post_id );
     181
     182                $actual = $this->get_enclosed_by_post_id( $post_id );
     183                $this->assertSame( $data['single-audio']['expected'], $actual );
     184        }
     185
     186        /**
     187         * The function should support a post object input.
     188         *
     189         * @since 5.3.0
     190         */
     191        public function test_function_should_support_post_object_input() {
     192                $data = $this->data_test_do_enclose();
     193
     194                $post_object = self::factory()->post->create_and_get(
     195                        array(
     196                                'post_content' => $data['multi']['content'],
     197                        )
     198                );
     199
     200                do_enclose( null, $post_object );
     201
     202                $actual = $this->get_enclosed_by_post_id( $post_object->ID );
     203                $this->assertSame( $data['multi']['expected'], $actual );
     204        }
     205
     206        /**
     207         * The enclosure links should be filterable with the `enclosure_links` filter.
     208         *
     209         * @since 5.3.0
     210         */
     211        public function test_function_enclosure_links_should_be_filterable() {
     212                $data = $this->data_test_do_enclose();
     213
     214                $post_id = self::factory()->post->create(
     215                        array(
     216                                'post_content' => $data['multi']['content'],
     217                        )
     218                );
     219
     220                add_filter( 'enclosure_links', array( $this, 'filter_enclosure_links' ), 10, 2 );
     221                do_enclose( null, $post_id );
     222                remove_filter( 'enclosure_links', array( $this, 'filter_enclosure_links' ) );
     223
     224                $actual   = $this->get_enclosed_by_post_id( $post_id );
     225                $expected = str_replace( 'example.org', sprintf( 'example-%d.org', $post_id ), $data['multi']['expected'] );
     226                $this->assertSame( $expected, $actual );
     227        }
     228
     229        /**
     230         * A callback to filter the list of enclosure links.
     231         *
     232         * @since 5.3.0
     233         *
     234         * @param  array $post_links An array of enclosure links.
     235         * @param  int   $post_id    Post ID.
     236         * @return array $post_links An array of enclosure links.
     237         */
     238        public function filter_enclosure_links( $enclosure_links, $post_id ) {
     239                // Replace the link host to contain the post ID, to test both filter input arguments.
     240                foreach ( $enclosure_links as &$link ) {
     241                        $link = str_replace( 'example.org', sprintf( 'example-%d.org', $post_id ), $link );
     242                }
     243                return $enclosure_links;
     244        }
     245
     246        /**
     247         * Helper function to get all enclosure data for a given post.
     248         *
     249         * @since 5.3.0
     250         *
     251         * @param  int    $post_id Post ID.
     252         * @return string          All enclosure data for the given post.
     253         */
     254        protected function get_enclosed_by_post_id( $post_id ) {
     255                return join( (array) get_post_meta( $post_id, 'enclosure', false ), '' );
     256        }
     257
     258        /**
     259         * Fake the HTTP request response.
     260         *
     261         * @since 5.3.0
     262         *
     263         * @param bool   $false     False.
     264         * @param array  $arguments Request arguments.
     265         * @param string $url       Request URL.
     266         *
     267         * @return array            Header.
     268         */
     269        public function fake_http_request( $false, $arguments, $url ) {
     270
     271                // Video and audio headers.
     272                $fake_headers = array(
     273                        'mp4' => array(
     274                                'headers' => array(
     275                                        'content-length' => 123,
     276                                        'content-type'   => 'video/mp4',
     277                                ),
     278                        ),
     279                        'ogg' => array(
     280                                'headers' => array(
     281                                        'content-length' => 321,
     282                                        'content-type'   => 'audio/ogg',
     283                                ),
     284                        ),
     285                );
     286
     287                $path = parse_url( $url, PHP_URL_PATH );
     288
     289                if ( false !== $path ) {
     290                        $extension = pathinfo( $path, PATHINFO_EXTENSION );
     291                        if ( isset( $fake_headers[ $extension ] ) ) {
     292                                return $fake_headers[ $extension ];
     293                        }
     294                }
     295
     296                // Fallback header.
     297                return array(
     298                        'headers' => array(
     299                                'content-length' => 0,
     300                                'content-type'   => '',
     301                        ),
     302                );
     303        }
     304
     305}