PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / team-updraft / lib-central / central / modules / media.php

media.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/team-updraft/lib-central/central/modules/media.php

602 lines 19.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
4
5 /**
6 * Handles Media Commands
7 */
8 class UpdraftCentral_Media_Commands extends UpdraftCentral_Commands {
9
10 private $switched = false;
11
12 /**
13 * Function that gets called before every action
14 *
15 * @param string $command a string that corresponds to UDC command to call a certain method for this class.
16 * @param array $data an array of data post or get fields
17 * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
18 *
19 * link to udrpc_action main function in class UpdraftCentral_Listener
20 */
21 public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
22 // Here we assign the current blog_id to a variable $blog_id
23 $blog_id = get_current_blog_id();
24 if (!empty($data['site_id'])) $blog_id = $data['site_id'];
25
26 if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
27 $this->switched = switch_to_blog($blog_id);
28 }
29 }
30
31 /**
32 * Function that gets called after every action
33 *
34 * @param string $command a string that corresponds to UDC command to call a certain method for this class.
35 * @param array $data an array of data post or get fields
36 * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
37 *
38 * link to udrpc_action main function in class UpdraftCentral_Listener
39 */
40 public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
41 // Here, we're restoring to the current (default) blog before we switched
42 if ($this->switched) restore_current_blog();
43 }
44
45 /**
46 * Fetch and retrieves posts based from the submitted parameters
47 *
48 * @param array $params Containing all the needed information to filter the results of the current request
49 * @return array
50 */
51 public function get_media_items($params) {
52 $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
53 if (!empty($error)) return $error;
54
55 // check paged parameter; if empty set to defaults
56 $paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
57 $numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
58 $offset = ($paged - 1) * $numberposts;
59
60 $args = array(
61 'posts_per_page' => $numberposts,
62 'paged' => $paged,
63 'offset' => $offset,
64 'post_type' => 'attachment',
65 'post_status' => 'inherit',
66 );
67
68 if (!empty($params['keyword'])) {
69 $args['s'] = $params['keyword'];
70 }
71
72 if (!empty($params['category'])) {
73 if (in_array($params['category'], array('detached', 'unattached'))) {
74 $attachment_ids = $this->get_unattached_ids();
75 } else {
76 $attachment_ids = $this->get_type_ids($params['category']);
77 }
78
79 $args['post__in'] = $attachment_ids;
80 }
81
82 if (!empty($params['date'])) {
83 list($monthnum, $year) = explode(':', $params['date']);
84
85 $args['monthnum'] = $monthnum;
86 $args['year'] = $year;
87 }
88
89 $query = new WP_Query($args);
90 $result = $query->posts;
91
92 $count_posts = (int) $query->found_posts;
93 $page_count = 0;
94
95 if ($count_posts > 0) {
96 $page_count = absint($count_posts / $numberposts);
97 $remainder = absint($count_posts % $numberposts);
98 $page_count = ($remainder > 0) ? ++$page_count : $page_count;
99 }
100
101 $info = array(
102 'page' => $paged,
103 'pages' => $page_count,
104 'results' => $count_posts,
105 'items_from' => (($paged * $numberposts) - $numberposts) + 1,
106 'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
107 );
108
109 $media_items = array();
110 if (!empty($result)) {
111 foreach ($result as $item) {
112 $media = $this->get_media_item($item, null, true);
113 if (!empty($media)) {
114 array_push($media_items, $media);
115 }
116 }
117 }
118
119 $response = array(
120 'items' => $media_items,
121 'info' => $info,
122 'options' => array(
123 'date' => $this->get_date_options(),
124 'type' => $this->get_type_options()
125 )
126 );
127
128 return $this->_response($response);
129 }
130
131 /**
132 * Check whether we have an image editor (e.g. GD, Imagick, etc.) set in place to handle the basic editing
133 * functions such as rotate, crop, etc. If not, then we hide that feature in UpdraftCentral
134 *
135 * @param object $media The media item/object to check
136 * @return boolean
137 */
138 private function has_image_editor($media) {
139 // Most of the time image library are enabled by default in the php.ini but there's a possbility that users don't
140 // enable them as they have no need for them at the moment or for some other reasons. Thus, we need to confirm
141 // that here through the wp_get_image_editor method.
142 $has_image_editor = true;
143 if (!empty($media)) {
144 if (!function_exists('wp_get_image_editor')) {
145 require_once(ABSPATH.'wp-includes/media.php');
146 }
147
148 if (!function_exists('_load_image_to_edit_path')) {
149 require_once(ABSPATH.'wp-admin/includes/image.php');
150 }
151
152 $image_editor = wp_get_image_editor(_load_image_to_edit_path($media->ID));
153 if (is_wp_error($image_editor)) {
154 $has_image_editor = false;
155 }
156 }
157
158 return $has_image_editor;
159 }
160
161 /**
162 * Fetch a single media item information
163 *
164 * @param array $params Containing all the needed information to filter the results of the current request
165 * @param array|null $extra_info Additional information from the current request
166 * @param boolean $raw If set, returns the result of the fetch process unwrapped by the response array
167 * @return array
168 */
169 public function get_media_item($params, $extra_info = null, $raw = false) {
170 $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
171 if (!empty($error)) return $error;
172
173 // Raw means that we need to return the result without wrapping it
174 // with the "$this->_response" function which indicates that the call
175 // was done locally (within the class) and not directly from UpdraftCentral.
176 if ($raw && is_object($params) && isset($params->ID)) {
177 $media = $params;
178 } elseif (is_array($params) && !empty($params['id'])) {
179 $media = get_post($params['id']);
180 }
181
182 if (!function_exists('get_post_mime_types')) {
183 global $updraftcentral_main;
184
185 // For a much later version of WP the "get_post_mime_types" is located
186 // in a different folder. So, we make sure that we have it loaded before
187 // actually using it.
188 if (version_compare($updraftcentral_main->get_wordpress_version(), '3.5', '>=')) {
189 require_once(ABSPATH.WPINC.'/post.php');
190 } else {
191 // For WP 3.4, the "get_post_mime_types" is located in the location provided below.
192 require_once(ABSPATH.'wp-admin/includes/post.php');
193 }
194 }
195
196 if (!function_exists('wp_image_editor')) {
197 require_once(ABSPATH.'wp-admin/includes/image-edit.php');
198 }
199
200 if (!function_exists('get_media_item')) {
201 require_once(ABSPATH.'wp-admin/includes/template.php');
202 require_once(ABSPATH.'wp-admin/includes/media.php');
203 }
204
205
206 if ($media) {
207 $thumb = wp_get_attachment_image_src($media->ID, 'thumbnail', true);
208 if (!empty($thumb)) $media->thumb_url = $thumb[0];
209
210 $media->url = wp_get_attachment_url($media->ID);
211 $media->parent_post_title = get_the_title($media->post_parent);
212 $media->author = get_the_author_meta('display_name', $media->post_author);
213 $media->filename = basename($media->url);
214 $media->date = date('Y/m/d', strtotime($media->post_date));
215 $media->upload_date = mysql2date(get_option('date_format'), $media->post_date);
216
217 $media->filesize = 0;
218 $file = get_attached_file($media->ID);
219 if (!empty($file) && file_exists($file)) {
220 $media->filesize = size_format(filesize($file));
221 }
222
223 $media->nonce = wp_create_nonce('image_editor-'.$media->ID);
224 if (false !== strpos($media->post_mime_type, 'image/')) {
225 $meta = wp_get_attachment_metadata($media->ID);
226
227 $thumb = image_get_intermediate_size($media->ID, 'thumbnail');
228 $sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
229
230 // Pulling details
231 $sizer = 1;
232 if (isset($meta['width'], $meta['height'])) {
233 $big = max($meta['width'], $meta['height']);
234 $sizer = $big > 400 ? 400 / $big : 1;
235 }
236
237 $constrained_dims = array();
238 if ($thumb && $sub_sizes) {
239 $constrained_dims = wp_constrain_dimensions($thumb['width'], $thumb['height'], 160, 120);
240 }
241
242 $rotate_supported = false;
243 if (function_exists('imagerotate') || wp_image_editor_supports(array('mime_type' => get_post_mime_type($media->ID), 'methods' => array('rotate')))) {
244 $rotate_supported = true;
245 }
246
247 // Check for alternative text if present
248 $alt = get_post_meta($media->ID, '_wp_attachment_image_alt', true);
249 $media->alt = !empty($alt) ? $alt : '';
250
251 // Check whether edited images are restorable
252 $backup_sizes = get_post_meta($media->ID, '_wp_attachment_backup_sizes', true);
253 $can_restore = !empty($backup_sizes) && isset($backup_sizes['full-orig']) && basename($meta['file']) != $backup_sizes['full-orig']['file'];
254
255 $image_edit_overwrite = (!defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE) ? 0 : 1;
256 $media->misc = array(
257 'sizer' => $sizer,
258 'rand' => rand(1, 99999),
259 'constrained_dims' => $constrained_dims,
260 'rotate_supported' => (int) $rotate_supported,
261 'thumb' => $thumb,
262 'meta' => $meta,
263 'alt_text' => $alt,
264 'can_restore' => $can_restore,
265 'image_edit_overwrite' => $image_edit_overwrite
266 );
267
268 $media->has_image_editor = $this->has_image_editor($media);
269 }
270 }
271
272 return $raw ? $media : $this->_response(array('item' => $media));
273 }
274
275 /**
276 * Fetch and retrieves posts based from the submitted parameters
277 *
278 * @param array $params Containing all the needed information to filter the results of the current request
279 * @return array
280 */
281 public function get_posts($params) {
282 $error = $this->_validate_capabilities(array('edit_posts'));
283 if (!empty($error)) return $error;
284
285 // check paged parameter; if empty set to defaults
286 $paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
287 $numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
288 $offset = ($paged - 1) * $numberposts;
289
290 $args = array(
291 'posts_per_page' => $numberposts,
292 'paged' => $paged,
293 'offset' => $offset,
294 'post_type' => 'post',
295 'post_status' => 'publish,private,draft,pending,future',
296 );
297
298 if (!empty($params['keyword'])) {
299 $args['s'] = $params['keyword'];
300 }
301
302 $query = new WP_Query($args);
303 $result = $query->posts;
304
305 $count_posts = (int) $query->found_posts;
306 $page_count = 0;
307
308 if ($count_posts > 0) {
309 $page_count = absint($count_posts / $numberposts);
310 $remainder = absint($count_posts % $numberposts);
311 $page_count = ($remainder > 0) ? ++$page_count : $page_count;
312 }
313
314 $info = array(
315 'page' => $paged,
316 'pages' => $page_count,
317 'results' => $count_posts,
318 'items_from' => (($paged * $numberposts) - $numberposts) + 1,
319 'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
320 );
321
322 $posts = array();
323 if (!empty($result)) {
324 foreach ($result as $post) {
325 array_push($posts, array('ID' => $post->ID, 'title' => $post->post_title));
326 }
327 }
328
329 $response = array(
330 'posts' => $posts,
331 'info' => $info
332 );
333 return $this->_response($response);
334 }
335
336 /**
337 * Saves media changes from UpdraftCentral
338 *
339 * @param array $params Containing all the needed information to filter the results of the current request
340 * @return array
341 */
342 public function save_media_item($params) {
343 $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
344 if (!empty($error)) return $error;
345
346 $args = array(
347 'post_title' => $params['image_title'],
348 'post_excerpt' => $params['image_caption'],
349 'post_content' => $params['image_description']
350 );
351
352 if (!empty($params['new'])) {
353 $args['post_type'] = 'attachment';
354 $media_id = wp_insert_post($args, true);
355 } else {
356 $args['ID'] = $params['id'];
357 $args['post_modified'] = date('Y-m-d H:i:s');
358 $args['post_modified_gmt'] = gmdate('Y-m-d H:i:s');
359
360 $media_id = wp_update_post($args, true);
361 }
362
363 if (!empty($media_id)) {
364 // Update alternative text if not empty
365 if (!empty($params['image_alternative_text'])) {
366 update_post_meta($media_id, '_wp_attachment_image_alt', $params['image_alternative_text']);
367 }
368
369 $result = array(
370 'status' => 'success',
371 'item' => $this->get_media_item(array('id' => $media_id), null, true)
372 );
373 } else {
374 $result = array('status' => 'failed');
375 }
376
377 return $this->_response($result);
378 }
379
380 /**
381 * Executes media action (e.g. attach, detach and delete)
382 *
383 * @param array $params Containing all the needed information to filter the results of the current request
384 * @return array
385 */
386 public function execute_media_action($params) {
387 global $updraftcentral_host_plugin;
388
389 $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
390 if (!empty($error)) return $error;
391
392 $result = array();
393 switch ($params['do']) {
394 case 'attach':
395 global $wpdb;
396 $query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = %d WHERE `post_type` = 'attachment' AND ID = %d", $params['parent_id'], $params['id']));
397
398 if (false === $query_result) {
399 $result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_attach_media');
400 } else {
401 $result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('media_attached');
402 }
403 break;
404 case 'detach':
405 global $wpdb;
406 $query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = 0 WHERE `post_type` = 'attachment' AND ID = %d", $params['id']));
407
408 if (false === $query_result) {
409 $result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_detach_media');
410 } else {
411 $result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('media_detached');
412 }
413 break;
414 case 'delete':
415 $failed_items = array();
416 foreach ($params['ids'] as $id) {
417 // Delete permanently
418 if (false === wp_delete_attachment($id, true)) {
419 $failed_items[] = $id;
420 }
421 }
422
423 if (!empty($failed_items)) {
424 $result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_delete_media');
425 $result['items'] = $failed_items;
426 } else {
427 $result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('selected_media_deleted');
428 }
429 break;
430 default:
431 break;
432 }
433
434 return $this->_response($result);
435 }
436
437 /**
438 * Retrieves a collection of formatted dates found for the given post statuses.
439 * It will be used as options for the date filter when managing the media items in UpdraftCentral.
440 *
441 * @return array
442 */
443 private function get_date_options() {
444 global $wpdb;
445 $options = array();
446
447 $date_options = $wpdb->get_col("SELECT DATE_FORMAT(`post_date`, '%M %Y') as `formatted_post_date` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `formatted_post_date` ORDER BY `post_date` DESC");
448
449 if (!empty($date_options)) {
450 foreach ($date_options as $monthyear) {
451 $timestr = strtotime($monthyear);
452 $options[] = array('label' => date('F Y', $timestr), 'value' => date('n:Y', $timestr));
453 }
454 }
455
456 return $options;
457 }
458
459 /**
460 * Retrieves mime types that will be use as filter option in UpdraftCentral
461 *
462 * @return array
463 */
464 private function get_type_options() {
465 global $wpdb, $updraftcentral_host_plugin, $updraftcentral_main;
466
467 $options = array();
468 if (!function_exists('get_post_mime_types')) {
469 // For a much later version of WP the "get_post_mime_types" is located
470 // in a different folder. So, we make sure that we have it loaded before
471 // actually using it.
472 if (version_compare($updraftcentral_main->get_wordpress_version(), '3.5', '>=')) {
473 require_once(ABSPATH.WPINC.'/post.php');
474 } else {
475 // For WP 3.4, the "get_post_mime_types" is located in the location provided below.
476 require_once(ABSPATH.'wp-admin/includes/post.php');
477 }
478 }
479
480 $post_mime_types = get_post_mime_types();
481 $type_options = $wpdb->get_col("SELECT `post_mime_type` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `post_mime_type` ORDER BY `post_mime_type` DESC");
482
483 foreach ($post_mime_types as $mime_type => $label) {
484 if (!wp_match_mime_types($mime_type, $type_options)) continue;
485 $options[] = array('label' => $label[0], 'value' => esc_attr($mime_type));
486 }
487
488 $options[] = array('label' => $updraftcentral_host_plugin->retrieve_show_message('unattached'), 'value' => 'detached');
489 return $options;
490 }
491
492 /**
493 * Retrieves media items that haven't been attached to any posts
494 *
495 * @return array
496 */
497 private function get_unattached_ids() {
498 global $wpdb;
499 return $wpdb->get_col("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_parent` = '0'");
500 }
501
502 /**
503 * Retrieves IDs of media items that has the given mime type
504 *
505 * @param string $type The mime type to search for
506 * @return array
507 */
508 private function get_type_ids($type) {
509 global $wpdb;
510 return $wpdb->get_col($wpdb->prepare("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_mime_type` LIKE %s", $type.'/%'));
511 }
512
513 /**
514 * Checks whether we have the required fields submitted and the user has
515 * the capabilities to execute the requested action
516 *
517 * @param array $capabilities The capabilities to check and validate
518 *
519 * @return array|void
520 */
521 private function _validate_capabilities($capabilities) {
522 foreach ($capabilities as $capability) {
523 if (!current_user_can($capability)) {
524 return $this->_generic_error_response('insufficient_permission');
525 }
526 }
527 }
528
529 /**
530 * Populates the $_REQUEST global variable with the submitted data
531 *
532 * @param array $params Submitted data received from UpdraftCentral
533 * @return array
534 */
535 private function populate_request($params) {
536 if (!empty($params)) {
537 foreach ($params as $key => $value) {
538 $_REQUEST[$key] = $value;
539 }
540 }
541 }
542
543 /**
544 * Handles image editing requests coming from UpdraftCentral
545 *
546 * @param array $params Containing all the needed information to filter the results of the current request
547 * @return array
548 */
549 public function image_editor($params) {
550 $error = $this->_validate_capabilities(array('edit_posts'));
551 if (!empty($error)) return $error;
552
553 $attachment_id = (int) $params['postid'];
554 $this->populate_request($params);
555
556 if (!function_exists('load_image_to_edit')) {
557 require_once(ABSPATH.'wp-admin/includes/image.php');
558 }
559
560 include_once(ABSPATH.'wp-admin/includes/image-edit.php');
561 $msg = false;
562 switch ($params['do']) {
563 case 'save':
564 case 'scale':
565 $msg = wp_save_image($attachment_id);
566 break;
567 case 'restore':
568 $msg = wp_restore_image($attachment_id);
569 break;
570 }
571
572 $msg = (false !== $msg) ? json_encode($msg) : $msg;
573 return $this->_response(array('content' => $msg));
574 }
575
576 /**
577 * Handles image preview requests coming from UpdraftCentral
578 *
579 * @param array $params Containing all the needed information to filter the results of the current request
580 * @return array
581 */
582 public function image_preview($params) {
583 $error = $this->_validate_capabilities(array('edit_posts'));
584 if (!empty($error)) return $error;
585
586 if (!function_exists('load_image_to_edit')) {
587 require_once(ABSPATH.'wp-admin/includes/image.php');
588 }
589
590 include_once(ABSPATH.'wp-admin/includes/image-edit.php');
591 $this->populate_request($params);
592 $post_id = (int) $params['postid'];
593
594 ob_start();
595 stream_preview_image($post_id);
596 $content = ob_get_contents();
597 ob_end_clean();
598
599 return $this->_response(array('content' => base64_encode($content)));
600 }
601 }
602