Make WordPress Core

Changeset 58130


Ignore:
Timestamp:
05/10/2024 06:57:53 PM (2 years ago)
Author:
swissspidy
Message:

REST API: Ensure attachments are uploaded to the post's year/month folder.

If organizing uploads into month- and year-based folders, uploading an attachment to an existing post should store the file in wp-content/uploads/<year>/<month> based on the post's publish date. This is in line with the behavior in classic editor / the media modal.

Props swissspidy, adamsilverstein, timothyblynjacobs, skithund, sergeybiryukov, patricia70.
Fixes #61189.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/file.php

    r57984 r58130  
    10901090 *                               to override default variables. Default false.
    10911091 *                               See _wp_handle_upload() for accepted values.
    1092  * @param string      $time      Optional. Time formatted in 'yyyy/mm'. Default null.
     1092 * @param string|null $time      Optional. Time formatted in 'yyyy/mm'. Default null.
    10931093 * @return array See _wp_handle_upload() for return value.
    10941094 */
     
    11211121 *                               to override default variables. Default false.
    11221122 *                               See _wp_handle_upload() for accepted values.
    1123  * @param string      $time      Optional. Time formatted in 'yyyy/mm'. Default null.
     1123 * @param string|null $time      Optional. Time formatted in 'yyyy/mm'. Default null.
    11241124 * @return array See _wp_handle_upload() for return value.
    11251125 */
  • trunk/src/wp-includes/functions.php

    r57987 r58130  
    23452345 * @uses _wp_upload_dir()
    23462346 *
    2347  * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
    2348  * @param bool   $create_dir Optional. Whether to check and create the uploads directory.
    2349  *                           Default true for backward compatibility.
    2350  * @param bool   $refresh_cache Optional. Whether to refresh the cache. Default false.
     2347 * @param string|null $time          Optional. Time formatted in 'yyyy/mm'. Default null.
     2348 * @param bool        $create_dir    Optional. Whether to check and create the uploads directory.
     2349 *                                   Default true for backward compatibility.
     2350 * @param bool        $refresh_cache Optional. Whether to refresh the cache. Default false.
    23512351 * @return array {
    23522352 *     Array of information about the upload directory.
     
    24202420 * @access private
    24212421 *
    2422  * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
     2422 * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
    24232423 * @return array See wp_upload_dir()
    24242424 */
     
    28722872 * @param null|string $deprecated Never used. Set to null.
    28732873 * @param string      $bits       File content
    2874  * @param string      $time       Optional. Time formatted in 'yyyy/mm'. Default null.
     2874 * @param string|null $time       Optional. Time formatted in 'yyyy/mm'. Default null.
    28752875 * @return array {
    28762876 *     Information about the newly-uploaded file.
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php

    r57603 r58130  
    255255                $headers = $request->get_headers();
    256256
     257                $time = null;
     258
     259                // Matches logic in media_handle_upload().
     260                if ( ! empty( $request['post'] ) ) {
     261                        $post = get_post( $request['post'] );
     262                        // The post date doesn't usually matter for pages, so don't backdate this upload.
     263                        if ( $post && 'page' !== $post->post_type && substr( $post->post_date, 0, 4 ) > 0 ) {
     264                                $time = $post->post_date;
     265                        }
     266                }
     267
    257268                if ( ! empty( $files ) ) {
    258                         $file = $this->upload_from_file( $files, $headers );
     269                        $file = $this->upload_from_file( $files, $headers, $time );
    259270                } else {
    260                         $file = $this->upload_from_data( $request->get_body(), $headers );
     271                        $file = $this->upload_from_data( $request->get_body(), $headers, $time );
    261272                }
    262273
     
    10361047         *
    10371048         * @since 4.7.0
    1038          *
    1039          * @param string $data    Supplied file data.
    1040          * @param array  $headers HTTP headers from the request.
     1049         * @since 6.6.0 Added the `$time` parameter.
     1050         *
     1051         * @param string      $data    Supplied file data.
     1052         * @param array       $headers HTTP headers from the request.
     1053         * @param string|null $time    Optional. Time formatted in 'yyyy/mm'. Default null.
    10411054         * @return array|WP_Error Data from wp_handle_sideload().
    10421055         */
    1043         protected function upload_from_data( $data, $headers ) {
     1056        protected function upload_from_data( $data, $headers, $time = null ) {
    10441057                if ( empty( $data ) ) {
    10451058                        return new WP_Error(
     
    11291142                );
    11301143
    1131                 $sideloaded = wp_handle_sideload( $file_data, $overrides );
     1144                $sideloaded = wp_handle_sideload( $file_data, $overrides, $time );
    11321145
    11331146                if ( isset( $sideloaded['error'] ) ) {
     
    12471260         *
    12481261         * @since 4.7.0
    1249          *
    1250          * @param array $files   Data from the `$_FILES` superglobal.
    1251          * @param array $headers HTTP headers from the request.
     1262         * @since 6.6.0 Added the `$time` parameter.
     1263         *
     1264         * @param array       $files   Data from the `$_FILES` superglobal.
     1265         * @param array       $headers HTTP headers from the request.
     1266         * @param string|null $time    Optional. Time formatted in 'yyyy/mm'. Default null.
    12521267         * @return array|WP_Error Data from wp_handle_upload().
    12531268         */
    1254         protected function upload_from_file( $files, $headers ) {
     1269        protected function upload_from_file( $files, $headers, $time = null ) {
    12551270                if ( empty( $files ) ) {
    12561271                        return new WP_Error(
     
    12941309                require_once ABSPATH . 'wp-admin/includes/file.php';
    12951310
    1296                 $file = wp_handle_upload( $files['file'], $overrides );
     1311                $file = wp_handle_upload( $files['file'], $overrides, $time );
    12971312
    12981313                if ( isset( $file['error'] ) ) {
  • trunk/tests/phpunit/tests/rest-api/rest-attachments-controller.php

    r58065 r58130  
    20762076        }
    20772077
     2078        /**
     2079         * @ticket 61189
     2080         * @requires function imagejpeg
     2081         */
     2082        public function test_create_item_year_month_based_folders() {
     2083                update_option( 'uploads_use_yearmonth_folders', 1 );
     2084
     2085                wp_set_current_user( self::$editor_id );
     2086
     2087                $published_post = self::factory()->post->create(
     2088                        array(
     2089                                'post_status'   => 'publish',
     2090                                'post_date'     => '2017-02-14 00:00:00',
     2091                                'post_date_gmt' => '2017-02-14 00:00:00',
     2092                        )
     2093                );
     2094
     2095                $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
     2096                $request->set_header( 'Content-Type', 'image/jpeg' );
     2097                $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
     2098                $request->set_param( 'title', 'My title is very cool' );
     2099                $request->set_param( 'caption', 'This is a better caption.' );
     2100                $request->set_param( 'description', 'Without a description, my attachment is descriptionless.' );
     2101                $request->set_param( 'alt_text', 'Alt text is stored outside post schema.' );
     2102                $request->set_param( 'post', $published_post );
     2103
     2104                $request->set_body( file_get_contents( self::$test_file ) );
     2105                $response = rest_get_server()->dispatch( $request );
     2106                $data     = $response->get_data();
     2107
     2108                update_option( 'uploads_use_yearmonth_folders', 0 );
     2109
     2110                $this->assertSame( 201, $response->get_status() );
     2111
     2112                $attachment = get_post( $data['id'] );
     2113
     2114                $this->assertSame( $attachment->post_parent, $data['post'] );
     2115                $this->assertSame( $attachment->post_parent, $published_post );
     2116                $this->assertSame( wp_get_attachment_url( $attachment->ID ), $data['source_url'] );
     2117                $this->assertStringContainsString( '2017/02', $data['source_url'] );
     2118        }
     2119
     2120
     2121        /**
     2122         * @ticket 61189
     2123         * @requires function imagejpeg
     2124         */
     2125        public function test_create_item_year_month_based_folders_page_post_type() {
     2126                update_option( 'uploads_use_yearmonth_folders', 1 );
     2127
     2128                wp_set_current_user( self::$editor_id );
     2129
     2130                $published_post = self::factory()->post->create(
     2131                        array(
     2132                                'post_type'     => 'page',
     2133                                'post_status'   => 'publish',
     2134                                'post_date'     => '2017-02-14 00:00:00',
     2135                                'post_date_gmt' => '2017-02-14 00:00:00',
     2136                        )
     2137                );
     2138
     2139                $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
     2140                $request->set_header( 'Content-Type', 'image/jpeg' );
     2141                $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
     2142                $request->set_param( 'title', 'My title is very cool' );
     2143                $request->set_param( 'caption', 'This is a better caption.' );
     2144                $request->set_param( 'description', 'Without a description, my attachment is descriptionless.' );
     2145                $request->set_param( 'alt_text', 'Alt text is stored outside post schema.' );
     2146                $request->set_param( 'post', $published_post );
     2147
     2148                $request->set_body( file_get_contents( self::$test_file ) );
     2149                $response = rest_get_server()->dispatch( $request );
     2150                $data     = $response->get_data();
     2151
     2152                update_option( 'uploads_use_yearmonth_folders', 0 );
     2153
     2154                $time   = current_time( 'mysql' );
     2155                $y      = substr( $time, 0, 4 );
     2156                $m      = substr( $time, 5, 2 );
     2157                $subdir = "/$y/$m";
     2158
     2159                $this->assertSame( 201, $response->get_status() );
     2160
     2161                $attachment = get_post( $data['id'] );
     2162
     2163                $this->assertSame( $attachment->post_parent, $data['post'] );
     2164                $this->assertSame( $attachment->post_parent, $published_post );
     2165                $this->assertSame( wp_get_attachment_url( $attachment->ID ), $data['source_url'] );
     2166                $this->assertStringNotContainsString( '2017/02', $data['source_url'] );
     2167                $this->assertStringContainsString( $subdir, $data['source_url'] );
     2168        }
     2169
    20782170        public function filter_rest_insert_attachment( $attachment ) {
    20792171                ++self::$rest_insert_attachment_count;
Note: See TracChangeset for help on using the changeset viewer.