config
10 years ago
languages
10 years ago
scripts
10 years ago
styles
10 years ago
views
10 years ago
cacert.pem
11 years ago
class-tiny-compress-curl.php
10 years ago
class-tiny-compress-fopen.php
10 years ago
class-tiny-compress.php
10 years ago
class-tiny-exception.php
11 years ago
class-tiny-metadata.php
10 years ago
class-tiny-notices.php
11 years ago
class-tiny-php.php
11 years ago
class-tiny-plugin.php
10 years ago
class-tiny-settings.php
10 years ago
class-tiny-wp-base.php
10 years ago
class-tiny-plugin.php
289 lines
| 1 | <?php |
| 2 | /* |
| 3 | * Tiny Compress Images - WordPress plugin. |
| 4 | * Copyright (C) 2015 Voormedia B.V. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the Free |
| 8 | * Software Foundation; either version 2 of the License, or (at your option) |
| 9 | * any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 14 | * more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License along |
| 17 | * with this program; if not, write to the Free Software Foundation, Inc., 51 |
| 18 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 19 | */ |
| 20 | |
| 21 | class Tiny_Plugin extends Tiny_WP_Base { |
| 22 | const MEDIA_COLUMN = self::NAME; |
| 23 | const MEDIA_COLUMN_HEADER = 'Compression'; |
| 24 | const DATETIME_FORMAT = 'Y-m-d G:i:s'; |
| 25 | |
| 26 | private $settings; |
| 27 | private $twig; |
| 28 | |
| 29 | public static function jpeg_quality() { |
| 30 | return 95; |
| 31 | } |
| 32 | |
| 33 | public function __construct() { |
| 34 | parent::__construct(); |
| 35 | |
| 36 | $this->settings = new Tiny_Settings(); |
| 37 | if (is_admin()) { |
| 38 | add_action('admin_menu', $this->get_method('admin_menu')); |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | public function set_compressor($compressor) { |
| 43 | $this->settings->set_compressor($compressor); |
| 44 | } |
| 45 | |
| 46 | public function init() { |
| 47 | add_filter('jpeg_quality', $this->get_static_method('jpeg_quality')); |
| 48 | add_filter('wp_editor_set_quality', $this->get_static_method('jpeg_quality')); |
| 49 | add_filter('wp_generate_attachment_metadata', $this->get_method('compress_attachment'), 10, 2); |
| 50 | load_plugin_textdomain(self::NAME, false, dirname(plugin_basename(__FILE__)) . '/languages'); |
| 51 | } |
| 52 | |
| 53 | public function admin_init() { |
| 54 | add_filter('manage_media_columns', $this->get_method('add_media_columns')); |
| 55 | add_action('manage_media_custom_column', $this->get_method('render_media_column'), 10, 2); |
| 56 | add_action('wp_ajax_tiny_compress_image', $this->get_method('compress_image')); |
| 57 | add_action('admin_action_tiny_bulk_compress', $this->get_method('bulk_compress')); |
| 58 | add_action('admin_enqueue_scripts', $this->get_method('enqueue_scripts')); |
| 59 | $plugin = plugin_basename(dirname(dirname(__FILE__)) . '/tiny-compress-images.php'); |
| 60 | add_filter("plugin_action_links_$plugin", $this->get_method('add_plugin_links')); |
| 61 | add_thickbox(); |
| 62 | } |
| 63 | |
| 64 | public function admin_menu() { |
| 65 | add_media_page( |
| 66 | self::translate('Compress JPEG & PNG Images'), self::translate('Compress All Images'), |
| 67 | 'upload_files', 'tiny-bulk-compress', $this->get_method('bulk_compress_page') |
| 68 | ); |
| 69 | } |
| 70 | |
| 71 | public function add_plugin_links($current_links) { |
| 72 | $additional[] = sprintf('<a href="options-media.php#%s">%s</a>', self::NAME, |
| 73 | self::translate_escape('Settings')); |
| 74 | return array_merge($additional, $current_links); |
| 75 | } |
| 76 | |
| 77 | public function enqueue_scripts($hook) { |
| 78 | wp_enqueue_style(self::NAME .'_admin', plugins_url('/styles/admin.css', __FILE__), |
| 79 | array(), self::plugin_version()); |
| 80 | |
| 81 | $handle = self::NAME .'_admin'; |
| 82 | wp_register_script($handle, plugins_url('/scripts/admin.js', __FILE__), |
| 83 | array(), self::plugin_version(), true); |
| 84 | |
| 85 | // WordPress < 3.3 does not handle multidimensional arrays |
| 86 | wp_localize_script($handle, 'tinyCompress', array( |
| 87 | 'nonce' => wp_create_nonce('tiny-compress'), |
| 88 | 'wpVersion' => self::wp_version(), |
| 89 | 'pluginVersion' => self::plugin_version(), |
| 90 | 'L10nAllDone' => self::translate('All images are processed'), |
| 91 | 'L10nBulkAction' => self::translate('Compress Images'), |
| 92 | 'L10nCompressing' => self::translate('Compressing'), |
| 93 | 'L10nCompressions' => self::translate('compressions'), |
| 94 | 'L10nError' => self::translate('Error'), |
| 95 | 'L10nInternalError' => self::translate('Internal error'), |
| 96 | 'L10nOutOf' => self::translate('out of'), |
| 97 | 'L10nWaiting' => self::translate('Waiting'), |
| 98 | )); |
| 99 | wp_enqueue_script($handle); |
| 100 | } |
| 101 | |
| 102 | private function compress($metadata, $attachment_id) { |
| 103 | $mime_type = get_post_mime_type($attachment_id); |
| 104 | $tiny_metadata = new Tiny_Metadata($attachment_id, $metadata); |
| 105 | |
| 106 | if ($this->settings->get_compressor() === null || strpos($mime_type, 'image/') !== 0) { |
| 107 | return array($tiny_metadata, null); |
| 108 | } |
| 109 | |
| 110 | $success = 0; |
| 111 | $failed = 0; |
| 112 | |
| 113 | $compressor = $this->settings->get_compressor(); |
| 114 | $active_tinify_sizes = $this->settings->get_active_tinify_sizes(); |
| 115 | $uncompressed_sizes = $tiny_metadata->get_uncompressed_sizes($active_tinify_sizes); |
| 116 | |
| 117 | foreach ($uncompressed_sizes as $uncompressed_size) { |
| 118 | try { |
| 119 | $tiny_metadata->add_request($uncompressed_size); |
| 120 | $tiny_metadata->update(); |
| 121 | |
| 122 | $resize = $tiny_metadata->is_resizable($uncompressed_size) ? $this->settings->get_resize_options() : false; |
| 123 | $response = $compressor->compress_file($tiny_metadata->get_filename($uncompressed_size), $resize); |
| 124 | |
| 125 | $tiny_metadata->add_response($response, $uncompressed_size); |
| 126 | $tiny_metadata->update(); |
| 127 | $success++; |
| 128 | } catch (Tiny_Exception $e) { |
| 129 | $tiny_metadata->add_exception($e, $uncompressed_size); |
| 130 | $tiny_metadata->update(); |
| 131 | $failed++; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | return array($tiny_metadata, array('success' => $success, 'failed' => $failed)); |
| 136 | } |
| 137 | |
| 138 | public function compress_attachment($metadata, $attachment_id) { |
| 139 | if (!empty($metadata)) { |
| 140 | list($tiny_metadata, $result) = $this->compress($metadata, $attachment_id); |
| 141 | return $tiny_metadata->update_wp_metadata($metadata); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | public function compress_image() { |
| 146 | if (!$this->check_ajax_referer()) { |
| 147 | exit(); |
| 148 | } |
| 149 | $json = !empty($_POST['json']) && $_POST['json']; |
| 150 | if (!current_user_can('upload_files')) { |
| 151 | $message = self::translate("You don't have permission to work with uploaded files") . '.'; |
| 152 | echo $json ? json_encode(array('error' => $message)) : $message; |
| 153 | exit(); |
| 154 | } |
| 155 | if (empty($_POST['id'])) { |
| 156 | $message = self::translate("Not a valid media file") . '.'; |
| 157 | echo $json ? json_encode(array('error' => $message)) : $message; |
| 158 | exit(); |
| 159 | } |
| 160 | $id = intval($_POST['id']); |
| 161 | $metadata = wp_get_attachment_metadata($id); |
| 162 | if (!is_array($metadata)) { |
| 163 | $message = self::translate("Could not find metadata of media file") . '.'; |
| 164 | echo $json ? json_encode(array('error' => $message)) : $message; |
| 165 | exit; |
| 166 | } |
| 167 | |
| 168 | list($tiny_metadata, $result) = $this->compress($metadata, $id); |
| 169 | wp_update_attachment_metadata($id, $tiny_metadata->update_wp_metadata($metadata)); |
| 170 | |
| 171 | if ($json) { |
| 172 | $result['message'] = $tiny_metadata->get_latest_error(); |
| 173 | $result['status'] = $this->settings->get_status(); |
| 174 | $result['thumbnail'] = $tiny_metadata->get_url('thumbnail'); |
| 175 | echo json_encode($result); |
| 176 | } else { |
| 177 | echo $this->render_compress_details($tiny_metadata); |
| 178 | } |
| 179 | |
| 180 | exit(); |
| 181 | } |
| 182 | |
| 183 | public function bulk_compress() { |
| 184 | check_admin_referer('bulk-media'); |
| 185 | |
| 186 | if (empty($_REQUEST['media']) || !is_array( $_REQUEST['media'])) { |
| 187 | return; |
| 188 | } |
| 189 | |
| 190 | $ids = implode('-', array_map('intval', $_REQUEST['media'])); |
| 191 | wp_redirect(add_query_arg( |
| 192 | '_wpnonce', |
| 193 | wp_create_nonce('tiny-bulk-compress'), |
| 194 | admin_url("upload.php?page=tiny-bulk-compress&ids=$ids") |
| 195 | )); |
| 196 | exit(); |
| 197 | } |
| 198 | |
| 199 | public function add_media_columns($columns) { |
| 200 | $columns[self::MEDIA_COLUMN] = self::translate(self::MEDIA_COLUMN_HEADER); |
| 201 | return $columns; |
| 202 | } |
| 203 | |
| 204 | public function render_media_column($column, $id) { |
| 205 | if ($column === self::MEDIA_COLUMN) { |
| 206 | $this->render_compress_details(new Tiny_Metadata($id)); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | private function render_compress_details($tiny_metadata) { |
| 211 | $active = $this->settings->get_active_tinify_sizes(); |
| 212 | $uncompressed = $tiny_metadata->get_uncompressed_sizes($active); |
| 213 | $not_compressed_active = count($tiny_metadata->get_not_compressed_active_sizes($active)); |
| 214 | $savings = $tiny_metadata->get_savings(); |
| 215 | $error = $tiny_metadata->get_latest_error(); |
| 216 | $missing = $tiny_metadata->get_missing_count(); |
| 217 | $modified = $tiny_metadata->get_modified_count(); |
| 218 | $compressing = (count($uncompressed) > 0) ? count($uncompressed) : count($active); |
| 219 | |
| 220 | if ($tiny_metadata->get_in_progress_count() > 0) { |
| 221 | include(dirname(__FILE__) . '/views/compress-details-processing.php'); |
| 222 | } else { |
| 223 | include(dirname(__FILE__) . '/views/compress-details.php'); |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | public function bulk_compress_page() { |
| 228 | global $wpdb; |
| 229 | |
| 230 | echo '<div class="wrap" id="tiny-bulk-compress">'; |
| 231 | echo '<h2>' . self::translate('Compress JPEG & PNG Images') . '</h2>'; |
| 232 | if (empty($_POST['tiny-bulk-compress']) && empty($_REQUEST['ids'])) { |
| 233 | $result = $wpdb->get_results("SELECT COUNT(*) AS `count` FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A); |
| 234 | $image_count = $result[0]['count']; |
| 235 | $sizes_count = count($this->settings->get_active_tinify_sizes()); |
| 236 | |
| 237 | echo '<p>'; |
| 238 | echo self::translate_escape("Use this tool to compress all images in your media library") . '. '; |
| 239 | echo self::translate_escape("Only images that have not been compressed will be compressed") . '. '; |
| 240 | echo '</p>'; |
| 241 | echo '<p>'; |
| 242 | echo sprintf(self::translate_escape("We have found %d images in your media library and for each image %d sizes will be compressed"), $image_count, $sizes_count) . '. '; |
| 243 | echo sprintf(self::translate_escape('This results in %d compressions at most'), $image_count*$sizes_count) . '. '; |
| 244 | echo '</p>'; |
| 245 | echo '<p>'; |
| 246 | echo self::translate_escape("To begin, just press the button below") . '. '; |
| 247 | echo '</p>'; |
| 248 | |
| 249 | echo '<form method="POST" action="?page=tiny-bulk-compress">'; |
| 250 | echo '<input type="hidden" name="_wpnonce" value="' . wp_create_nonce('tiny-bulk-compress') . '">'; |
| 251 | echo '<input type="hidden" name="tiny-bulk-compress" value="1">'; |
| 252 | echo '<p>'; |
| 253 | echo '<button class="button button-primary button-large" type="submit">'; |
| 254 | echo self::translate_escape('Compress All Images'); |
| 255 | echo '</button>'; |
| 256 | echo '</p>'; |
| 257 | echo '</form>'; |
| 258 | } else { |
| 259 | check_admin_referer('tiny-bulk-compress'); |
| 260 | |
| 261 | if (!empty($_REQUEST['ids'])) { |
| 262 | $ids = implode(',', array_map('intval', explode('-', $_REQUEST['ids']))); |
| 263 | $cond = "AND ID IN($ids)"; |
| 264 | } else { |
| 265 | $cond = ""; |
| 266 | } |
| 267 | |
| 268 | // Get all ids and names of the images and not the whole objects which will only fill memory |
| 269 | $items = $wpdb->get_results("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' $cond ORDER BY ID DESC", ARRAY_A); |
| 270 | |
| 271 | echo '<p>'; |
| 272 | echo self::translate_escape("Please be patient while the images are being compressed") . '. '; |
| 273 | echo self::translate_escape("This can take a while if you have many images") . '. '; |
| 274 | echo self::translate_escape("Do not navigate away from this page because it will stop the process") . '. '; |
| 275 | echo self::translate_escape("You will be notified via this page when the processing is done") . '.'; |
| 276 | echo "</p>"; |
| 277 | |
| 278 | echo '<div id="tiny-status"><p>'. self::translate_escape('Compressions this month') . sprintf(' <span>%d</span></p></div>', $this->settings->get_status()); |
| 279 | echo '<div id="tiny-progress"><p>'. self::translate_escape('Processing') . ' <span>0</span> ' . self::translate_escape('out of') . sprintf(' %d </p></div>', count($items)); |
| 280 | echo '<div id="media-items">'; |
| 281 | echo '</div>'; |
| 282 | |
| 283 | echo '<script type="text/javascript">jQuery(function() { tinyBulkCompress('. json_encode($items) . ')})</script>'; |
| 284 | } |
| 285 | |
| 286 | echo '</div>'; |
| 287 | } |
| 288 | } |
| 289 |