PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.9.2
Jetpack – WP Security, Backup, Speed, & Growth v13.9.2
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 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 years ago class.wpcom-json-api-add-widget-endpoint.php 2 years ago class.wpcom-json-api-autosave-post-v1-1-endpoint.php 5 years ago class.wpcom-json-api-bulk-delete-post-endpoint.php 4 years ago class.wpcom-json-api-bulk-restore-post-endpoint.php 2 years ago class.wpcom-json-api-bulk-update-comments-endpoint.php 3 years ago class.wpcom-json-api-comment-endpoint.php 2 years ago class.wpcom-json-api-delete-media-endpoint.php 4 years ago class.wpcom-json-api-delete-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-edit-media-v1-2-endpoint.php 2 years ago class.wpcom-json-api-get-autosave-v1-1-endpoint.php 5 years ago class.wpcom-json-api-get-comment-counts-endpoint.php 4 years ago class.wpcom-json-api-get-comment-endpoint.php 4 years ago class.wpcom-json-api-get-comment-history-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php 4 years ago class.wpcom-json-api-get-customcss.php 2 years ago class.wpcom-json-api-get-media-endpoint.php 4 years ago class.wpcom-json-api-get-media-v1-1-endpoint.php 4 years ago class.wpcom-json-api-get-media-v1-2-endpoint.php 2 years ago class.wpcom-json-api-get-post-counts-v1-1-endpoint.php 2 years ago class.wpcom-json-api-get-post-endpoint.php 2 years ago class.wpcom-json-api-get-post-v1-1-endpoint.php 2 years ago class.wpcom-json-api-get-site-endpoint.php 1 year ago class.wpcom-json-api-get-site-v1-2-endpoint.php 2 years ago class.wpcom-json-api-get-taxonomies-endpoint.php 2 years ago class.wpcom-json-api-get-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-get-term-endpoint.php 4 years ago class.wpcom-json-api-list-comments-endpoint.php 2 years ago class.wpcom-json-api-list-dropdown-pages-endpoint.php 3 years ago class.wpcom-json-api-list-embeds-endpoint.php 4 years ago class.wpcom-json-api-list-media-endpoint.php 2 years ago class.wpcom-json-api-list-media-v1-1-endpoint.php 2 years ago class.wpcom-json-api-list-media-v1-2-endpoint.php 2 years ago class.wpcom-json-api-list-post-type-taxonomies-endpoint.php 4 years ago class.wpcom-json-api-list-post-types-endpoint.php 3 years ago class.wpcom-json-api-list-posts-endpoint.php 2 years ago class.wpcom-json-api-list-posts-v1-1-endpoint.php 3 years ago class.wpcom-json-api-list-posts-v1-2-endpoint.php 3 years ago class.wpcom-json-api-list-roles-endpoint.php 2 years ago class.wpcom-json-api-list-shortcodes-endpoint.php 4 years ago class.wpcom-json-api-list-terms-endpoint.php 2 years ago class.wpcom-json-api-list-users-endpoint.php 2 years ago class.wpcom-json-api-menus-v1-1-endpoint.php 2 years ago class.wpcom-json-api-post-endpoint.php 2 years ago class.wpcom-json-api-post-v1-1-endpoint.php 2 years ago class.wpcom-json-api-render-embed-endpoint.php 2 years ago class.wpcom-json-api-render-embed-reversal-endpoint.php 2 years ago class.wpcom-json-api-render-endpoint.php 3 years ago class.wpcom-json-api-render-shortcode-endpoint.php 3 years ago class.wpcom-json-api-sharing-buttons-endpoint.php 2 years ago class.wpcom-json-api-site-settings-endpoint.php 1 year ago class.wpcom-json-api-site-settings-v1-2-endpoint.php 2 years ago class.wpcom-json-api-site-settings-v1-3-endpoint.php 2 years ago class.wpcom-json-api-site-settings-v1-4-endpoint.php 1 year ago class.wpcom-json-api-site-user-endpoint.php 2 years ago class.wpcom-json-api-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-comment-endpoint.php 2 years ago class.wpcom-json-api-update-customcss.php 2 years ago class.wpcom-json-api-update-media-endpoint.php 4 years ago class.wpcom-json-api-update-media-v1-1-endpoint.php 2 years ago class.wpcom-json-api-update-post-endpoint.php 3 years ago class.wpcom-json-api-update-post-v1-1-endpoint.php 2 years ago class.wpcom-json-api-update-post-v1-2-endpoint.php 2 years ago class.wpcom-json-api-update-site-homepage-endpoint.php 4 years ago class.wpcom-json-api-update-site-logo-endpoint.php 2 years ago class.wpcom-json-api-update-taxonomy-endpoint.php 4 years ago class.wpcom-json-api-update-term-endpoint.php 4 years ago class.wpcom-json-api-update-user-endpoint.php 3 years ago class.wpcom-json-api-upload-media-endpoint.php 3 years ago class.wpcom-json-api-upload-media-v1-1-endpoint.php 2 years ago
class.wpcom-json-api-edit-media-v1-2-endpoint.php
498 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.media.php';
4
5 define( 'REVISION_HISTORY_MAXIMUM_AMOUNT', 5 );
6 define( 'WP_ATTACHMENT_IMAGE_ALT', '_wp_attachment_image_alt' );
7
8 new WPCOM_JSON_API_Edit_Media_v1_2_Endpoint(
9 array(
10 'description' => 'Edit a media item.',
11 'group' => 'media',
12 'stat' => 'media:1:POST',
13 'min_version' => '1',
14 'max_version' => '1.2',
15 'method' => 'POST',
16 'path' => '/sites/%s/media/%d/edit',
17 'path_labels' => array(
18 '$site' => '(int|string) Site ID or domain',
19 '$media_ID' => '(int) The ID of the media item',
20 ),
21
22 'request_format' => array(
23 'parent_id' => '(int) ID of the post this media is attached to',
24 'title' => '(string) The file name.',
25 'caption' => '(string) File caption.',
26 'description' => '(HTML) Description of the file.',
27 'alt' => '(string) Alternative text for image files.',
28 'artist' => '(string) Audio Only. Artist metadata for the audio track.',
29 'album' => '(string) Audio Only. Album metadata for the audio track.',
30 'media' => '(media) An object file to attach to the post. To upload media, ' .
31 'the entire request should be multipart/form-data encoded. ' .
32 'Multiple media items will be displayed in a gallery. Accepts ' .
33 'jpg, jpeg, png, gif, pdf, doc, ppt, odt, pptx, docx, pps, ppsx, xls, xlsx, key. ' .
34 'Audio and Video may also be available. See <code>allowed_file_types</code> ' .
35 'in the options response of the site endpoint. ' .
36 '<br /><br /><strong>Example</strong>:<br />' .
37 "<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>",
38 'attrs' => '(object) An Object of attributes (`title`, `description` and `caption`) ' .
39 'are supported to assign to the media uploaded via the `media` or `media_url`',
40 'media_url' => '(string) An URL of the image to attach to a post.',
41 ),
42
43 'response_format' => array(
44 'ID' => '(int) The ID of the media item',
45 'date' => '(ISO 8601 datetime) The date the media was uploaded',
46 'post_ID' => '(int) ID of the post this media is attached to',
47 'author_ID' => '(int) ID of the user who uploaded the media',
48 'URL' => '(string) URL to the file',
49 'guid' => '(string) Unique identifier',
50 'file' => '(string) File name',
51 'extension' => '(string) File extension',
52 'mime_type' => '(string) File mime type',
53 'title' => '(string) File name',
54 'caption' => '(string) User provided caption of the file',
55 'description' => '(string) Description of the file',
56 'alt' => '(string) Alternative text for image files.',
57 'thumbnails' => '(object) Media item thumbnail URL options',
58 'height' => '(int) (Image & video only) Height of the media item',
59 'width' => '(int) (Image & video only) Width of the media item',
60 'length' => '(int) (Video & audio only) Duration of the media item, in seconds',
61 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item',
62 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress',
63 '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.',
64 'revision_history' => '(object) An object with `items` and `original` keys. ' .
65 '`original` is an object with data about the original image. ' .
66 '`items` is an array of snapshots of the previous images of this Media. ' .
67 'Each item has the `URL`, `file, `extension`, `date`, and `mime_type` fields.',
68 ),
69
70 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/82974409/media/446',
71 'example_request_data' => array(
72 'headers' => array(
73 'authorization' => 'Bearer YOUR_API_TOKEN',
74 ),
75 'body' => array(
76 'title' => 'Updated Title',
77 ),
78 ),
79 )
80 );
81
82 /**
83 * Edit media v1_2 endpoint class.
84 */
85 class WPCOM_JSON_API_Edit_Media_v1_2_Endpoint extends WPCOM_JSON_API_Update_Media_v1_1_Endpoint { //phpcs:ignore
86 /**
87 * Return an array of mime_type items allowed when the media file is uploaded.
88 *
89 * @param array $default_mime_types - array of default mime types.
90 *
91 * @return array mime_type array
92 */
93 public static function get_allowed_mime_types( $default_mime_types ) {
94 return array_unique(
95 array_merge(
96 $default_mime_types,
97 array(
98 'application/msword', // .doc
99 'application/vnd.ms-powerpoint', // .ppt, .pps
100 'application/vnd.ms-excel', // .xls
101 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
102 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', // .ppsx
103 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
104 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
105 'application/vnd.oasis.opendocument.text', // .odt
106 'application/pdf', // .pdf
107 )
108 )
109 );
110 }
111
112 /**
113 * Update the media post grabbing the post values from
114 * the `attrs` parameter
115 *
116 * @param int $media_id - post media ID.
117 * @param array $attrs - `attrs` parameter sent from the client in the request body.
118 */
119 private function update_by_attrs_parameter( $media_id, $attrs ) {
120 $post_update_action = null;
121 $insert = array();
122
123 // Attributes: Title, Caption, Description.
124 if ( isset( $attrs['title'] ) ) {
125 $insert['post_title'] = $attrs['title'];
126 }
127
128 if ( isset( $attrs['caption'] ) ) {
129 $insert['post_excerpt'] = $attrs['caption'];
130 }
131
132 if ( isset( $attrs['description'] ) ) {
133 $insert['post_content'] = $attrs['description'];
134 }
135
136 if ( ! empty( $insert ) ) {
137 $insert['ID'] = $media_id;
138 $update_action = wp_update_post( (object) $insert );
139 if ( is_wp_error( $update_action ) ) {
140 return $update_action;
141 }
142 }
143
144 // Attributes: Alt.
145 if ( isset( $attrs['alt'] ) ) {
146 $alt = wp_strip_all_tags( $attrs['alt'], true );
147 $post_update_action = update_post_meta( $media_id, WP_ATTACHMENT_IMAGE_ALT, $alt );
148
149 if ( is_wp_error( $post_update_action ) ) {
150 return $post_update_action;
151 }
152 }
153
154 // Attributes: Artist, Album.
155 $id3_meta = array();
156
157 foreach ( array( 'artist', 'album' ) as $key ) {
158 if ( isset( $attrs[ $key ] ) ) {
159 $id3_meta[ $key ] = wp_strip_all_tags( $attrs[ $key ], true );
160 }
161 }
162
163 if ( ! empty( $id3_meta ) ) {
164 // Before updating metadata, ensure that the item is audio.
165 $item = $this->get_media_item_v1_1( $media_id );
166 if ( str_starts_with( $item->mime_type, 'audio/' ) ) {
167 $update_action = wp_update_attachment_metadata( $media_id, $id3_meta );
168 if ( is_wp_error( $update_action ) ) {
169 return $update_action;
170 }
171 }
172 }
173
174 return $post_update_action;
175 }
176
177 /**
178 * Return an object to be used to store into the revision_history
179 *
180 * @param object $media_item - media post object.
181 * @return object the snapshot object
182 */
183 private function get_snapshot( $media_item ) {
184 $current_file = get_attached_file( $media_item->ID );
185 $file_paths = pathinfo( $current_file );
186
187 $snapshot = array(
188 'date' => (string) $this->format_date( $media_item->post_modified_gmt, $media_item->post_modified ),
189 'URL' => (string) wp_get_attachment_url( $media_item->ID ),
190 'file' => (string) $file_paths['basename'],
191 'extension' => (string) $file_paths['extension'],
192 'mime_type' => (string) $media_item->post_mime_type,
193 'size' => (int) filesize( $current_file ),
194 );
195
196 return (object) $snapshot;
197 }
198
199 /**
200 * Try to remove the temporal file from the given file array.
201 *
202 * @param array $file_array - Array with data about the temporal file.
203 */
204 private function remove_tmp_file( $file_array ) {
205 if ( file_exists( $file_array['tmp_name'] ) ) {
206 wp_delete_file( $file_array['tmp_name'] );
207 }
208 }
209
210 /**
211 * Save the given temporal file in a local folder.
212 *
213 * @param array $file_array - array containing file data.
214 * @param int $media_id - the media id.
215 * @param bool $is_upload - True if `$file_array` derives from an upload in `$_FILES`, false if this is a sideload.
216 * @return array|WP_Error An array with information about the new file saved or a WP_Error is something went wrong.
217 */
218 private function save_temporary_file( $file_array, $media_id, $is_upload ) {
219 $tmp_filename = $file_array['tmp_name'];
220
221 $is_ok = $is_upload ? is_uploaded_file( $tmp_filename ) : file_exists( $tmp_filename );
222 if ( ! $is_ok ) {
223 return new WP_Error( 'invalid_input', 'No media provided in input.' );
224 }
225
226 // add additional mime_types through of the `jetpack_supported_media_sideload_types` filter.
227 $mime_type_static_filter = array(
228 'WPCOM_JSON_API_Edit_Media_v1_2_Endpoint',
229 'get_allowed_mime_types',
230 );
231
232 add_filter( 'jetpack_supported_media_sideload_types', $mime_type_static_filter );
233 if (
234 ! $this->is_file_supported_for_sideloading( $tmp_filename ) &&
235 ! file_is_displayable_image( $tmp_filename )
236 ) {
237 if ( ! $is_upload ) {
238 wp_delete_file( $tmp_filename );
239 }
240 return new WP_Error( 'invalid_input', 'Invalid file type.', 403 );
241 }
242 remove_filter( 'jetpack_supported_media_sideload_types', $mime_type_static_filter );
243
244 // generate a new file name.
245 $tmp_new_filename = Jetpack_Media::generate_new_filename( $media_id, $file_array['name'] );
246
247 // start to create the parameters to move the temporal file.
248 $overrides = array( 'test_form' => false );
249
250 $time = $this->get_time_string_from_guid( $media_id );
251
252 $file_array['name'] = $tmp_new_filename;
253 if ( $is_upload ) {
254 $file = wp_handle_upload( $file_array, $overrides, $time );
255 } else {
256 $file = wp_handle_sideload( $file_array, $overrides, $time );
257 $this->remove_tmp_file( $file_array );
258 }
259
260 if ( isset( $file['error'] ) ) {
261 return new WP_Error( 'upload_error', $file['error'] );
262 }
263
264 return $file;
265 }
266
267 /**
268 * File urls use the post date to generate a folder path.
269 * Post dates can change, so we use the original date used in the guid
270 * url so edits can remain in the same folder. In the following function
271 * we capture a string in the format of `YYYY/MM` from the guid.
272 *
273 * For example with a guid of
274 * "http://test.files.wordpress.com/2016/10/test.png" the resulting string
275 * would be: "2016/10"
276 *
277 * @param int $media_id - the media id.
278 *
279 * @return string
280 */
281 private function get_time_string_from_guid( $media_id ) {
282 // @todo: investigate if we can replace date with gmdate()
283 // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
284 $time = date( 'Y/m', strtotime( current_time( 'mysql' ) ) );
285 $media = get_post( $media_id );
286 if ( $media ) {
287 $pattern = '/\/(\d{4}\/\d{2})\//';
288 preg_match( $pattern, $media->guid, $matches );
289 if ( count( $matches ) > 1 ) {
290 $time = $matches[1];
291 }
292 }
293 return $time;
294 }
295
296 /**
297 * Get the image from a remote url and then save it locally.
298 *
299 * @param int $media_id - media post ID.
300 * @param string $url - image URL to save locally.
301 * @return array|WP_Error An array with information about the new file saved or a WP_Error is something went wrong.
302 */
303 private function build_file_array_from_url( $media_id, $url ) {
304 if ( ! $url ) {
305 return null;
306 }
307
308 // if we didn't get a URL, let's bail.
309 $parsed = wp_parse_url( $url );
310 if ( empty( $parsed ) ) {
311 return new WP_Error( 'invalid_url', 'No media provided in url.' );
312 }
313
314 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
315 $url = wpcom_get_private_file( $url );
316 }
317
318 // save the remote image into a tmp file.
319 $tmp = download_url( $url );
320 if ( is_wp_error( $tmp ) ) {
321 return $tmp;
322 }
323
324 return array(
325 'name' => basename( $url ),
326 'tmp_name' => $tmp,
327 );
328 }
329
330 /**
331 * Add a new item into revision_history array.
332 *
333 * @param object $media_item - media post.
334 * @param array|WP_Error $file - File data, or WP_Error on error.
335 * @param bool $has_original_media - condition is the original media has been already added.
336 * @return bool `true` if the item has been added. Otherwise `false`.
337 */
338 private function register_revision( $media_item, $file, $has_original_media ) {
339 if (
340 is_wp_error( $file ) ||
341 ! $has_original_media
342 ) {
343 return false;
344 }
345
346 add_post_meta( $media_item->ID, Jetpack_Media::WP_REVISION_HISTORY, $this->get_snapshot( $media_item ) );
347 }
348
349 /**
350 * Restore the original media file.
351 *
352 * @param int $media_id - media post ID.
353 * @param object $original_media - orginal media data.
354 * @return array - restore media info.
355 */
356 private function restore_original( $media_id, $original_media ) {
357 $revisions = (array) Jetpack_Media::get_revision_history( $media_id );
358 $revisions = array_filter(
359 $revisions,
360 function ( $revision ) use ( $original_media ) {
361 return $revision->file !== $original_media->file;
362 }
363 );
364 $criteria = array(
365 'from' => 0,
366 'to' => REVISION_HISTORY_MAXIMUM_AMOUNT,
367 );
368
369 Jetpack_Media::remove_items_from_revision_history( $media_id, $criteria, $revisions );
370 $file = get_attached_file( $media_id );
371 $file_parts = pathinfo( $file );
372 $orginal_file = path_join( $file_parts['dirname'], $original_media->file );
373 $restored_media = array(
374 'file' => $orginal_file,
375 'type' => $original_media->mime_type,
376 );
377
378 return $restored_media;
379 }
380
381 /**
382 * API callback.
383 *
384 * @param string $path - the path.
385 * @param int $blog_id - the blog ID.
386 * @param int $media_id - the media ID.
387 */
388 public function callback( $path = '', $blog_id = 0, $media_id = 0 ) {
389 $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
390 if ( is_wp_error( $blog_id ) ) {
391 return $blog_id;
392 }
393
394 $media_item = get_post( $media_id );
395
396 if ( ! $media_item || is_wp_error( $media_item ) ) {
397 return new WP_Error( 'unknown_media', 'Unknown Media', 404 );
398 }
399
400 if ( is_wp_error( $media_item ) ) {
401 return $media_item;
402 }
403
404 if ( ! current_user_can( 'upload_files', $media_id ) ) {
405 return new WP_Error( 'unauthorized', 'User cannot view media', 403 );
406 }
407
408 $input = $this->input( true );
409
410 // Images.
411 $media_file = isset( $input['media'] ) ? (array) $input['media'] : null;
412 $media_url = isset( $input['media_url'] ) ? $input['media_url'] : null;
413 $media_attrs = isset( $input['attrs'] ) ? (array) $input['attrs'] : null;
414
415 if ( isset( $media_url ) || $media_file ) {
416 $user_can_upload_files = current_user_can( 'upload_files' ) || $this->api->is_authorized_with_upload_token();
417
418 if ( ! $user_can_upload_files ) {
419 return new WP_Error( 'unauthorized', 'User cannot upload media.', 403 );
420 }
421
422 $has_original_media = Jetpack_Media::get_original_media( $media_id );
423
424 if ( ! $has_original_media ) {
425 // The first time that the media is updated
426 // the original media is stored into the revision_history.
427 $snapshot = $this->get_snapshot( $media_item );
428 add_post_meta( $media_id, Jetpack_Media::WP_ORIGINAL_MEDIA, $snapshot, true );
429 }
430
431 // save the temporal file locally.
432 $is_upload = (bool) $media_file;
433 $temporal_file = $media_file ? $media_file : $this->build_file_array_from_url( $media_id, $media_url );
434
435 if ( is_wp_error( $temporal_file ) ) {
436 return $temporal_file;
437 }
438
439 // edited media is sent as $media_file and restored media is sent as $media_url
440 $should_restore = isset( $media_url ) && ! isset( $media_file ) && $has_original_media;
441
442 $uploaded_file = $should_restore
443 ? $this->restore_original( $media_id, $has_original_media )
444 : $this->save_temporary_file( $temporal_file, $media_id, $is_upload );
445
446 if ( is_wp_error( $uploaded_file ) ) {
447 return $uploaded_file;
448 }
449
450 // revision_history control.
451 $this->register_revision( $media_item, $uploaded_file, $has_original_media );
452
453 $uploaded_path = $uploaded_file['file'];
454 $udpated_mime_type = $uploaded_file['type'];
455 $was_updated = update_attached_file( $media_id, $uploaded_path );
456
457 if ( $was_updated ) {
458 $new_metadata = wp_generate_attachment_metadata( $media_id, $uploaded_path );
459 wp_update_attachment_metadata( $media_id, $new_metadata );
460
461 // check maximum amount of revision_history.
462 Jetpack_Media::limit_revision_history( $media_id, REVISION_HISTORY_MAXIMUM_AMOUNT );
463
464 wp_update_post(
465 (object) array(
466 'ID' => $media_id,
467 'post_mime_type' => $udpated_mime_type,
468 )
469 );
470 }
471
472 unset( $input['media'] );
473 unset( $input['media_url'] );
474 unset( $input['attrs'] );
475 }
476
477 // update media through of `attrs` value it it's defined.
478 if ( ( $media_file || isset( $media_url ) ) && $media_attrs ) {
479 $was_updated = $this->update_by_attrs_parameter( $media_id, $media_attrs );
480
481 if ( is_wp_error( $was_updated ) ) {
482 return $was_updated;
483 }
484 }
485
486 // call parent method.
487 $response = parent::callback( $path, $blog_id, $media_id );
488
489 // expose `revision_history` object.
490 $response->revision_history = (object) array(
491 'items' => (array) Jetpack_Media::get_revision_history( $media_id ),
492 'original' => (object) Jetpack_Media::get_original_media( $media_id ),
493 );
494
495 return $response;
496 }
497 }
498