PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.0-beta
16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / json-endpoints / class.wpcom-json-api-edit-media-v1-2-endpoint.php
jetpack / json-endpoints Last commit date
jetpack 2 weeks ago class.wpcom-json-api-add-widget-endpoint.php 7 months ago class.wpcom-json-api-autosave-post-v1-1-endpoint.php 7 months ago class.wpcom-json-api-bulk-delete-post-endpoint.php 7 months ago class.wpcom-json-api-bulk-restore-post-endpoint.php 7 months ago class.wpcom-json-api-bulk-update-comments-endpoint.php 1 month ago class.wpcom-json-api-comment-endpoint.php 7 months ago class.wpcom-json-api-delete-media-endpoint.php 7 months ago class.wpcom-json-api-delete-media-v1-1-endpoint.php 7 months ago class.wpcom-json-api-edit-media-v1-2-endpoint.php 1 month ago class.wpcom-json-api-get-autosave-v1-1-endpoint.php 7 months ago class.wpcom-json-api-get-comment-counts-endpoint.php 7 months ago class.wpcom-json-api-get-comment-endpoint.php 7 months ago class.wpcom-json-api-get-comment-history-endpoint.php 7 months ago class.wpcom-json-api-get-comments-tree-endpoint.php 7 months ago class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php 7 months ago class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php 7 months ago class.wpcom-json-api-get-customcss.php 7 months ago class.wpcom-json-api-get-media-endpoint.php 7 months ago class.wpcom-json-api-get-media-v1-1-endpoint.php 7 months ago class.wpcom-json-api-get-media-v1-2-endpoint.php 7 months ago class.wpcom-json-api-get-post-counts-v1-1-endpoint.php 2 weeks ago class.wpcom-json-api-get-post-endpoint.php 7 months ago class.wpcom-json-api-get-post-v1-1-endpoint.php 7 months ago class.wpcom-json-api-get-site-endpoint.php 2 weeks ago class.wpcom-json-api-get-site-v1-2-endpoint.php 2 weeks ago class.wpcom-json-api-get-taxonomies-endpoint.php 2 months ago class.wpcom-json-api-get-taxonomy-endpoint.php 7 months ago class.wpcom-json-api-get-term-endpoint.php 7 months ago class.wpcom-json-api-list-comments-endpoint.php 2 weeks ago class.wpcom-json-api-list-dropdown-pages-endpoint.php 7 months ago class.wpcom-json-api-list-embeds-endpoint.php 7 months ago class.wpcom-json-api-list-media-endpoint.php 7 months ago class.wpcom-json-api-list-media-v1-1-endpoint.php 1 month ago class.wpcom-json-api-list-media-v1-2-endpoint.php 7 months ago class.wpcom-json-api-list-post-type-taxonomies-endpoint.php 7 months ago class.wpcom-json-api-list-post-types-endpoint.php 7 months ago class.wpcom-json-api-list-posts-endpoint.php 2 weeks ago class.wpcom-json-api-list-posts-v1-1-endpoint.php 2 weeks ago class.wpcom-json-api-list-posts-v1-2-endpoint.php 2 weeks ago class.wpcom-json-api-list-roles-endpoint.php 7 months ago class.wpcom-json-api-list-shortcodes-endpoint.php 7 months ago class.wpcom-json-api-list-terms-endpoint.php 7 months ago class.wpcom-json-api-list-users-endpoint.php 2 weeks ago class.wpcom-json-api-menus-v1-1-endpoint.php 1 month ago class.wpcom-json-api-post-endpoint.php 7 months ago class.wpcom-json-api-post-v1-1-endpoint.php 2 months ago class.wpcom-json-api-render-embed-endpoint.php 7 months ago class.wpcom-json-api-render-embed-reversal-endpoint.php 7 months ago class.wpcom-json-api-render-endpoint.php 1 month ago class.wpcom-json-api-render-shortcode-endpoint.php 7 months ago class.wpcom-json-api-sharing-buttons-endpoint.php 1 month ago class.wpcom-json-api-site-settings-endpoint.php 2 weeks ago class.wpcom-json-api-site-settings-v1-2-endpoint.php 7 months ago class.wpcom-json-api-site-settings-v1-3-endpoint.php 7 months ago class.wpcom-json-api-site-settings-v1-4-endpoint.php 2 weeks ago class.wpcom-json-api-site-user-endpoint.php 7 months ago class.wpcom-json-api-taxonomy-endpoint.php 7 months ago class.wpcom-json-api-update-comment-endpoint.php 6 months ago class.wpcom-json-api-update-customcss.php 7 months ago class.wpcom-json-api-update-media-endpoint.php 7 months ago class.wpcom-json-api-update-media-v1-1-endpoint.php 1 month ago class.wpcom-json-api-update-post-endpoint.php 1 month ago class.wpcom-json-api-update-post-v1-1-endpoint.php 1 month ago class.wpcom-json-api-update-post-v1-2-endpoint.php 1 month ago class.wpcom-json-api-update-site-homepage-endpoint.php 7 months ago class.wpcom-json-api-update-site-logo-endpoint.php 7 months ago class.wpcom-json-api-update-taxonomy-endpoint.php 6 months ago class.wpcom-json-api-update-term-endpoint.php 7 months ago class.wpcom-json-api-update-user-endpoint.php 7 months ago class.wpcom-json-api-upload-media-endpoint.php 7 months ago class.wpcom-json-api-upload-media-v1-1-endpoint.php 7 months ago
class.wpcom-json-api-edit-media-v1-2-endpoint.php
504 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit( 0 );
5 }
6
7 require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.media.php';
8
9 define( 'REVISION_HISTORY_MAXIMUM_AMOUNT', 5 );
10 define( 'WP_ATTACHMENT_IMAGE_ALT', '_wp_attachment_image_alt' );
11
12 new WPCOM_JSON_API_Edit_Media_v1_2_Endpoint(
13 array(
14 'description' => 'Edit a media item.',
15 'group' => 'media',
16 'stat' => 'media:1:POST',
17 'min_version' => '1',
18 'max_version' => '1.2',
19 'method' => 'POST',
20 'path' => '/sites/%s/media/%d/edit',
21 'path_labels' => array(
22 '$site' => '(int|string) Site ID or domain',
23 '$media_ID' => '(int) The ID of the media item',
24 ),
25
26 'request_format' => array(
27 'parent_id' => '(int) ID of the post this media is attached to',
28 'title' => '(string) The file name.',
29 'caption' => '(string) File caption.',
30 'description' => '(HTML) Description of the file.',
31 'alt' => '(string) Alternative text for image files.',
32 'artist' => '(string) Audio Only. Artist metadata for the audio track.',
33 'album' => '(string) Audio Only. Album metadata for the audio track.',
34 'media' => '(media) An object file to attach to the post. To upload media, ' .
35 'the entire request should be multipart/form-data encoded. ' .
36 'Multiple media items will be displayed in a gallery. Accepts ' .
37 'jpg, jpeg, png, gif, pdf, doc, ppt, odt, pptx, docx, pps, ppsx, xls, xlsx, key. ' .
38 'Audio and Video may also be available. See <code>allowed_file_types</code> ' .
39 'in the options response of the site endpoint. ' .
40 '<br /><br /><strong>Example</strong>:<br />' .
41 "<code>curl \<br />--form 'title=Image' \<br />--form 'media=@/path/to/file.jpg' \<br />-H 'Authorization: BEARER your-token' \<br />'https://public-api.wordpress.com/rest/v1/sites/123/media/new'</code>",
42 'attrs' => '(object) An Object of attributes (`title`, `description` and `caption`) ' .
43 'are supported to assign to the media uploaded via the `media` or `media_url`',
44 'media_url' => '(string) An URL of the image to attach to a post.',
45 ),
46
47 'response_format' => array(
48 'ID' => '(int) The ID of the media item',
49 'date' => '(ISO 8601 datetime) The date the media was uploaded',
50 'post_ID' => '(int) ID of the post this media is attached to',
51 'author_ID' => '(int) ID of the user who uploaded the media',
52 'URL' => '(string) URL to the file',
53 'guid' => '(string) Unique identifier',
54 'file' => '(string) File name',
55 'extension' => '(string) File extension',
56 'mime_type' => '(string) File mime type',
57 'title' => '(string) File name',
58 'caption' => '(string) User provided caption of the file',
59 'description' => '(string) Description of the file',
60 'alt' => '(string) Alternative text for image files.',
61 'thumbnails' => '(object) Media item thumbnail URL options',
62 'height' => '(int) (Image & video only) Height of the media item',
63 'width' => '(int) (Image & video only) Width of the media item',
64 'length' => '(int) (Video & audio only) Duration of the media item, in seconds',
65 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item',
66 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress',
67 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.',
68 'revision_history' => '(object) An object with `items` and `original` keys. ' .
69 '`original` is an object with data about the original image. ' .
70 '`items` is an array of snapshots of the previous images of this Media. ' .
71 'Each item has the `URL`, `file, `extension`, `date`, and `mime_type` fields.',
72 ),
73
74 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/82974409/media/446',
75 'example_request_data' => array(
76 'headers' => array(
77 'authorization' => 'Bearer YOUR_API_TOKEN',
78 ),
79 'body' => array(
80 'title' => 'Updated Title',
81 ),
82 ),
83 )
84 );
85
86 /**
87 * Edit media v1_2 endpoint class.
88 *
89 * @phan-constructor-used-for-side-effects
90 */
91 class WPCOM_JSON_API_Edit_Media_v1_2_Endpoint extends WPCOM_JSON_API_Update_Media_v1_1_Endpoint { //phpcs:ignore
92 /**
93 * Return an array of mime_type items allowed when the media file is uploaded.
94 *
95 * @param array $default_mime_types - array of default mime types.
96 *
97 * @return array mime_type array
98 */
99 public static function get_allowed_mime_types( $default_mime_types ) {
100 return array_unique(
101 array_merge(
102 $default_mime_types,
103 array(
104 'application/msword', // .doc
105 'application/vnd.ms-powerpoint', // .ppt, .pps
106 'application/vnd.ms-excel', // .xls
107 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
108 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', // .ppsx
109 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
110 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
111 'application/vnd.oasis.opendocument.text', // .odt
112 'application/pdf', // .pdf
113 )
114 )
115 );
116 }
117
118 /**
119 * Update the media post grabbing the post values from
120 * the `attrs` parameter
121 *
122 * @param int $media_id - post media ID.
123 * @param array $attrs - `attrs` parameter sent from the client in the request body.
124 */
125 private function update_by_attrs_parameter( $media_id, $attrs ) {
126 $post_update_action = null;
127 $insert = array();
128
129 // Attributes: Title, Caption, Description.
130 if ( isset( $attrs['title'] ) ) {
131 $insert['post_title'] = $attrs['title'];
132 }
133
134 if ( isset( $attrs['caption'] ) ) {
135 $insert['post_excerpt'] = $attrs['caption'];
136 }
137
138 if ( isset( $attrs['description'] ) ) {
139 $insert['post_content'] = $attrs['description'];
140 }
141
142 if ( ! empty( $insert ) ) {
143 $insert['ID'] = $media_id;
144 $update_action = wp_update_post( (object) $insert );
145 if ( is_wp_error( $update_action ) ) {
146 return $update_action;
147 }
148 }
149
150 // Attributes: Alt.
151 if ( isset( $attrs['alt'] ) ) {
152 $alt = wp_strip_all_tags( $attrs['alt'], true );
153 $post_update_action = update_post_meta( $media_id, WP_ATTACHMENT_IMAGE_ALT, $alt );
154
155 if ( is_wp_error( $post_update_action ) ) {
156 return $post_update_action;
157 }
158 }
159
160 // Attributes: Artist, Album.
161 $id3_meta = array();
162
163 foreach ( array( 'artist', 'album' ) as $key ) {
164 if ( isset( $attrs[ $key ] ) ) {
165 $id3_meta[ $key ] = wp_strip_all_tags( $attrs[ $key ], true );
166 }
167 }
168
169 if ( ! empty( $id3_meta ) ) {
170 // Before updating metadata, ensure that the item is audio.
171 $item = $this->get_media_item_v1_1( $media_id );
172 if ( str_starts_with( $item->mime_type, 'audio/' ) ) {
173 $update_action = wp_update_attachment_metadata( $media_id, $id3_meta );
174 if ( is_wp_error( $update_action ) ) {
175 return $update_action;
176 }
177 }
178 }
179
180 return $post_update_action;
181 }
182
183 /**
184 * Return an object to be used to store into the revision_history
185 *
186 * @param object $media_item - media post object.
187 * @return object the snapshot object
188 */
189 private function get_snapshot( $media_item ) {
190 $current_file = get_attached_file( $media_item->ID );
191 $file_paths = pathinfo( $current_file );
192
193 $snapshot = array(
194 'date' => (string) $this->format_date( $media_item->post_modified_gmt, $media_item->post_modified ),
195 'URL' => (string) wp_get_attachment_url( $media_item->ID ),
196 'file' => (string) $file_paths['basename'],
197 'extension' => (string) $file_paths['extension'],
198 'mime_type' => (string) $media_item->post_mime_type,
199 'size' => (int) filesize( $current_file ),
200 );
201
202 return (object) $snapshot;
203 }
204
205 /**
206 * Try to remove the temporal file from the given file array.
207 *
208 * @param array $file_array - Array with data about the temporal file.
209 */
210 private function remove_tmp_file( $file_array ) {
211 if ( file_exists( $file_array['tmp_name'] ) ) {
212 wp_delete_file( $file_array['tmp_name'] );
213 }
214 }
215
216 /**
217 * Save the given temporal file in a local folder.
218 *
219 * @param array $file_array - array containing file data.
220 * @param int $media_id - the media id.
221 * @param bool $is_upload - True if `$file_array` derives from an upload in `$_FILES`, false if this is a sideload.
222 * @return array|WP_Error An array with information about the new file saved or a WP_Error is something went wrong.
223 */
224 private function save_temporary_file( $file_array, $media_id, $is_upload ) {
225 $tmp_filename = $file_array['tmp_name'];
226
227 $is_ok = $is_upload ? is_uploaded_file( $tmp_filename ) : file_exists( $tmp_filename );
228 if ( ! $is_ok ) {
229 return new WP_Error( 'invalid_input', 'No media provided in input.' );
230 }
231
232 // add additional mime_types through of the `jetpack_supported_media_sideload_types` filter.
233 $mime_type_static_filter = array(
234 'WPCOM_JSON_API_Edit_Media_v1_2_Endpoint',
235 'get_allowed_mime_types',
236 );
237
238 add_filter( 'jetpack_supported_media_sideload_types', $mime_type_static_filter );
239 if (
240 ! $this->is_file_supported_for_sideloading( $tmp_filename ) &&
241 ! file_is_displayable_image( $tmp_filename )
242 ) {
243 if ( ! $is_upload ) {
244 wp_delete_file( $tmp_filename );
245 }
246 return new WP_Error( 'invalid_input', 'Invalid file type.', 403 );
247 }
248 remove_filter( 'jetpack_supported_media_sideload_types', $mime_type_static_filter );
249
250 // generate a new file name.
251 $tmp_new_filename = Jetpack_Media::generate_new_filename( $media_id, $file_array['name'] );
252
253 // start to create the parameters to move the temporal file.
254 $overrides = array( 'test_form' => false );
255
256 $time = $this->get_time_string_from_guid( $media_id );
257
258 $file_array['name'] = $tmp_new_filename;
259 if ( $is_upload ) {
260 $file = wp_handle_upload( $file_array, $overrides, $time );
261 } else {
262 $file = wp_handle_sideload( $file_array, $overrides, $time );
263 $this->remove_tmp_file( $file_array );
264 }
265
266 if ( isset( $file['error'] ) ) {
267 return new WP_Error( 'upload_error', $file['error'] );
268 }
269
270 return $file;
271 }
272
273 /**
274 * File urls use the post date to generate a folder path.
275 * Post dates can change, so we use the original date used in the guid
276 * url so edits can remain in the same folder. In the following function
277 * we capture a string in the format of `YYYY/MM` from the guid.
278 *
279 * For example with a guid of
280 * "http://test.files.wordpress.com/2016/10/test.png" the resulting string
281 * would be: "2016/10"
282 *
283 * @param int $media_id - the media id.
284 *
285 * @return string
286 */
287 private function get_time_string_from_guid( $media_id ) {
288 // @todo: investigate if we can replace date with gmdate()
289 // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
290 $time = date( 'Y/m', strtotime( current_time( 'mysql' ) ) );
291 $media = get_post( $media_id );
292 if ( $media ) {
293 $pattern = '/\/(\d{4}\/\d{2})\//';
294 preg_match( $pattern, $media->guid, $matches );
295 if ( count( $matches ) > 1 ) {
296 $time = $matches[1];
297 }
298 }
299 return $time;
300 }
301
302 /**
303 * Get the image from a remote url and then save it locally.
304 *
305 * @param int $media_id - media post ID.
306 * @param string $url - image URL to save locally.
307 * @return array|WP_Error An array with information about the new file saved or a WP_Error is something went wrong.
308 */
309 private function build_file_array_from_url( $media_id, $url ) {
310 if ( ! $url ) {
311 return null;
312 }
313
314 // if we didn't get a URL, let's bail.
315 $parsed = wp_parse_url( $url );
316 if ( empty( $parsed ) ) {
317 return new WP_Error( 'invalid_url', 'No media provided in url.' );
318 }
319
320 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
321 $url = wpcom_get_private_file( $url );
322 }
323
324 // save the remote image into a tmp file.
325 $tmp = download_url( $url );
326 if ( is_wp_error( $tmp ) ) {
327 return $tmp;
328 }
329
330 return array(
331 'name' => basename( $url ),
332 'tmp_name' => $tmp,
333 );
334 }
335
336 /**
337 * Add a new item into revision_history array.
338 *
339 * @param object $media_item - media post.
340 * @param array|WP_Error $file - File data, or WP_Error on error.
341 * @param bool $has_original_media - condition is the original media has been already added.
342 * @return bool `true` if the item has been added. Otherwise `false`.
343 */
344 private function register_revision( $media_item, $file, $has_original_media ) {
345 if (
346 is_wp_error( $file ) ||
347 ! $has_original_media
348 ) {
349 return false;
350 }
351
352 add_post_meta( $media_item->ID, Jetpack_Media::WP_REVISION_HISTORY, $this->get_snapshot( $media_item ) );
353 }
354
355 /**
356 * Restore the original media file.
357 *
358 * @param int $media_id - media post ID.
359 * @param object $original_media - orginal media data.
360 * @return array - restore media info.
361 */
362 private function restore_original( $media_id, $original_media ) {
363 $revisions = (array) Jetpack_Media::get_revision_history( $media_id );
364 $revisions = array_filter(
365 $revisions,
366 function ( $revision ) use ( $original_media ) {
367 return $revision->file !== $original_media->file;
368 }
369 );
370 $criteria = array(
371 'from' => 0,
372 'to' => REVISION_HISTORY_MAXIMUM_AMOUNT,
373 );
374
375 Jetpack_Media::remove_items_from_revision_history( $media_id, $criteria, $revisions );
376 $file = get_attached_file( $media_id );
377 $file_parts = pathinfo( $file );
378 $orginal_file = path_join( $file_parts['dirname'], $original_media->file );
379 $restored_media = array(
380 'file' => $orginal_file,
381 'type' => $original_media->mime_type,
382 );
383
384 return $restored_media;
385 }
386
387 /**
388 * API callback.
389 *
390 * @param string $path - the path.
391 * @param int $blog_id - the blog ID.
392 * @param int $media_id - the media ID.
393 */
394 public function callback( $path = '', $blog_id = 0, $media_id = 0 ) {
395 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
396 if ( is_wp_error( $blog_id ) ) {
397 return $blog_id;
398 }
399
400 $media_item = get_post( $media_id );
401
402 if ( ! $media_item || is_wp_error( $media_item ) ) {
403 return new WP_Error( 'unknown_media', 'Unknown Media', 404 );
404 }
405
406 if ( is_wp_error( $media_item ) ) {
407 return $media_item;
408 }
409
410 if ( ! current_user_can( 'upload_files', $media_id ) ) {
411 return new WP_Error( 'unauthorized', 'User cannot view media', 403 );
412 }
413
414 $input = $this->input( true );
415
416 // Images.
417 $media_file = isset( $input['media'] ) ? (array) $input['media'] : null;
418 $media_url = $input['media_url'] ?? null;
419 $media_attrs = isset( $input['attrs'] ) ? (array) $input['attrs'] : null;
420
421 if ( isset( $media_url ) || $media_file ) {
422 $user_can_upload_files = current_user_can( 'upload_files' ) || $this->api->is_authorized_with_upload_token();
423
424 if ( ! $user_can_upload_files ) {
425 return new WP_Error( 'unauthorized', 'User cannot upload media.', 403 );
426 }
427
428 $has_original_media = Jetpack_Media::get_original_media( $media_id );
429
430 if ( ! $has_original_media ) {
431 // The first time that the media is updated
432 // the original media is stored into the revision_history.
433 $snapshot = $this->get_snapshot( $media_item );
434 add_post_meta( $media_id, Jetpack_Media::WP_ORIGINAL_MEDIA, $snapshot, true );
435 }
436
437 // save the temporal file locally.
438 $is_upload = (bool) $media_file;
439 $temporal_file = $media_file ? $media_file : $this->build_file_array_from_url( $media_id, $media_url );
440
441 if ( is_wp_error( $temporal_file ) ) {
442 return $temporal_file;
443 }
444
445 // edited media is sent as $media_file and restored media is sent as $media_url
446 $should_restore = isset( $media_url ) && ! isset( $media_file ) && $has_original_media;
447
448 $uploaded_file = $should_restore
449 ? $this->restore_original( $media_id, $has_original_media )
450 : $this->save_temporary_file( $temporal_file, $media_id, $is_upload );
451
452 if ( is_wp_error( $uploaded_file ) ) {
453 return $uploaded_file;
454 }
455
456 // revision_history control.
457 $this->register_revision( $media_item, $uploaded_file, $has_original_media );
458
459 $uploaded_path = $uploaded_file['file'];
460 $udpated_mime_type = $uploaded_file['type'];
461 $was_updated = update_attached_file( $media_id, $uploaded_path );
462
463 if ( $was_updated ) {
464 $new_metadata = wp_generate_attachment_metadata( $media_id, $uploaded_path );
465 wp_update_attachment_metadata( $media_id, $new_metadata );
466
467 // check maximum amount of revision_history.
468 Jetpack_Media::limit_revision_history( $media_id, REVISION_HISTORY_MAXIMUM_AMOUNT );
469
470 wp_update_post(
471 (object) array(
472 'ID' => $media_id,
473 'post_mime_type' => $udpated_mime_type,
474 )
475 );
476 }
477
478 unset( $input['media'] );
479 unset( $input['media_url'] );
480 unset( $input['attrs'] );
481 }
482
483 // update media through of `attrs` value it it's defined.
484 if ( ( $media_file || isset( $media_url ) ) && $media_attrs ) {
485 $was_updated = $this->update_by_attrs_parameter( $media_id, $media_attrs );
486
487 if ( is_wp_error( $was_updated ) ) {
488 return $was_updated;
489 }
490 }
491
492 // call parent method.
493 $response = parent::callback( $path, $blog_id, $media_id );
494
495 // expose `revision_history` object.
496 $response->revision_history = (object) array(
497 'items' => (array) Jetpack_Media::get_revision_history( $media_id ),
498 'original' => (object) Jetpack_Media::get_original_media( $media_id ),
499 );
500
501 return $response;
502 }
503 }
504