PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.21
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.21
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 / central / modules / media.php

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

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