├── bower.json ├── component.json ├── composer.json ├── dynamic_img_resize.php ├── package.json └── readme.md /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "wcm/dynamic-image-resize", 3 | "version" : "1.6.3", 4 | "main" : "dynamic_img_resize.php", 5 | "ignore" : [ 6 | ".git", 7 | "assets/scripts/vendor", 8 | "assets/styles/vendor", 9 | "node_modules" 10 | ] 11 | } -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "wcm/dynamic-image-resize", 3 | "version" : "1.6.3", 4 | "description" : "Enables WordPress custom image sizes on the fly. Can be used with a shortcode or a template tag.", 5 | "homepage" : "http://franz-josef-kaiser.github.io/Dynamic-Image-Resize/", 6 | "author" : "Franz Josef Kaiser", 7 | "main" : "dynamic_img_resize.php", 8 | "keywords" : [ 9 | "wordpress", 10 | "plugin", 11 | "responsive", 12 | "adaptive", 13 | "dynamic", 14 | "image", 15 | "resize" 16 | ] 17 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "wcm/dynamic-image-resize", 3 | "description" : "Enables WordPress custom image sizes on the fly. Can be used with a shortcode or a template tag.", 4 | "type" : "library", 5 | "homepage" : "http://franz-josef-kaiser.github.io/Dynamic-Image-Resize/", 6 | "license" : "MIT", 7 | "require" : { 8 | "php" : ">=5.2.7", 9 | "composer/installers" : "~1.0" 10 | }, 11 | "authors" : [ 12 | { 13 | "name" : "Franz Josef Kaiser", 14 | "email" : "franzjosef@unserkaiser.com" 15 | }, 16 | { 17 | "name" : "Andrea Carraro", 18 | "email" : "hi@andreacarraro.it" 19 | } 20 | ], 21 | "support" : { 22 | "issues" : "https://github.com/franz-josef-kaiser/Dynamic-Image-Resize/issues", 23 | "source" : "https://github.com/franz-josef-kaiser/Dynamic-Image-Resize" 24 | }, 25 | "keywords" : [ 26 | "wordpress", 27 | "plugin", 28 | "responsive", 29 | "adaptive", 30 | "dynamic", 31 | "image", 32 | "resize" 33 | ] 34 | } -------------------------------------------------------------------------------- /dynamic_img_resize.php: -------------------------------------------------------------------------------- 1 | [dynamic_image] shortcode, pseudo-TimThumb but creates resized and cropped image files from existing media library entries. Usage: [dynamic_image src="http://example.org/wp-content/uploads/2012/03/image.png" width="100" height="100"]. Also offers a template tag. 8 | * Version: 1.6.3 9 | * Author: Franz Josef Kaiser 10 | * Author URI: http://unserkaiser.com 11 | * License: MIT 12 | */ 13 | 14 | 15 | if ( ! class_exists( 'oxoDynamicImageResize' ) ) 16 | { 17 | 18 | /** 19 | * @author Franz Josef Kaiser 20 | * @link http://unserkaiser.com 21 | * @license MIT 22 | */ 23 | class oxoDynamicImageResize 24 | { 25 | /** 26 | * Holds the input attributes 27 | * @var array 28 | * @access private 29 | */ 30 | private $atts = array(); 31 | 32 | /** 33 | * Holds the HTML MarkUp for height/width Attributes 34 | * @var string 35 | */ 36 | private $hw_string = ''; 37 | 38 | /** 39 | * Base URL to prefix for all image files. 40 | * @var string 41 | */ 42 | private $baseUrl = ''; 43 | 44 | /** 45 | * The currently processed Attachments ID. 46 | * @var int|null 47 | */ 48 | private $att_id = null; 49 | 50 | /** 51 | * The currently processed Attachment Meta Data Array. 52 | * @var array 53 | */ 54 | private $att_meta = array(); 55 | 56 | /** 57 | * Constructor 58 | * Adds the shortcode 59 | * @param array $atts 60 | * @return \oxoDynamicImageResize|\WP_Error 61 | */ 62 | public function __construct( $atts ) 63 | { 64 | if ( ! is_array( $atts ) ) 65 | { 66 | return new WP_Error( 67 | 'wrong_arg_type', 68 | __( 'Args need to be an array for the dynamic_image_resize template tag.', 'dyn_textdomain' ), 69 | __FILE__ 70 | ); 71 | } 72 | 73 | return $this->setAttributes( $atts ); 74 | } 75 | 76 | /** 77 | * Set the Attributes 78 | * @param $atts 79 | * @return void 80 | */ 81 | public function setAttributes( $atts ) 82 | { 83 | $this->atts = $atts; 84 | } 85 | 86 | /** 87 | * Get the Attributes 88 | * @return array 89 | */ 90 | public function getAttributes() 91 | { 92 | return $this->atts; 93 | } 94 | 95 | /** 96 | * Returns the image HTML or the Error message. 97 | * @return string 98 | */ 99 | public function __toString() 100 | { 101 | return $this->getHTMLOutput(); 102 | } 103 | 104 | /** 105 | * Wrapper function that combines the HTML and Error output. 106 | * Makes it easier for extending classes to just override the __toString() method. 107 | * @return mixed|string 108 | */ 109 | public function getHTMLOutput() 110 | { 111 | $output = $this->getImage(); 112 | 113 | if ( ! is_wp_error( $output ) ) 114 | return $output; 115 | 116 | return $this->getErrorMessage( $output ); 117 | } 118 | 119 | /** 120 | * Displays an Error Message if an error was found instead of an Image. 121 | * Only displays for logged in users who are allowed to edit posts. 122 | * Only is available when WP_DEBUG is set to TRUE. 123 | * @param $output \WP_Error 124 | * @return string 125 | */ 126 | public function getErrorMessage( $output ) 127 | { 128 | // No error message for Guests or Subscribers 129 | // Assuming that no one has activated caching plugins when debugging 130 | // and not set WP_DEBUG to TRUE on a live site 131 | if ( 132 | ! is_user_logged_in() 133 | AND ! current_user_can( 'edit_posts' ) 134 | AND ( ! defined( 'WP_DEBUG' ) OR ! WP_DEBUG ) 135 | ) 136 | return ''; 137 | 138 | // Error output for development 139 | return "{$output->get_error_message( 'no_attachment' )}: {$output->get_error_data()}"; 140 | 141 | } 142 | 143 | /** 144 | * Merges the Shortcode Attributes with input Arguments. 145 | * @param array $atts 146 | * @return array $atts 147 | */ 148 | public function parseAttributes( $atts ) 149 | { 150 | return shortcode_atts( 151 | array( 152 | 'src' => '', 153 | 'width' => '', 154 | 'height' => '', 155 | 'classes' => '', 156 | 'hwmarkup' => 'true', 157 | ), 158 | $atts, 159 | // If the shortcode name changes, this arg must align. 160 | 'dynamic_image' 161 | ); 162 | } 163 | 164 | /** 165 | * Sanitize attributes 166 | * @param array $atts 167 | * @return array 168 | */ 169 | public function sanitizeAttributes( $atts ) 170 | { 171 | // Get rid of eventual leading/trailing white spaces around attributes. 172 | $atts = array_map( 'trim', $atts ); 173 | 174 | return array( 175 | 'src' => ! filter_var( $atts['src'], FILTER_VALIDATE_INT ) 176 | ? esc_url( $atts['src'] ) 177 | : absint( $atts['src'] ), 178 | 'height' => absint( $atts['height'] ), 179 | 'width' => absint( $atts['width'] ), 180 | 'classes' => esc_attr( $atts['classes'] ), 181 | 'hwmarkup' => filter_var( $atts['hwmarkup'], FILTER_VALIDATE_BOOLEAN ) 182 | ); 183 | } 184 | 185 | /** 186 | * Sets the $hw_string class var that holds the height/width HTML attribute string. 187 | * @param int $width 188 | * @param int $height 189 | * @return void 190 | */ 191 | public function setHeightWidthString( $width, $height ) 192 | { 193 | $this->hw_string = image_hwstring( $width, $height ); 194 | } 195 | 196 | /** 197 | * Gets the height/width HTML string. 198 | * @return string 199 | */ 200 | public function getHeightWidthString() 201 | { 202 | return $this->hw_string; 203 | } 204 | 205 | /** 206 | * Builds the image 207 | * @uses image_make_intermediate_size 208 | * @internal param array $atts 209 | * @return mixed string/WP Error $html 210 | */ 211 | public function getImage() 212 | { 213 | $atts = $this->getAttributes(); 214 | $atts = $this->parseAttributes( $atts ); 215 | $atts = $this->sanitizeAttributes( $atts ); 216 | 217 | $this->setHeightWidthString( 218 | $atts['width'], 219 | $atts['height'] 220 | ); 221 | $hw_string = $this->getHeightWidthString(); 222 | ! $atts['hwmarkup'] AND $hw_string = ''; 223 | 224 | $needs_resize = true; 225 | $file = 'No image'; 226 | $error = false; 227 | 228 | // ID as src 229 | if ( is_int( $atts['src'] ) ) 230 | { 231 | $att_id = $atts['src']; 232 | // returns false on failure 233 | $atts['src'] = wp_get_attachment_url( $att_id ); 234 | 235 | // If nothing was found: 236 | ! $atts['src'] AND $error = true; 237 | } 238 | // Path as src 239 | else 240 | { 241 | // Let's see if the image belongs to our uploads directory… 242 | $img_url = substr( 243 | $atts['src'], 244 | 0, 245 | strlen( $this->getBaseUrl() ) 246 | ); 247 | 248 | // …And if not: just return the image HTML string 249 | if ( $img_url !== $this->getBaseUrl() ) 250 | { 251 | return $this->getMarkUp( 252 | $img_url, 253 | $hw_string, 254 | $atts['classes'] 255 | ); 256 | } 257 | 258 | // Prepare file name for DB search. 259 | $file = str_replace( 260 | trailingslashit( $this->getBaseUrl() ), 261 | '', 262 | $atts['src'] 263 | ); 264 | // Look up the file in the database. 265 | $att_id = $this->getAttachment( $file ); 266 | // If no attachment record was found: Prepare for an WP_Error. 267 | ! $att_id AND $error = true; 268 | } 269 | 270 | // Abort if the attachment wasn't found 271 | if ( $error ) 272 | { 273 | return new WP_Error( 274 | 'no_attachment', 275 | __( 'Attachment not found by the dynamic-image shortcode.', 'dyn_textdomain' ), 276 | $file 277 | ); 278 | } 279 | 280 | // Look through the attachment meta data for an image that fits our size. 281 | $meta = wp_get_attachment_metadata( $att_id ); 282 | $this->setAttachmentMeta( $meta ); 283 | foreach( $meta['sizes'] as $size ) 284 | { 285 | if ( 286 | $atts['width'] === $size['width'] 287 | AND $atts['height'] === $size['height'] 288 | ) 289 | { 290 | $atts['src'] = str_replace( 291 | basename( $atts['src'] ), 292 | $size['file'], 293 | $atts['src'] 294 | ); 295 | $needs_resize = false; 296 | 297 | // We found an image. Now abort the loop and process it. 298 | break; 299 | } 300 | } 301 | 302 | // If we need resizing 303 | if ( $needs_resize ) 304 | { 305 | // and if an image of such size was not found,… 306 | $attached_file = get_attached_file( $att_id ); 307 | // …we can create one. 308 | $resized = image_make_intermediate_size( 309 | $attached_file, 310 | $atts['width'], 311 | $atts['height'], 312 | true 313 | ); 314 | 315 | if ( 316 | // \WP_Error returned from WP_Image_Editor_Imagick, WP_Image_Editor_GD 317 | // or any other editor that was added using the 'wp_image_editors'-filter. 318 | ! is_wp_error( $resized ) 319 | // FALSE returned from image_make_intermediate_size() 320 | // when no width/height were provided. 321 | AND false !== $resized 322 | ) 323 | { 324 | // Generate key for new size 325 | $key = sprintf( 326 | 'resized-%dx%d', 327 | $atts['width'], 328 | $atts['height'] 329 | ); 330 | // Push to Meta Data Array 331 | $meta['sizes'][ $key ] = $resized; 332 | 333 | // Update src for final MarkUp 334 | $atts['src'] = str_replace( 335 | basename( $atts['src'] ), 336 | $resized['file'], 337 | $atts['src'] 338 | ); 339 | 340 | // Let metadata know about our new size. 341 | wp_update_attachment_metadata( $att_id, $meta ); 342 | 343 | // Record in backup sizes, so everything's 344 | // cleaned up when attachment is deleted. 345 | $backup_sizes = get_post_meta( 346 | $att_id, 347 | '_wp_attachment_backup_sizes', 348 | true 349 | ); 350 | # 351 | // If an error occurred, we'll get back FALSE 352 | // By default it's not a single meta entry, so we 353 | // should get an array anyway. Unless WP_Cache went off. 354 | ! is_array( $backup_sizes ) AND $backup_sizes = array(); 355 | 356 | // Add the new image to the size meta data array. 357 | $backup_sizes[ $key ] = $resized; 358 | 359 | // Update the meta entry. 360 | update_post_meta( 361 | $att_id, 362 | '_wp_attachment_backup_sizes', 363 | $backup_sizes 364 | ); 365 | } 366 | } 367 | 368 | // Generate the markup and return: 369 | $html = $this->getMarkUp( 370 | $atts['src'], 371 | $hw_string, 372 | $atts['classes'] 373 | ); 374 | 375 | return $html; 376 | } 377 | 378 | /** 379 | * Setter for the base URL for the Attachment/Image directory. 380 | */ 381 | public function setBaseUrl() 382 | { 383 | $uploaddir = wp_upload_dir(); 384 | $this->baseUrl = $uploaddir['baseurl']; 385 | } 386 | 387 | /** 388 | * Get the Base URL 389 | * @return string 390 | */ 391 | public function getBaseUrl() 392 | { 393 | if ( !$this->baseUrl ) $this->setBaseUrl(); 394 | return $this->baseUrl; 395 | } 396 | 397 | /** 398 | * Sets the currently processed Attachment ID. 399 | * @param int $id 400 | */ 401 | public function setAttachmentID( $id ) 402 | { 403 | $this->att_id = $id; 404 | } 405 | 406 | /** 407 | * Gets the currently processed Attachment ID. 408 | * @return int|null 409 | */ 410 | public function getAttachmentID() 411 | { 412 | return $this->att_id; 413 | } 414 | 415 | /** 416 | * Sets the currently processed Attachment Meta Data. 417 | * Allows extending classes to retrieve the meta data 418 | * to display captions, credits, generate MarkUp for 419 | * responsive stuff, etc. Sky is the limit. 420 | * @param array $data 421 | */ 422 | public function setAttachmentMeta( $data ) 423 | { 424 | $this->att_meta = $data; 425 | } 426 | 427 | /** 428 | * Gets the currently processed Attachment Meta Data Array. 429 | * @return array 430 | */ 431 | public function getAttachmentMeta() 432 | { 433 | return $this->att_meta; 434 | } 435 | 436 | /** 437 | * Query for the file by URl 438 | * @param string $url 439 | * @return mixed string/bool $result Attachment or FALSE if nothing was found (needed for error) 440 | */ 441 | public function getAttachment( $url ) 442 | { 443 | global $wpdb; 444 | 445 | $result = $wpdb->get_var( $this->getAttachmentSQL( $url ) ); 446 | 447 | // FALSE if no result 448 | if ( empty( $result ) ) 449 | return false; 450 | 451 | return $result; 452 | } 453 | 454 | /** 455 | * Retrieves the SQL statement that is used to retrieve a single Attachment 456 | * @param string $url 457 | * @return string $sql 458 | */ 459 | public function getAttachmentSQL( $url ) 460 | { 461 | global $wpdb; 462 | 463 | if ( 464 | // Starting from WordPress 4.0 like_escape() is deprecated in favour of $wpdb->esc_like(). 465 | // By default use $wpdb->esc_like(), else fall back to like_escape(). 466 | method_exists( $wpdb, 'esc_like' ) 467 | ) 468 | { 469 | $url = $wpdb->prepare( "%s", "%".$wpdb->esc_like( $url )."%" ); 470 | } 471 | else 472 | { 473 | $url = $wpdb->prepare( "%s", "%".like_escape( $url )."%" ); 474 | } 475 | return <<postmeta} 478 | WHERE meta_key = '_wp_attachment_metadata' 479 | AND meta_value LIKE {$url} 480 | LIMIT 1 481 | SQL; 482 | } 483 | 484 | /** 485 | * Builds the markup 486 | * @param string $src URl to the image 487 | * @param string $hw_string 488 | * @param string $classes 489 | * @return string $html 490 | */ 491 | public function getMarkUp( $src, $hw_string, $classes ) 492 | { 493 | return sprintf( 494 | '', 495 | $src, 496 | $hw_string, 497 | ! empty( $classes ) ? " class='{$classes}'" : '' 498 | ); 499 | } 500 | } // END Class oxoDynamicImageResize 501 | 502 | 503 | /*********************************** 504 | * PUBLIC API 505 | ***********************************/ 506 | 507 | 508 | /** 509 | * Retrieve a dynamically/on-the-fly resized image 510 | * @param array $atts Attributes: src(URi/ID), width, height, classes 511 | * @return mixed string/html $html Image mark up 512 | */ 513 | function dynamic_image_resize( $atts ) 514 | { 515 | return new oxoDynamicImageResize( $atts ); 516 | } 517 | 518 | 519 | /** 520 | * Add a short code named [dynamic_image] 521 | * Use the same attributes as for the class 522 | * If the shortcode name changes, the third argument 523 | * for `shortcode_atts()` must change as well. 524 | */ 525 | add_shortcode( 'dynamic_image', 'dynamic_image_resize' ); 526 | 527 | } // endif; 528 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "wcm/dynamic-image-resize", 3 | "description" : "Enables WordPress custom image sizes on the fly. Can be used with a shortcode or a template tag.", 4 | "version" : "1.6.3", 5 | "homepage" : "http://franz-josef-kaiser.github.io/Dynamic-Image-Resize/", 6 | "main" : "dynamic_img_resize.php", 7 | "readmeFilename" : "README.md", 8 | "private" : false, 9 | "keywords" : [ 10 | "wordpress", 11 | "plugin", 12 | "responsive", 13 | "adaptive", 14 | "dynamic", 15 | "image", 16 | "resize" 17 | ], 18 | "repository" : { 19 | "type" : "git", 20 | "url" : "https://github.com/franz-josef-kaiser/Dynamic-Image-Resize" 21 | }, 22 | "author" : { 23 | "name" : "Franz Josef Kaiser", 24 | "email" : "wecodemore@gmail.com", 25 | "url" : "http://unserkaiser.com/" 26 | }, 27 | "licenses" : [ 28 | { 29 | "type" : "MIT", 30 | "url" : "http://www.tldrlegal.com/license/mit-license" 31 | } 32 | ], 33 | "engines" : { 34 | "node" : ">= 0.6.x" 35 | }, 36 | "scripts" : { 37 | "dist" : "", 38 | "postinstall" : "", 39 | "start" : "" 40 | } 41 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Dynamic Image resizing in WordPress 2 | 3 | version: _v1.6.3_ 4 | 5 | "Dynamic Image Resize" is a WordPress (MU-)plugin that offers a shortcode and a template tag to resize images "on the flight" without the need of TimThumb, but with WP core functions. 6 | 7 | Original Idea, Concept & Script by [Konstantin Kovshenin](http://kovshenin.com/2012/native-image-sizing-on-the-fly-with-wordpress/) 8 | 9 | License: extended MIT/Expat 10 | 11 | Known issues: none 12 | 13 | Visit *Franz Josef Kaiser* at [his homepage](http://unserkaiser.com) or get social on [Google+](https://plus.google.com/+FranzJosefKaiser) or [on Twitter](https://twitter.com/unserkaiser). 14 | 15 | ----- 16 | 17 | ## Updates 18 | 19 | If you are really not using Composer to keep your install up to date and don't have this plugin running as mu-plugin or included in your Theme, I recommend [using the GitHub plugin updater](https://github.com/afragen/github-updater). This plugin is compatible. 20 | 21 | ----- 22 | 23 | ## Dedicated Project Page 24 | 25 | For further info, please [visit the project page](http://franz-josef-kaiser.github.io/Dynamic-Image-Resize/). 26 | 27 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/franz-josef-kaiser/dynamic-image-resize/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 28 | --------------------------------------------------------------------------------