| @@ -1,94 +1,391 @@ | ||
| 1 | -<?php | |
| 2 | -defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' ); | |
| 1 | +<?php | |
| 2 | +defined( 'ABSPATH' ) || exit; | |
| 3 | 3 | |
| 4 | -/* | |
| 5 | - * Get all mime type which could be optimized by Imagify. | |
| 4 | +/** | |
| 5 | + * Get all mime types which could be optimized by Imagify. | |
| 6 | 6 | * |
| 7 | - * @since 1.3 | |
| 7 | + * @since 1.7 | |
| 8 | + * @since 1.8 Added $type parameter. | |
| 8 | 9 | * |
| 9 | - * @return array $mime_type The mime type. | |
| 10 | + * @param string $type One of 'image', 'not-image'. Any other value will return all mime types. | |
| 11 | + * @return array The mime types. | |
| 10 | 12 | */ |
| 11 | -function get_imagify_mime_type() { | |
| 12 | - $mime_type = array( | |
| 13 | - 'image/jpeg', | |
| 14 | - 'image/png', | |
| 15 | - 'image/gif' | |
| 13 | +function imagify_get_mime_types( $type = null ) { | |
| 14 | + $mimes = []; | |
| 15 | + | |
| 16 | + if ( 'not-image' !== $type ) { | |
| 17 | + $mimes = [ | |
| 18 | + 'jpg|jpeg|jpe' => 'image/jpeg', | |
| 19 | + 'png' => 'image/png', | |
| 20 | + 'gif' => 'image/gif', | |
| 21 | + 'webp' => 'image/webp', | |
| 22 | + ]; | |
| 23 | + } | |
| 24 | + | |
| 25 | + if ( 'image' !== $type ) { | |
| 26 | + $mimes['pdf'] = 'application/pdf'; | |
| 27 | + } | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * Filter the mime types which could be optimized by Imagify. | |
| 31 | + * | |
| 32 | + * @since 2.3.1 | |
| 33 | + * | |
| 34 | + * @param array $mimes The mime types, as extension => mime type pairs. | |
| 35 | + */ | |
| 36 | + $mimes = wpm_apply_filters_typed( 'array', 'imagify_get_mime_types', $mimes ); | |
| 37 | + | |
| 38 | + // Keep only well-formed extension => mime type pairs. | |
| 39 | + return array_filter( | |
| 40 | + $mimes, | |
| 41 | + function ( $mime, $ext ) { | |
| 42 | + return is_string( $ext ) && '' !== $ext && is_string( $mime ) && preg_match( '@^[a-z-]+/[a-z0-9.+-]+$@', $mime ); | |
| 43 | + }, | |
| 44 | + ARRAY_FILTER_USE_BOTH | |
| 16 | 45 | ); |
| 17 | - | |
| 18 | - return $mime_type; | |
| 19 | 46 | } |
| 20 | 47 | |
| 21 | -/* | |
| 22 | - * Get the backup path of a specific attachement. | |
| 48 | +/** | |
| 49 | + * Tell if an attachment has a supported mime type. | |
| 50 | + * Was previously Imagify_AS3CF::is_mime_type_supported() since 1.6.6. | |
| 23 | 51 | * |
| 24 | - * @since 1.0 | |
| 52 | + * @since 1.6.8 | |
| 53 | + * @author Grégory Viguier | |
| 25 | 54 | * |
| 26 | - * @param int $file_path The attachment path. | |
| 27 | - * @return string $backup_path The backup path. | |
| 55 | + * @param int $attachment_id The attachment ID. | |
| 56 | + * @return bool | |
| 28 | 57 | */ |
| 29 | -function get_imagify_attachment_backup_path( $file_path ) { | |
| 30 | - $upload_dir = wp_upload_dir(); | |
| 31 | - $upload_basedir = trailingslashit( $upload_dir['basedir'] ); | |
| 32 | - $backup_dir = $upload_basedir . 'backup/'; | |
| 33 | - | |
| 58 | +function imagify_is_attachment_mime_type_supported( $attachment_id ) { | |
| 59 | + static $is = [ false ]; | |
| 60 | + | |
| 61 | + $attachment_id = absint( $attachment_id ); | |
| 62 | + | |
| 63 | + if ( isset( $is[ $attachment_id ] ) ) { | |
| 64 | + return $is[ $attachment_id ]; | |
| 65 | + } | |
| 66 | + | |
| 67 | + $mime_types = imagify_get_mime_types(); | |
| 68 | + $mime_types = array_flip( $mime_types ); | |
| 69 | + $mime_type = (string) get_post_mime_type( $attachment_id ); | |
| 70 | + | |
| 71 | + $is[ $attachment_id ] = isset( $mime_types[ $mime_type ] ); | |
| 72 | + | |
| 73 | + return $is[ $attachment_id ]; | |
| 74 | +} | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Get post statuses related to attachments. | |
| 78 | + * | |
| 79 | + * @since 1.7 | |
| 80 | + * @author Grégory Viguier | |
| 81 | + * | |
| 82 | + * @return array | |
| 83 | + */ | |
| 84 | +function imagify_get_post_statuses() { | |
| 85 | + static $statuses; | |
| 86 | + | |
| 87 | + if ( isset( $statuses ) ) { | |
| 88 | + return $statuses; | |
| 89 | + } | |
| 90 | + | |
| 91 | + $statuses = [ | |
| 92 | + 'inherit' => 'inherit', | |
| 93 | + 'private' => 'private', | |
| 94 | + ]; | |
| 95 | + | |
| 96 | + $custom_statuses = get_post_stati( [ 'public' => true ] ); | |
| 97 | + unset( $custom_statuses['publish'] ); | |
| 98 | + | |
| 99 | + if ( $custom_statuses ) { | |
| 100 | + $statuses = array_merge( $statuses, $custom_statuses ); | |
| 101 | + } | |
| 102 | + | |
| 34 | 103 | /** |
| 35 | - * Filter the backup directory path | |
| 104 | + * Filter the post statuses Imagify is allowed to optimize. | |
| 36 | 105 | * |
| 106 | + * @since 1.7 | |
| 107 | + * @author Grégory Viguier | |
| 108 | + * | |
| 109 | + * @param array $statuses An array of post statuses. Kays and values are set. | |
| 110 | + */ | |
| 111 | + $statuses = apply_filters( 'imagify_post_statuses', $statuses ); | |
| 112 | + | |
| 113 | + return $statuses; | |
| 114 | +} | |
| 115 | + | |
| 116 | +/** | |
| 117 | + * Tell if the site has attachments (only the ones Imagify would optimize) without the required WP metadata. | |
| 118 | + * | |
| 119 | + * @param bool $reset Reset the static method to null when set to true, defaulted to false. | |
| 120 | + * @since 1.7 | |
| 121 | + * @author Grégory Viguier | |
| 122 | + * | |
| 123 | + * @return bool | |
| 124 | + */ | |
| 125 | +function imagify_has_attachments_without_required_metadata( $reset = false ) { | |
| 126 | + global $wpdb; | |
| 127 | + static $has; | |
| 128 | + | |
| 129 | + if ( $reset ) { | |
| 130 | + $has = null; | |
| 131 | + } | |
| 132 | + | |
| 133 | + if ( isset( $has ) ) { | |
| 134 | + return $has; | |
| 135 | + } | |
| 136 | + | |
| 137 | + $mime_types = Imagify_DB::get_mime_types(); | |
| 138 | + $statuses = Imagify_DB::get_post_statuses(); | |
| 139 | + $exist_data = Imagify_DB::get_required_wp_metadata_exist_clause( | |
| 140 | + 'p.ID', | |
| 141 | + false | |
| 142 | + ); | |
| 143 | + $has = (bool) $wpdb->get_var( // WPCS: unprepared SQL ok. | |
| 144 | + " | |
| 145 | + SELECT p.ID | |
| 146 | + FROM $wpdb->posts AS p | |
| 147 | + WHERE p.post_mime_type IN ( $mime_types ) | |
| 148 | + AND p.post_type = 'attachment' | |
| 149 | + AND p.post_status IN ( $statuses ) | |
| 150 | + $exist_data | |
| 151 | + LIMIT 1" | |
| 152 | + ); | |
| 153 | + | |
| 154 | + return $has; | |
| 155 | +} | |
| 156 | + | |
| 157 | +/** | |
| 158 | + * Get the path to the backups directory. | |
| 159 | + * | |
| 160 | + * @since 1.6.8 | |
| 161 | + * @author Grégory Viguier | |
| 162 | + * | |
| 163 | + * @param bool $bypass_error True to return the path even if there is an error. This is used when we want to display this path in a message for example. | |
| 164 | + * @return string|bool Path to the backups directory. False on failure. | |
| 165 | + */ | |
| 166 | +function get_imagify_backup_dir_path( $bypass_error = false ) { | |
| 167 | + static $backup_dir; | |
| 168 | + | |
| 169 | + if ( isset( $backup_dir ) ) { | |
| 170 | + return $backup_dir; | |
| 171 | + } | |
| 172 | + | |
| 173 | + $upload_basedir = get_imagify_upload_basedir( $bypass_error ); | |
| 174 | + | |
| 175 | + if ( ! $upload_basedir ) { | |
| 176 | + return false; | |
| 177 | + } | |
| 178 | + | |
| 179 | + $backup_dir = $upload_basedir . 'backup/'; | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Filter the backup directory path. | |
| 183 | + * | |
| 37 | 184 | * @since 1.0 |
| 38 | 185 | * |
| 39 | - * @param string $backup_dir The backup directory path | |
| 186 | + * @param string $backup_dir The backup directory path. | |
| 40 | 187 | */ |
| 41 | - $backup_dir = apply_filters( 'imagify_backup_directory', $backup_dir ); | |
| 42 | - $backup_dir = trailingslashit( $backup_dir ); | |
| 43 | - | |
| 44 | - $backup_path = str_replace( $upload_basedir, $backup_dir, $file_path ); | |
| 45 | - return $backup_path; | |
| 188 | + $backup_dir = apply_filters( 'imagify_backup_directory', $backup_dir ); | |
| 189 | + $backup_dir = imagify_get_filesystem()->normalize_dir_path( $backup_dir ); | |
| 190 | + | |
| 191 | + return $backup_dir; | |
| 46 | 192 | } |
| 47 | 193 | |
| 48 | -/* | |
| 194 | +/** | |
| 195 | + * Tell if the folder containing the backups is writable. | |
| 196 | + * | |
| 197 | + * @since 1.6.8 | |
| 198 | + * @author Grégory Viguier | |
| 199 | + * | |
| 200 | + * @return bool | |
| 201 | + */ | |
| 202 | +function imagify_backup_dir_is_writable() { | |
| 203 | + return imagify_get_filesystem()->make_dir( get_imagify_backup_dir_path() ); | |
| 204 | +} | |
| 205 | + | |
| 206 | +/** | |
| 207 | + * Get the backup path of a specific attachement. | |
| 208 | + * | |
| 209 | + * @since 1.0 | |
| 210 | + * | |
| 211 | + * @param string $file_path The file path. | |
| 212 | + * @return string|bool The backup path. False on failure. | |
| 213 | + */ | |
| 214 | +function get_imagify_attachment_backup_path( $file_path ) { | |
| 215 | + $file_path = wp_normalize_path( (string) $file_path ); | |
| 216 | + $upload_basedir = get_imagify_upload_basedir(); | |
| 217 | + $backup_dir = get_imagify_backup_dir_path(); | |
| 218 | + | |
| 219 | + if ( ! $file_path || ! $upload_basedir ) { | |
| 220 | + return false; | |
| 221 | + } | |
| 222 | + | |
| 223 | + return preg_replace( '@^' . preg_quote( $upload_basedir, '@' ) . '@', $backup_dir, $file_path ); | |
| 224 | +} | |
| 225 | + | |
| 226 | +/** | |
| 49 | 227 | * Retrieve file path for an attachment based on filename. |
| 50 | 228 | * |
| 51 | 229 | * @since 1.4.5 |
| 52 | 230 | * |
| 53 | - * @param int $filename The filename. | |
| 54 | - * @return string|false $file_path The file path to where the attached file should be, false otherwise. | |
| 231 | + * @param int $file_path The file path. | |
| 232 | + * @return string|false The file path to where the attached file should be, false otherwise. | |
| 55 | 233 | */ |
| 56 | -function get_imagify_attached_file( $filename ) { | |
| 57 | - $file_path = false; | |
| 58 | - | |
| 59 | - // If the file is relative, prepend upload dir. | |
| 60 | - if ( $filename && 0 !== strpos( $filename, '/' ) && ! preg_match( '|^.:\\\|', $filename ) && ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) ) { | |
| 61 | - $file_path = $uploads['basedir'] . "/$filename"; | |
| 234 | +function get_imagify_attached_file( $file_path ) { | |
| 235 | + $file_path = wp_normalize_path( (string) $file_path ); | |
| 236 | + $upload_basedir = get_imagify_upload_basedir(); | |
| 237 | + | |
| 238 | + if ( ! $file_path || ! $upload_basedir ) { | |
| 239 | + return false; | |
| 62 | 240 | } |
| 63 | - | |
| 64 | - return $file_path; | |
| 241 | + | |
| 242 | + // The file path is absolute. | |
| 243 | + if ( strpos( $file_path, '/' ) === 0 || preg_match( '|^.:\\\|', $file_path ) ) { | |
| 244 | + return false; | |
| 245 | + } | |
| 246 | + | |
| 247 | + // Prepend upload dir. | |
| 248 | + return $upload_basedir . $file_path; | |
| 65 | 249 | } |
| 66 | 250 | |
| 67 | -/* | |
| 68 | - * Retrieve the URL for an attachment based on filename. | |
| 251 | +/** | |
| 252 | + * Retrieve the URL for an attachment based on file path. | |
| 69 | 253 | * |
| 70 | 254 | * @since 1.4.5 |
| 71 | 255 | * |
| 72 | - * @param int $filename The filename. | |
| 73 | - * @return string|false $url Attachment URL, otherwise false. | |
| 256 | + * @param string $file_path A relative or absolute file path. | |
| 257 | + * @return string|bool File URL, otherwise false. | |
| 74 | 258 | */ |
| 75 | -function get_imagify_attachment_url( $filename ) { | |
| 76 | - $url = ''; | |
| 77 | - | |
| 78 | - // Get upload directory. | |
| 79 | - if ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) { | |
| 80 | - // Check that the upload base exists in the file location. | |
| 81 | - if ( 0 === strpos( $filename, $uploads['basedir'] ) ) { | |
| 82 | - // Replace file location with url location. | |
| 83 | - $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filename ); | |
| 84 | - } elseif ( false !== strpos( $filename, 'wp-content/uploads' ) ) { | |
| 85 | - // Get the directory name relative to the basedir (back compat for pre-2.7 uploads) | |
| 86 | - $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $filename ) ) . basename( $filename ); | |
| 259 | +function get_imagify_attachment_url( $file_path ) { | |
| 260 | + $file_path = wp_normalize_path( (string) $file_path ); | |
| 261 | + $upload_basedir = get_imagify_upload_basedir(); | |
| 262 | + | |
| 263 | + if ( ! $file_path || ! $upload_basedir ) { | |
| 264 | + return false; | |
| 265 | + } | |
| 266 | + | |
| 267 | + $upload_baseurl = get_imagify_upload_baseurl(); | |
| 268 | + | |
| 269 | + // Check that the upload base exists in the (absolute) file location. | |
| 270 | + if ( 0 === strpos( $file_path, $upload_basedir ) ) { | |
| 271 | + // Replace file location with url location. | |
| 272 | + return preg_replace( '@^' . preg_quote( $upload_basedir, '@' ) . '@', $upload_baseurl, $file_path ); | |
| 273 | + } | |
| 274 | + | |
| 275 | + if ( false !== strpos( '/' . $file_path, '/wp-content/uploads/' ) ) { | |
| 276 | + // Get the directory name relative to the basedir (back compat for pre-2.7 uploads). | |
| 277 | + return trailingslashit( $upload_baseurl . _wp_get_attachment_relative_path( $file_path ) ) . imagify_get_filesystem()->file_name( $file_path ); | |
| 278 | + } | |
| 279 | + | |
| 280 | + // It's a newly-uploaded file, therefore $file is relative to the basedir. | |
| 281 | + return $upload_baseurl . $file_path; | |
| 282 | +} | |
| 283 | + | |
| 284 | +/** | |
| 285 | + * Get size information for all currently registered thumbnail sizes. | |
| 286 | + * | |
| 287 | + * @since 1.5.10 | |
| 288 | + * @since 1.6.10 For consistency, revamped the function like WP does with wp_generate_attachment_metadata(). | |
| 289 | + * Removed the filter, added crop value to each size. | |
| 290 | + * @author Grégory Viguier | |
| 291 | + * | |
| 292 | + * @return array { | |
| 293 | + * Data for the currently registered thumbnail sizes. | |
| 294 | + * Size names are used as array keys. | |
| 295 | + * | |
| 296 | + * @type int $width The image width. | |
| 297 | + * @type int $height The image height. | |
| 298 | + * @type bool $crop True to crop, false to resize. | |
| 299 | + * @type string $name The size name. | |
| 300 | + * } | |
| 301 | + */ | |
| 302 | +function get_imagify_thumbnail_sizes() { | |
| 303 | + // All image size names. | |
| 304 | + $intermediate_image_sizes = get_intermediate_image_sizes(); | |
| 305 | + $intermediate_image_sizes = array_flip( $intermediate_image_sizes ); | |
| 306 | + // Additional image size attributes. | |
| 307 | + $additional_image_sizes = wp_get_additional_image_sizes(); | |
| 308 | + | |
| 309 | + // Create the full array with sizes and crop info. | |
| 310 | + foreach ( $intermediate_image_sizes as $size_name => $s ) { | |
| 311 | + $intermediate_image_sizes[ $size_name ] = [ | |
| 312 | + 'width' => '', | |
| 313 | + 'height' => '', | |
| 314 | + 'crop' => false, | |
| 315 | + 'name' => $size_name, | |
| 316 | + ]; | |
| 317 | + | |
| 318 | + if ( isset( $additional_image_sizes[ $size_name ]['width'] ) ) { | |
| 319 | + // For theme-added sizes. | |
| 320 | + $intermediate_image_sizes[ $size_name ]['width'] = (int) $additional_image_sizes[ $size_name ]['width']; | |
| 87 | 321 | } else { |
| 88 | - // It's a newly-uploaded file, therefore $file is relative to the basedir. | |
| 89 | - $url = $uploads['baseurl'] . "/$filename"; | |
| 322 | + // For default sizes set in options. | |
| 323 | + $intermediate_image_sizes[ $size_name ]['width'] = (int) get_option( "{$size_name}_size_w" ); | |
| 90 | 324 | } |
| 325 | + | |
| 326 | + if ( isset( $additional_image_sizes[ $size_name ]['height'] ) ) { | |
| 327 | + // For theme-added sizes. | |
| 328 | + $intermediate_image_sizes[ $size_name ]['height'] = (int) $additional_image_sizes[ $size_name ]['height']; | |
| 329 | + } else { | |
| 330 | + // For default sizes set in options. | |
| 331 | + $intermediate_image_sizes[ $size_name ]['height'] = (int) get_option( "{$size_name}_size_h" ); | |
| 332 | + } | |
| 333 | + | |
| 334 | + if ( isset( $additional_image_sizes[ $size_name ]['crop'] ) ) { | |
| 335 | + // For theme-added sizes. | |
| 336 | + $intermediate_image_sizes[ $size_name ]['crop'] = (int) $additional_image_sizes[ $size_name ]['crop']; | |
| 337 | + } else { | |
| 338 | + // For default sizes set in options. | |
| 339 | + $intermediate_image_sizes[ $size_name ]['crop'] = (int) get_option( "{$size_name}_crop" ); | |
| 340 | + } | |
| 91 | 341 | } |
| 92 | - | |
| 93 | - return $url; | |
| 94 | -} | |
| 342 | + | |
| 343 | + return $intermediate_image_sizes; | |
| 344 | +} | |
| 345 | + | |
| 346 | +/** | |
| 347 | + * A simple helper to get the upload basedir. | |
| 348 | + * | |
| 349 | + * @since 1.6.7 | |
| 350 | + * @since 1.6.8 Added the $bypass_error parameter. | |
| 351 | + * @author Grégory Viguier | |
| 352 | + * | |
| 353 | + * @param bool $bypass_error True to return the path even if there is an error. This is used when we want to display this path in a message for example. | |
| 354 | + * @return string|bool The path. False on failure. | |
| 355 | + */ | |
| 356 | +function get_imagify_upload_basedir( $bypass_error = false ) { | |
| 357 | + return imagify_get_filesystem()->get_upload_basedir( $bypass_error ); | |
| 358 | +} | |
| 359 | + | |
| 360 | +/** | |
| 361 | + * A simple helper to get the upload baseurl. | |
| 362 | + * | |
| 363 | + * @since 1.6.7 | |
| 364 | + * @author Grégory Viguier | |
| 365 | + * | |
| 366 | + * @return string|bool The URL. False on failure. | |
| 367 | + */ | |
| 368 | +function get_imagify_upload_baseurl() { | |
| 369 | + return imagify_get_filesystem()->get_upload_baseurl(); | |
| 370 | +} | |
| 371 | + | |
| 372 | +/** | |
| 373 | + * Get the maximal number of unoptimized attachments to fetch. | |
| 374 | + * | |
| 375 | + * @since 1.6.14 | |
| 376 | + * @author Grégory Viguier | |
| 377 | + * | |
| 378 | + * @return int | |
| 379 | + */ | |
| 380 | +function imagify_get_unoptimized_attachment_limit() { | |
| 381 | + /** | |
| 382 | + * Filter the unoptimized attachments limit query. | |
| 383 | + * | |
| 384 | + * @since 1.4.4 | |
| 385 | + * | |
| 386 | + * @param int $limit The limit (-1 for unlimited). | |
| 387 | + */ | |
| 388 | + $limit = (int) apply_filters( 'imagify_unoptimized_attachment_limit', 10000 ); | |
| 389 | + | |
| 390 | + return -1 === $limit ? PHP_INT_MAX : abs( $limit ); | |
| 391 | +} | |