config
11 years ago
languages
10 years ago
scripts
11 years ago
styles
11 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
11 years ago
class-tiny-plugin.php
277 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 | |
| 25 | private $settings; |
| 26 | |
| 27 | public static function jpeg_quality() { |
| 28 | return 95; |
| 29 | } |
| 30 | |
| 31 | public function __construct() { |
| 32 | parent::__construct(); |
| 33 | |
| 34 | $this->settings = new Tiny_Settings(); |
| 35 | if (is_admin()) { |
| 36 | add_action('admin_menu', $this->get_method('admin_menu')); |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | public function set_compressor($compressor) { |
| 41 | $this->settings->set_compressor($compressor); |
| 42 | } |
| 43 | |
| 44 | public function init() { |
| 45 | add_filter('jpeg_quality', $this->get_static_method('jpeg_quality')); |
| 46 | add_filter('wp_editor_set_quality', $this->get_static_method('jpeg_quality')); |
| 47 | add_filter('wp_generate_attachment_metadata', $this->get_method('compress_attachment'), 10, 2); |
| 48 | load_plugin_textdomain(self::NAME, false, dirname(plugin_basename(__FILE__)) . '/languages'); |
| 49 | } |
| 50 | |
| 51 | public function admin_init() { |
| 52 | add_filter('manage_media_columns', $this->get_method('add_media_columns')); |
| 53 | add_action('manage_media_custom_column', $this->get_method('render_media_column'), 10, 2); |
| 54 | add_action('wp_ajax_tiny_compress_image', $this->get_method('compress_image')); |
| 55 | add_action('admin_action_tiny_bulk_compress', $this->get_method('bulk_compress')); |
| 56 | add_action('admin_enqueue_scripts', $this->get_method('enqueue_scripts')); |
| 57 | } |
| 58 | |
| 59 | public function admin_menu() { |
| 60 | add_management_page( |
| 61 | self::translate('Compress JPEG & PNG Images'), self::translate('Compress All Images'), |
| 62 | 'upload_files', 'tiny-bulk-compress', $this->get_method('bulk_compress_page') |
| 63 | ); |
| 64 | |
| 65 | } |
| 66 | |
| 67 | public function enqueue_scripts($hook) { |
| 68 | wp_enqueue_style(self::NAME .'_admin', plugins_url('/styles/admin.css', __FILE__), |
| 69 | array(), self::plugin_version()); |
| 70 | |
| 71 | $handle = self::NAME .'_admin'; |
| 72 | wp_register_script($handle, plugins_url('/scripts/admin.js', __FILE__), |
| 73 | array(), self::plugin_version(), true); |
| 74 | |
| 75 | // Wordpress < 3.3 does not handle multi dimensional arrays |
| 76 | wp_localize_script($handle, 'tinyCompress', array( |
| 77 | 'nonce' => wp_create_nonce('tiny-compress'), |
| 78 | 'wpVersion' => self::wp_version(), |
| 79 | 'pluginVersion' => self::plugin_version(), |
| 80 | 'L10nAllDone' => self::translate('All images are processed'), |
| 81 | 'L10nBulkAction' => self::translate('Compress Images'), |
| 82 | 'L10nCompressing' => self::translate('Compressing'), |
| 83 | 'L10nCompressions' => self::translate('compressions'), |
| 84 | 'L10nError' => self::translate('Error'), |
| 85 | 'L10nInternalError' => self::translate('Internal error'), |
| 86 | 'L10nOutOf' => self::translate('out of'), |
| 87 | 'L10nWaiting' => self::translate('Waiting'), |
| 88 | )); |
| 89 | wp_enqueue_script($handle); |
| 90 | } |
| 91 | |
| 92 | private function compress($metadata, $attachment_id) { |
| 93 | $mime_type = get_post_mime_type($attachment_id); |
| 94 | $tiny_metadata = new Tiny_Metadata($attachment_id, $metadata); |
| 95 | |
| 96 | if ($this->settings->get_compressor() === null || strpos($mime_type, 'image/') !== 0) { |
| 97 | return $metadata; |
| 98 | } |
| 99 | |
| 100 | $success = 0; |
| 101 | $failed = 0; |
| 102 | |
| 103 | $compressor = $this->settings->get_compressor(); |
| 104 | $active_tinify_sizes = $this->settings->get_active_tinify_sizes(); |
| 105 | $uncompressed_sizes = $tiny_metadata->get_uncompressed_sizes($active_tinify_sizes); |
| 106 | |
| 107 | foreach ($uncompressed_sizes as $uncompressed_size) { |
| 108 | try { |
| 109 | $tiny_metadata->add_request($uncompressed_size); |
| 110 | $tiny_metadata->update(); |
| 111 | $response = $compressor->compress_file($tiny_metadata->get_filename($uncompressed_size)); |
| 112 | $responses[$uncompressed_size] = $response; |
| 113 | |
| 114 | $tiny_metadata->add_response($response, $uncompressed_size); |
| 115 | $success++; |
| 116 | } catch (Tiny_Exception $e) { |
| 117 | $tiny_metadata->add_exception($e, $uncompressed_size); |
| 118 | $failed++; |
| 119 | } |
| 120 | } |
| 121 | $tiny_metadata->update(); |
| 122 | |
| 123 | return array($tiny_metadata, array('success' => $success, 'failed' => $failed)); |
| 124 | } |
| 125 | |
| 126 | public function compress_attachment($metadata, $attachment_id) { |
| 127 | $this->compress($metadata, $attachment_id); |
| 128 | return $metadata; |
| 129 | } |
| 130 | |
| 131 | public function compress_image() { |
| 132 | if (!$this->check_ajax_referer()) { |
| 133 | exit(); |
| 134 | } |
| 135 | $json = !empty($_POST['json']) && $_POST['json']; |
| 136 | if (!current_user_can('upload_files')) { |
| 137 | $message = self::translate("You don't have permission to work with uploaded files") . '.'; |
| 138 | echo $json ? json_encode(array('error' => $message)) : $message; |
| 139 | exit(); |
| 140 | } |
| 141 | if (empty($_POST['id'])) { |
| 142 | $message = self::translate("Not a valid media file") . '.'; |
| 143 | echo $json ? json_encode(array('error' => $message)) : $message; |
| 144 | exit(); |
| 145 | } |
| 146 | $id = intval($_POST['id']); |
| 147 | $metadata = wp_get_attachment_metadata($id); |
| 148 | if (!is_array($metadata)) { |
| 149 | $message = self::translate("Could not find metadata of media file") . '.'; |
| 150 | echo $json ? json_encode(array('error' => $message)) : $message; |
| 151 | exit; |
| 152 | } |
| 153 | |
| 154 | list($tiny_metadata, $result) = $this->compress($metadata, $id); |
| 155 | if ($json) { |
| 156 | $result['message'] = $tiny_metadata->get_latest_error(); |
| 157 | $result['status'] = $this->settings->get_status(); |
| 158 | $result['thumbnail'] = $tiny_metadata->get_url('thumbnail'); |
| 159 | echo json_encode($result); |
| 160 | } else { |
| 161 | echo $this->render_compress_details($tiny_metadata); |
| 162 | } |
| 163 | |
| 164 | exit(); |
| 165 | } |
| 166 | |
| 167 | public function bulk_compress() { |
| 168 | check_admin_referer('bulk-media'); |
| 169 | |
| 170 | if (empty($_REQUEST['media']) || !is_array( $_REQUEST['media'])) { |
| 171 | return; |
| 172 | } |
| 173 | |
| 174 | $ids = implode('-', array_map('intval', $_REQUEST['media'])); |
| 175 | wp_redirect(add_query_arg( |
| 176 | '_wpnonce', |
| 177 | wp_create_nonce('tiny-bulk-compress'), |
| 178 | admin_url("tools.php?page=tiny-bulk-compress&ids=$ids") |
| 179 | )); |
| 180 | exit(); |
| 181 | } |
| 182 | |
| 183 | public function add_media_columns($columns) { |
| 184 | $columns[self::MEDIA_COLUMN] = self::translate(self::MEDIA_COLUMN_HEADER); |
| 185 | return $columns; |
| 186 | } |
| 187 | |
| 188 | public function render_media_column($column, $id) { |
| 189 | if ($column === self::MEDIA_COLUMN) { |
| 190 | $this->render_compress_details(new Tiny_Metadata($id)); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | private function render_compress_details($tiny_metadata) { |
| 195 | $missing = $tiny_metadata->get_uncompressed_sizes($this->settings->get_active_tinify_sizes()); |
| 196 | $success = count($tiny_metadata->get_success_sizes()); |
| 197 | $total = count($missing) + $success; |
| 198 | $progress = count($tiny_metadata->get_in_progress_sizes()); |
| 199 | |
| 200 | $duplicates = count($this->settings->get_active_tinify_sizes()) - $total; |
| 201 | $success += $duplicates; |
| 202 | $total += $duplicates; |
| 203 | |
| 204 | if (count($missing) > 0) { |
| 205 | printf(self::translate_escape('Compressed %d out of %d sizes'), $success, $total); |
| 206 | echo '<br/>'; |
| 207 | if (($error = $tiny_metadata->get_latest_error())) { |
| 208 | echo '<span class="error">' . self::translate_escape('Latest error') . ': '. self::translate_escape($error) .'</span><br/>'; |
| 209 | } |
| 210 | echo '<button type="button" class="tiny-compress" data-id="' . $tiny_metadata->get_id() . '">' . |
| 211 | self::translate_escape('Compress') . '</button>'; |
| 212 | echo '<div class="spinner hidden"></div>'; |
| 213 | } elseif ($progress > 0) { |
| 214 | printf(self::translate_escape('Compressing %d sizes...'), count($this->settings->get_active_tinify_sizes())); |
| 215 | } else { |
| 216 | printf(self::translate_escape('Compressed %d out of %d sizes'), $success, $total); |
| 217 | $savings = $tiny_metadata->get_savings(); |
| 218 | if ($savings['count'] > 0) { |
| 219 | echo '<br/>'; |
| 220 | echo self::translate_escape('Total size') . ': ' . size_format($savings['input']) . '<br/>'; |
| 221 | echo self::translate_escape('Compressed size') . ': ' . size_format($savings['output']); |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | public function bulk_compress_page() { |
| 227 | global $wpdb; |
| 228 | |
| 229 | echo '<div class="wrap" id="tiny-bulk-compress">'; |
| 230 | echo '<h2>' . self::translate('Compress JPEG & PNG Images') . '</h2>'; |
| 231 | if (empty($_POST['tiny-bulk-compress']) && empty($_REQUEST['ids'])) { |
| 232 | $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); |
| 233 | $count = $result[0]['count']; |
| 234 | |
| 235 | echo '<p>' . self::translate_escape("Use this tool to compress all images in your media library") . '. '; |
| 236 | echo self::translate_escape("Only images that have not been compressed will be compressed") . '.</p>'; |
| 237 | echo '<p>' . sprintf(self::translate_escape("We have found %d images in your media library"), $count) . '. '; |
| 238 | echo self::translate_escape("To begin, just press the button below") . '.</p>'; |
| 239 | |
| 240 | echo '<form method="POST" action="?page=tiny-bulk-compress">'; |
| 241 | echo '<input type="hidden" name="_wpnonce" value="' . wp_create_nonce('tiny-bulk-compress') . '">'; |
| 242 | echo '<input type="hidden" name="tiny-bulk-compress" value="1">'; |
| 243 | echo '<p><button class="button button-primary button-large" type="submit">' . |
| 244 | self::translate_escape('Compress All Images') . '</p>'; |
| 245 | echo '</form>'; |
| 246 | } else { |
| 247 | check_admin_referer('tiny-bulk-compress'); |
| 248 | |
| 249 | if (!empty($_REQUEST['ids'])) { |
| 250 | $ids = implode(',', array_map('intval', explode('-', $_REQUEST['ids']))); |
| 251 | $cond = "AND ID IN($ids)"; |
| 252 | } else { |
| 253 | $cond = ""; |
| 254 | } |
| 255 | |
| 256 | // Get all ids and names of the images and not the whole objects which will only fill memory |
| 257 | $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); |
| 258 | |
| 259 | echo '<p>'; |
| 260 | echo self::translate_escape("Please be patient while the images are being compressed") . '. '; |
| 261 | echo self::translate_escape("This can take a while if you have many images") . '. '; |
| 262 | echo self::translate_escape("Do not navigate away from this page because it will stop the process") . '. '; |
| 263 | echo self::translate_escape("You will be notified via this page when the processing is done") . '.'; |
| 264 | echo "</p>"; |
| 265 | |
| 266 | echo '<div id="tiny-status"><p>'. self::translate_escape('Compressions this month') . sprintf(' <span>%d</span></p></div>', $this->settings->get_status()); |
| 267 | echo '<div id="tiny-progress"><p>'. self::translate_escape('Processing') . ' <span>0</span> ' . self::translate_escape('out of') . sprintf(' %d </p></div>', count($items)); |
| 268 | echo '<div id="media-items">'; |
| 269 | echo '</div>'; |
| 270 | |
| 271 | echo '<script type="text/javascript">jQuery(function() { tinyBulkCompress('. json_encode($items) . ')})</script>'; |
| 272 | } |
| 273 | |
| 274 | echo '</div>'; |
| 275 | } |
| 276 | } |
| 277 |