Make WordPress Core

Changeset 58130


Ignore:
Timestamp:
05/10/2024 06:57:53 PM (5 months 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.