1 | <?php |
---|
2 | /** |
---|
3 | * VideoPress Attachment_Handler |
---|
4 | * |
---|
5 | * @package automattic/jetpack-videopress |
---|
6 | */ |
---|
7 | |
---|
8 | namespace Automattic\Jetpack\VideoPress; |
---|
9 | |
---|
10 | use Automattic\Jetpack\Connection\Client; |
---|
11 | use Automattic\Jetpack\Current_Plan; |
---|
12 | |
---|
13 | /** |
---|
14 | * VideoPress Attachment_Handler class. |
---|
15 | */ |
---|
16 | class Attachment_Handler { |
---|
17 | |
---|
18 | /** |
---|
19 | * Initializer |
---|
20 | * |
---|
21 | * This method should be called only once by the Initializer class. Do not call this method again. |
---|
22 | */ |
---|
23 | public static function init() { |
---|
24 | |
---|
25 | if ( ! Status::is_active() ) { |
---|
26 | return; |
---|
27 | } |
---|
28 | |
---|
29 | add_filter( 'wp_get_attachment_url', array( __CLASS__, 'maybe_get_attached_url_for_videopress' ), 10, 2 ); |
---|
30 | add_filter( 'get_attached_file', array( __CLASS__, 'maybe_get_attached_url_for_videopress' ), 10, 2 ); |
---|
31 | |
---|
32 | if ( Current_Plan::supports( 'videopress' ) ) { |
---|
33 | add_filter( 'upload_mimes', array( __CLASS__, 'add_video_upload_mimes' ), 999 ); |
---|
34 | } |
---|
35 | |
---|
36 | add_filter( 'pre_delete_attachment', array( __CLASS__, 'delete_video_wpcom' ), 10, 2 ); |
---|
37 | add_filter( 'wp_mime_type_icon', array( __CLASS__, 'wp_mime_type_icon' ), 10, 3 ); |
---|
38 | add_filter( 'wp_video_extensions', array( __CLASS__, 'add_videopress_extenstion' ) ); |
---|
39 | |
---|
40 | add_filter( 'wp_prepare_attachment_for_js', array( __CLASS__, 'prepare_attachment_for_js' ) ); |
---|
41 | add_filter( 'ajax_query_attachments_args', array( __CLASS__, 'ajax_query_attachments_args' ) ); |
---|
42 | add_action( 'pre_get_posts', array( __CLASS__, 'media_list_table_query' ) ); |
---|
43 | |
---|
44 | add_filter( 'user_has_cap', array( __CLASS__, 'disable_delete_if_disconnected' ), 10, 3 ); |
---|
45 | } |
---|
46 | |
---|
47 | /** |
---|
48 | * Returns the VideoPress URL for the give post id, otherwise returns the provided default. |
---|
49 | * |
---|
50 | * This is an attachment-based filter handler. |
---|
51 | * |
---|
52 | * @param string $default The default return value if post id is not a VideoPress video. |
---|
53 | * @param int $post_id The post id for the current attachment. |
---|
54 | */ |
---|
55 | public static function maybe_get_attached_url_for_videopress( $default, $post_id ) { |
---|
56 | $videopress_url = videopress_get_attachment_url( $post_id ); |
---|
57 | |
---|
58 | if ( null !== $videopress_url ) { |
---|
59 | return $videopress_url; |
---|
60 | } |
---|
61 | |
---|
62 | return $default; |
---|
63 | } |
---|
64 | |
---|
65 | /** |
---|
66 | * Makes sure that all video mimes are added in, as multi site installs can remove them. |
---|
67 | * |
---|
68 | * @param array $existing_mimes Mime types to extend/filter. |
---|
69 | * @return array |
---|
70 | */ |
---|
71 | public static function add_video_upload_mimes( $existing_mimes = array() ) { |
---|
72 | $mime_types = wp_get_mime_types(); |
---|
73 | $video_types = array_filter( $mime_types, array( __CLASS__, 'filter_video_mimes' ) ); |
---|
74 | |
---|
75 | foreach ( $video_types as $key => $value ) { |
---|
76 | $existing_mimes[ $key ] = $value; |
---|
77 | } |
---|
78 | |
---|
79 | // Make sure that videopress mimes are considered videos. |
---|
80 | $existing_mimes['videopress'] = 'video/videopress'; |
---|
81 | |
---|
82 | return $existing_mimes; |
---|
83 | } |
---|
84 | |
---|
85 | /** |
---|
86 | * Filter designed to get rid of non video mime types. |
---|
87 | * |
---|
88 | * @param string $value Mime type to filter. |
---|
89 | * @return int |
---|
90 | */ |
---|
91 | public static function filter_video_mimes( $value ) { |
---|
92 | return preg_match( '@^video/@', $value ); |
---|
93 | } |
---|
94 | |
---|
95 | /** |
---|
96 | * Attempts to delete a VideoPress video from wp.com. |
---|
97 | * Will block the deletion from continuing if certain errors return from the wp.com API. |
---|
98 | * |
---|
99 | * @param Boolean $delete if the deletion should occur or not (unused). |
---|
100 | * @param WP_Post $post the post object. |
---|
101 | * |
---|
102 | * @return null|WP_Error|Boolean null if deletion should continue. |
---|
103 | */ |
---|
104 | public static function delete_video_wpcom( $delete, $post ) { |
---|
105 | if ( ! is_videopress_attachment( $post->ID ) ) { |
---|
106 | return null; |
---|
107 | } |
---|
108 | |
---|
109 | $guid = get_post_meta( $post->ID, 'videopress_guid', true ); |
---|
110 | if ( empty( $guid ) ) { |
---|
111 | self::delete_video_poster_attachment( $post->ID ); |
---|
112 | return null; |
---|
113 | } |
---|
114 | |
---|
115 | // Phone home and have wp.com delete the VideoPress entry and files. |
---|
116 | $wpcom_response = Client::wpcom_json_api_request_as_blog( |
---|
117 | sprintf( '/videos/%s/delete', $guid ), |
---|
118 | '1.1', |
---|
119 | array( 'method' => 'POST' ) |
---|
120 | ); |
---|
121 | |
---|
122 | if ( is_wp_error( $wpcom_response ) ) { |
---|
123 | return $wpcom_response; |
---|
124 | } |
---|
125 | |
---|
126 | // Upon success or a 404 (video already deleted on wp.com), return null to allow the deletion to continue. |
---|
127 | if ( 200 === $wpcom_response['response']['code'] || 404 === $wpcom_response['response']['code'] ) { |
---|
128 | self::delete_video_poster_attachment( $post->ID ); |
---|
129 | return null; |
---|
130 | } |
---|
131 | |
---|
132 | // Otherwise we stop the deletion from proceeding. |
---|
133 | return false; |
---|
134 | } |
---|
135 | |
---|
136 | /** |
---|
137 | * Deletes a video poster attachment if it exists. |
---|
138 | * |
---|
139 | * @param int $attachment_id the WP attachment id. |
---|
140 | */ |
---|
141 | private static function delete_video_poster_attachment( $attachment_id ) { |
---|
142 | $thumbnail_id = get_post_meta( $attachment_id, '_thumbnail_id', true ); |
---|
143 | if ( ! empty( $thumbnail_id ) ) { |
---|
144 | // Let's ensure this is a VP poster image before we delete it. |
---|
145 | if ( '1' === get_post_meta( $thumbnail_id, 'videopress_poster_image', true ) ) { |
---|
146 | // This call triggers the `delete_video_wpcom` filter again but it bails early at the is_videopress_attachment() check. |
---|
147 | wp_delete_attachment( $thumbnail_id ); |
---|
148 | } |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | /** |
---|
153 | * Filter the mime type icon. |
---|
154 | * |
---|
155 | * @param string $icon Icon path. |
---|
156 | * @param string $mime Mime type. |
---|
157 | * @param int $post_id Post ID. |
---|
158 | * |
---|
159 | * @return string |
---|
160 | */ |
---|
161 | public static function wp_mime_type_icon( $icon, $mime, $post_id ) { |
---|
162 | |
---|
163 | if ( $mime !== 'video/videopress' ) { |
---|
164 | return $icon; |
---|
165 | } |
---|
166 | |
---|
167 | $status = get_post_meta( $post_id, 'videopress_status', true ); |
---|
168 | |
---|
169 | if ( $status === 'complete' ) { |
---|
170 | return $icon; |
---|
171 | } |
---|
172 | |
---|
173 | return 'https://wordpress.com/wp-content/mu-plugins/videopress/images/media-video-processing-icon.png'; |
---|
174 | } |
---|
175 | |
---|
176 | /** |
---|
177 | * Filter the list of supported video formats. |
---|
178 | * |
---|
179 | * @param array $extensions Supported video formats. |
---|
180 | * |
---|
181 | * @return array |
---|
182 | */ |
---|
183 | public static function add_videopress_extenstion( $extensions ) { |
---|
184 | $extensions[] = 'videopress'; |
---|
185 | return $extensions; |
---|
186 | } |
---|
187 | |
---|
188 | /** |
---|
189 | * Make sure that any Video that has a VideoPress GUID passes that data back. |
---|
190 | * |
---|
191 | * @param WP_Post $post Attachment object. |
---|
192 | */ |
---|
193 | public static function prepare_attachment_for_js( $post ) { |
---|
194 | if ( 'video' === $post['type'] ) { |
---|
195 | $guid = get_post_meta( $post['id'], 'videopress_guid' ); |
---|
196 | if ( $guid ) { |
---|
197 | $post['videopress_guid'] = $guid; |
---|
198 | } |
---|
199 | } |
---|
200 | return $post; |
---|
201 | } |
---|
202 | |
---|
203 | /** |
---|
204 | * Media Grid: |
---|
205 | * Filter out any videopress video posters that we've downloaded, |
---|
206 | * so that they don't seem to display twice. |
---|
207 | * |
---|
208 | * @param array $args Query variables. |
---|
209 | */ |
---|
210 | public static function ajax_query_attachments_args( $args ) { |
---|
211 | $meta_query = array( |
---|
212 | array( |
---|
213 | 'key' => 'videopress_poster_image', |
---|
214 | 'compare' => 'NOT EXISTS', |
---|
215 | ), |
---|
216 | ); |
---|
217 | |
---|
218 | // If there was already a meta query, let's AND it via |
---|
219 | // nesting it with our new one. No need to specify the |
---|
220 | // relation, as it defaults to AND. |
---|
221 | if ( ! empty( $args['meta_query'] ) ) { |
---|
222 | $meta_query[] = $args['meta_query']; |
---|
223 | } |
---|
224 | $args['meta_query'] = $meta_query; |
---|
225 | |
---|
226 | return $args; |
---|
227 | } |
---|
228 | |
---|
229 | /** |
---|
230 | * Media List: |
---|
231 | * Do the same as `videopress_ajax_query_attachments_args()` but for the list view. |
---|
232 | * |
---|
233 | * @param array $query WP_Query instance. |
---|
234 | */ |
---|
235 | public static function media_list_table_query( $query ) { |
---|
236 | |
---|
237 | if ( |
---|
238 | ! function_exists( 'get_current_screen' ) |
---|
239 | || get_current_screen() === null |
---|
240 | ) { |
---|
241 | return; |
---|
242 | } |
---|
243 | |
---|
244 | if ( is_admin() && $query->is_main_query() && ( 'upload' === get_current_screen()->id ) ) { |
---|
245 | $meta_query = array( |
---|
246 | array( |
---|
247 | 'key' => 'videopress_poster_image', |
---|
248 | 'compare' => 'NOT EXISTS', |
---|
249 | ), |
---|
250 | ); |
---|
251 | |
---|
252 | $old_meta_query = $query->get( 'meta_query' ); |
---|
253 | if ( $old_meta_query ) { |
---|
254 | $meta_query[] = $old_meta_query; |
---|
255 | } |
---|
256 | |
---|
257 | $query->set( 'meta_query', $meta_query ); |
---|
258 | } |
---|
259 | } |
---|
260 | |
---|
261 | /** |
---|
262 | * Filter to disable the `delete_post` capability |
---|
263 | * for VideoPress attachments if the current user is |
---|
264 | * not connected. |
---|
265 | * |
---|
266 | * @param array $allcaps All the capabilities of the user. |
---|
267 | * @param array $cap [0] Required capability. |
---|
268 | * @param array $args [0] Requested capability. |
---|
269 | * [1] User ID. |
---|
270 | * [2] Associated object ID. |
---|
271 | * @return array the filtered array of capabilities. |
---|
272 | */ |
---|
273 | public static function disable_delete_if_disconnected( $allcaps, $cap, $args ) { |
---|
274 | |
---|
275 | // Only apply this filter to `delete_post` checks |
---|
276 | if ( 'delete_post' !== $args[0] ) { |
---|
277 | return $allcaps; |
---|
278 | } |
---|
279 | |
---|
280 | // Only apply this filter to VideoPress attachments |
---|
281 | if ( ! is_videopress_attachment( $args[2] ) ) { |
---|
282 | return $allcaps; |
---|
283 | } |
---|
284 | |
---|
285 | // Set the capability to false if the user can't perform the actions |
---|
286 | if ( ! Data::can_perform_action() ) { |
---|
287 | $allcaps[ $cap[0] ] = false; |
---|
288 | } |
---|
289 | |
---|
290 | return $allcaps; |
---|
291 | } |
---|
292 | } |
---|