sizes="{{custom sizes value}}">
85 | ```
86 |
87 | ##### Note
88 |
89 | By default, the maximum width of images that are included in the `srcset` is 1600 pixels. You can override this default by adding a filter to `max_srcset_image_width`.
90 |
91 | ---
92 |
93 | #### Function wp_calculate_image_srcset
94 |
95 | `wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 )`
96 |
97 | A helper function to calculate the image sources to include in a `srcset` attribute.
98 |
99 | **Return:** (string|bool)
100 | The `srcset` attribute value. False on error or when only one source exists.
101 |
102 | ##### Parameters
103 |
104 | **$size_array** (array)
105 | Array of width and height values in pixels (in that order).
106 |
107 | **$image_src** (string)
108 | The `src` of the image.
109 |
110 | **$image_meta** (array)
111 | The image meta data as returned by `wp_get_attachment_metadata()`.
112 |
113 | **$attachment_id** (int)
114 | (Optional) Image attachment ID. Default 0.
115 |
116 | ##### Used by
117 |
118 | `wp_get_attachment_image_srcset()`
119 |
120 | ##### Usage Example
121 |
122 | ```
123 |
136 |
137 |
sizes="{{custom sizes value}}">
138 | ```
139 |
140 | ##### Note
141 |
142 | By default, the maximum width of images that are included in the `srcset` is 1600 pixels. You can override this default by adding a filter to `max_srcset_image_width`.
143 |
144 | ---
145 |
146 | #### Hook max_srcset_image_width
147 |
148 | `apply_filters( 'max_srcset_image_width', 1600, $size_array )`
149 |
150 | Filter the maximum image width to be included in a `srcset` attribute.
151 |
152 | ##### Parameters
153 |
154 | **$max_width** (int)
155 | The maximum image width to be included in the `srcset`. Default '1600'.
156 |
157 | **$size_array** (array)
158 | Array of width and height values in pixels (in that order).
159 |
160 | ##### Used by
161 |
162 | `wp_calculate_image_srcset()`
163 |
164 | ##### Usage Example
165 |
166 | ```
167 | 800 ) {
174 | $max_width = 2048;
175 | }
176 |
177 | return $max_width;
178 | }
179 | add_filter( 'max_srcset_image_width', 'custom_max_srcset_image_width', 10, 2 );
180 |
181 | ?>
182 | ```
183 |
184 | ---
185 |
186 | #### Hook wp_calculate_image_srcset
187 |
188 | `apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id )`
189 |
190 | Filter an image's `srcset` sources.
191 |
192 | ##### Parameters
193 |
194 | **$sources** (array)
195 | One or more arrays of source data to include in the `srcset`.
196 |
197 | ```
198 | $width (array) {
199 | $url (string) The URL of an image source.
200 | $descriptor (string) The descriptor type used in the image candidate string,
201 | either 'w' or 'x'.
202 | $value (int) The source width, if paired with a 'w' descriptor or a
203 | pixel density value if paired with an 'x' descriptor.
204 | }
205 | ```
206 |
207 | **$size_array** (array)
208 | Array of width and height values in pixels (in that order).
209 |
210 | **$image_src** (string)
211 | The `src` of the image.
212 |
213 | **$image_meta** (array)
214 | The image meta data as returned by `wp_get_attachment_metadata()`.
215 |
216 | **$attachment_id** (int)
217 | Image attachment ID or 0.
218 |
219 | ##### Used by
220 |
221 | `wp_calculate_image_srcset()`
222 |
223 | ##### Usage Example
224 |
225 | ```
226 | $source ) {
236 | if ( $source['value'] > 800 ) {
237 | unset( $sources[ $key ] );
238 | }
239 | }
240 | }
241 | }
242 |
243 | return $sources;
244 | }
245 | add_filter( 'wp_calculate_image_srcset', 'custom_wp_calculate_image_srcset', 10, 5 );
246 |
247 | ?>
248 | ```
249 |
250 | ---
251 |
252 | #### Function wp_get_attachment_image_sizes
253 |
254 | `wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null )`
255 |
256 | Retrieves the value for an image attachment's `sizes` attribute.
257 |
258 | **Return:** (string|bool)
259 | A valid source size value for use in a `sizes` attribute or false.
260 |
261 | ##### Parameters
262 |
263 | **$attachment_id** (int)
264 | Image attachment ID.
265 |
266 | **$size** (array|string)
267 | (Optional) Image size. Accepts any valid image size name ('thumbnail', 'medium', etc.), or an array of width and height values in pixels (in that order). Default 'medium'.
268 |
269 | **$image_meta** (array)
270 | (Optional) The image meta data as returned by `wp_get_attachment_metadata()`. Default null.
271 |
272 | ##### Uses
273 |
274 | `wp_calculate_image_sizes()`
275 |
276 | ##### Usage Example
277 |
278 | ```
279 |
283 |
284 |
srcset="{{custom srcset value}}">
285 | ```
286 |
287 | ##### Note
288 |
289 | By default, the sizes attribute will be declared as 100% of the viewport width when the viewport width is smaller than the width of the image, or to the width of the image itself when the viewport is larger than the image:
290 |
291 | `(max-width: {{image-width}}) 100vw, {{image-width}}`
292 |
293 | You can override this default by adding a filter to `wp_calculate_image_sizes`.
294 |
295 | ---
296 |
297 | #### Function wp_calculate_image_sizes
298 |
299 | `wp_calculate_image_sizes( $size, $image_src, $image_meta, $attachment_id = 0 )`
300 |
301 | Creates the `sizes` attribute value for an image.
302 |
303 | **Return:** (string|bool)
304 | A valid source size value for use in a `sizes` attribute or false.
305 |
306 | ##### Parameters
307 |
308 | **$size** (array|string)
309 | Image size. Accepts any valid image size name ('thumbnail', 'medium', etc.), or an array of width and height values in pixels (in that order).
310 |
311 | **$image_src** (string)
312 | (Optional) The URL to the image file. Default null.
313 |
314 | **$image_meta** (array)
315 | (Optional) The image meta data as returned by `wp_get_attachment_metadata()`. Default null.
316 |
317 | **$attachment_id** (int)
318 | (Optional) Image attachment ID. Default 0.
319 |
320 | Either `$image_meta` or `$attachment_id` is needed when using the image size name as argument for `$size`.
321 |
322 | ##### Used by
323 |
324 | `wp_get_attachment_image_sizes()`
325 |
326 | ##### Usage Example
327 |
328 | ```
329 |
333 |
334 |
srcset="{{custom srcset value}}">
335 | ```
336 |
337 | ##### Note
338 |
339 | By default, the sizes attribute will be declared as 100% of the viewport width when the viewport width is smaller than the width of the image, or to the width of the image itself when the viewport is larger than the image:
340 |
341 | `(max-width: {{image-width}}) 100vw, {{image-width}}`
342 |
343 | You can override this default by adding a filter to `wp_calculate_image_sizes`.
344 |
345 | ---
346 |
347 | #### Hook wp_calculate_image_sizes
348 |
349 | `apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id )`
350 |
351 | Filter the output of `wp_calculate_image_sizes()`.
352 |
353 | ##### Parameters
354 |
355 | **$sizes** (string)
356 | A source size value for use in a `sizes` attribute.
357 |
358 | **$size** (array|string)
359 | Requested size. Image size name or array of width and height values in pixels (in that order).
360 |
361 | **$image_src** (string|null)
362 | The URL to the image file or null.
363 |
364 | **$image_meta** (array|null)
365 | The image meta data as returned by `wp_get_attachment_metadata()` or null.
366 |
367 | **$attachment_id** (int)
368 | Image attachment ID of the original image or 0.
369 |
370 | ##### Used by
371 |
372 | `wp_calculate_image_sizes()`
373 |
374 | ##### Usage Example
375 |
376 | ```
377 | $content_width ) {
386 | $upload_dir = wp_upload_dir();
387 | $upload_baseurl = $upload_dir['baseurl'];
388 | $fullsize_file = $image_meta['file'];
389 | $fullsize_url = trailingslashit( $upload_baseurl ) . $fullsize_file;
390 |
391 | if ( $image_src === $fullsize_url ) {
392 | $sizes = '(max-width: ' . $content_width . 'px) 100vw, ' . $content_width . 'px';
393 | }
394 | }
395 | }
396 |
397 | return $sizes;
398 | }
399 | add_filter( 'wp_calculate_image_sizes', 'custom_wp_calculate_image_sizes', 10, 5 );
400 |
401 | ?>
402 | ```
403 |
404 | ---
405 |
406 | ### Backward Compatibility
407 |
408 | The following filters are used for backward compatibility. If the described case is not applicable you may want to remove the filter from its hook.
409 |
410 | #### data-sizes
411 |
412 | Prior to version 2.5 a `srcset` and `data-sizes` attribute were added to the image while inserting the image in the content and we used a content filter to replace `data-sizes` by `sizes`. As from 2.5 both `srcset` and `sizes` are added to images using a content filter, but images that already have a `srcset` attribute are skipped. For this reason we still replace `data-sizes` by `sizes`.
413 | If you did not use the plugin before version 2.5 or if you have removed `data-sizes` from your content you can remove the filter:
414 |
415 | ```
416 | remove_filter( 'the_content', 'tevkori_replace_data_sizes' );
417 | ```
418 |
419 | #### tevkori_get_sizes() $args param and filter
420 |
421 | The deprecated function `tevkori_get_sizes()` had an `$args` param and a `tevkori_image_sizes_args` filter. To make those still work we added a shim. If you do not use `tevkori_get_sizes()` in your templates, or at least not pass an argument to the `$args` param, and if you don't use the deprecated `tevkori_image_sizes_args` filter hook, you can remove the filter:
422 |
423 | ```
424 | remove_filter( 'wp_calculate_image_sizes', '_tevkori_image_sizes_args_shim', 1, 5 );
425 | ```
426 |
427 | #### wp_get_attachment_image_sizes filter
428 |
429 | In version 3.0 we introduced a new filter: `wp_get_attachment_image_sizes`. In version 3.1 this has been replaced by `wp_calculate_image_sizes`. If you don't use the `wp_get_attachment_image_sizes` filter you can remove the filter that has been added for backward compatibility:
430 |
431 | ```
432 | remove_filter( 'wp_calculate_image_sizes', 'wp_get_attachment_image_sizes_filter_shim', 10, 5 );
433 | ```
434 |
435 | ---
436 |
437 | ### Dependencies
438 |
439 | The only external dependency included in this plugin is [Picturefill](http://scottjehl.github.io/picturefill/) - v3.0.1. If you would like to remove Picturefill (see notes about [browser support](http://scottjehl.github.io/picturefill/#support)), add the following to your functions.php file:
440 |
441 | function mytheme_dequeue_scripts() {
442 | wp_dequeue_script('picturefill');
443 | }
444 |
445 | add_action('wp_enqueue_scripts', 'mytheme_dequeue_scripts');
446 |
447 | We use a hook because if you attempt to dequeue a script before it's enqueued, wp_dequeue_script has no effect. (If it's still being loaded, you may need to specify a [priority](http://codex.wordpress.org/Function_Reference/add_action).)
448 |
449 | ## Version
450 |
451 | 3.1.1
452 |
453 | ## Changelog
454 |
455 | **3.1.1**
456 |
457 | - Fixes a bug where the srcset of images in imported content was missing or broken (issue #263).
458 | - Improved calculation of ratio difference for images to be included in the srcset. (issue #260).
459 | - Fixes a bug where `img` tags without ending slash don't get responsive images (issue #259).
460 | - Deprecates the helper function `tevkori_get_media_embedded_in_content()` which is no longer used.
461 | - Makes sure that the setup of default themes doesn't break the tests (issue #261).
462 | - Adds more examples to the Hook Reference in readme.md.
463 | - Corrections and improvements to inline documentation.
464 |
465 | **3.1.0**
466 |
467 | - Adds special handling of GIFs in srcset attributes to preserve animation (issue #223).
468 | - Makes internal srcset/sizes functions more consistent (issue #224).
469 | - Fixes a bug where functions hooked into `tevkori_image_sizes_args` were not firing (issue #226).
470 | - Fixes a bug where custom sizes attributes added via the post editor were being overwritten (issue #227).
471 | - Deprecates hook `wp_get_attachment_image_sizes` (issue #228).
472 | - Fixes a bug where `the_post_thumbnail()` would fail to add srcset/sizes attributes (issue #232).
473 | - Several improvements to internal inline documentation.
474 | - Major improvements to function/hook documentation in readme.md after 3.0.0 changes.
475 |
476 | **3.0.0**
477 |
478 | - Deprecates all core functions that will be merged into WordPress core in 4.4.
479 | - Adds compatibility shims for sites using the plugin's internal functions and hooks.
480 | - Adds a new display filter callback which can be use as general utility function for adding srcset and sizes attributes.
481 | - Fixes a bug when `wp_get_attachment_metadata()` failed to return an array.
482 | - Update our tests to be compatible with WordPress 4.4
483 | - Upgrade to Picturefill 3.0.1
484 | - Clean up inline docs.
485 |
486 | **2.5.2**
487 |
488 | - Numerous performance and usability improvements
489 | - Pass height and width to `tevkori_get_sizes()`
490 | - Improved regex in display filter
491 | - Avoid calling `wp_get_attachment_image_src()` in srcset functions
492 | - Improved coding standards
493 | - Removed second regular expression in content filter
494 | - Improved cache warning function
495 | - Change default `$size` value for all functions to 'medium'
496 |
497 | **2.5.1**
498 |
499 | - Query all images in single request before replacing
500 | - Minor fix to prevent a potential undefined variable notice
501 | - Remove third fallback query from the display filter
502 |
503 | **2.5.0**
504 |
505 | - Responsify all post images by adding `srcset` and `sizes` through a display filter.
506 | - Improve method used to build paths in `tevkori_get_srcset_array()`
507 | - Added Linthub config files
508 | - Returns single source arrays in `tevkori_get_srcset_array()`
509 | - Add tests for PHP7 to our Travis matrix
510 | - Add test coverage for `tevkori_filter_attachment_image_attributes()`
511 |
512 | **2.4.0**
513 |
514 | - Added filter for `tevkori_get_sizes`, with tests
515 | - Added Composer support
516 | - Compare aspect ratio in relative values, not absolute values
517 | - Cleanup of code style and comments added
518 | - Added PHP 5.2 to our Travis test matrix
519 | - Fixed unit test loading
520 | - Preventing duplicates in srcset array
521 | - Updated docs for advanced image compression
522 | - Formatting cleanup in readme.md
523 | - Bump plugin 'Tested up to:' value to 4.3
524 | - Remove extra line from readme.txt
525 | - Added changelog items from 2.3.1 to the readme.txt file
526 | - Added 'sudo: false' to travis.ci to use new TravisCI infrastructure
527 | - Removing the srcset and sizes attributes if there is only one source present for the image
528 | - Use edited image hash to filter out originals from edited images
529 | - Make output of `tevkori_get_srcset_array` filterable
530 |
531 | **2.3.1**
532 |
533 | - First char no longer stripped from file name if there's no slash
534 | - Adding test for when uploads directory not organized by date
535 | - Don't calculate a srcset when the image data returns no width
536 | - Add test for image_downsize returning 0 as a width
537 |
538 | **2.3.0**
539 |
540 | - Improved performance of `get_srcset_array`
541 | - Added advanced image compression option (available by adding hook to functions.php)
542 | - Duplicate entires now filtered out from srcset array
543 | - Upgrade Picturefill to 2.3.1
544 | - Refactoring plugin JavaScript, including a switch to ajax for updating the srcset value when the image is changed in the editor
545 | - Now using `wp_get_attachment_image_attributes` filter for post thumbnails
546 | - Readme and other general code typo fixes
547 | - Gallery images will now contain a srcset attribute
548 |
549 | **2.2.1**
550 |
551 | - JavaScript patch for WordPress
552 |
553 | **2.2.0**
554 |
555 | - The mandatory sizes attribute is now included on all images
556 | - Updated to Picturefill v2.3.0
557 | - Extensive documentation included in readme
558 | - Integrated testing with Travis CLI
559 | - Check if wp.media exists before running JavaScript
560 | - Account for rounding variance when matching ascpect ratios
561 |
562 | **2.1.1**
563 |
564 | - Adding in wp-tevko-responsive-images.js after file not found to be in WordPress repository
565 | - Adjusts the aspect ratio check in `tevkori_get_srcset_array()` to account for rounding variance
566 |
567 | **2.1.0**
568 |
569 | - **This version introduces a breaking change**: There are now two functions. One returns an array of srcset values, and the other returns a string with the `srcset=".."` html needed to generate the responsive image. To retrieve the srcset array, use `tevkori_get_srcset_array( $id, $size )`
570 | - When the image size is changed in the post editor, the srcset values will adjust to match the change.
571 |
572 | **2.0.2**
573 |
574 | - A bugfix correcting a divide by zero error. Some users may have seen this after upgrading to 2.0.1
575 |
576 | **2.0.1**
577 |
578 | - Only outputs the default WordPress sizes, giving theme developers the option to extend as needed
579 | - Added support for featured images
580 |
581 | **2.0.0**
582 |
583 | - Uses [Picturefill 2.2.0 (Beta)](http://scottjehl.github.io/picturefill/)
584 | - Scripts are output to footer
585 | - Image sizes adjusted
586 | - Most importantly, the srcset syntax is being used
587 | - The structure of the plugin is significantly different. The plugin now works by extending the default WordPress image tag functionality to include the srcset attribute.
588 | - Works for cropped images!
589 | - Backwards compatible (images added before plugin install will still be responsive)!
590 |
--------------------------------------------------------------------------------
/tests/test-suite.php:
--------------------------------------------------------------------------------
1 | basename( $upload['file'] ),
40 | 'post_content' => '',
41 | 'post_type' => 'attachment',
42 | 'post_parent' => $parent,
43 | 'post_mime_type' => $type,
44 | 'guid' => $upload[ 'url' ],
45 | );
46 |
47 | // Save the data.
48 | $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $parent );
49 | wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
50 |
51 | return $id;
52 | }
53 |
54 | /* OUR TESTS */
55 |
56 | /**
57 | * @expectedDeprecated tevkori_get_srcset_array
58 | */
59 | function test_tevkori_get_srcset_array() {
60 | global $_wp_additional_image_sizes;
61 |
62 | // Make an image.
63 | $id = self::$large_id;
64 | $srcset = tevkori_get_srcset_array( $id, 'medium' );
65 |
66 | $year_month = date('Y/m');
67 | $image_meta = wp_get_attachment_metadata( $id );
68 |
69 | $intermediates = array( 'medium', 'medium_large', 'large', 'full' );
70 |
71 | // Add any soft crop intermediate sizes.
72 | foreach ( $_wp_additional_image_sizes as $name => $additional_size ) {
73 | if ( ! $_wp_additional_image_sizes[$name]['crop'] || 0 === $_wp_additional_image_sizes[$name]['height'] ) {
74 | $intermediates[] = $name;
75 | }
76 | }
77 |
78 | foreach( $image_meta['sizes'] as $name => $size ) {
79 | // Whitelist the sizes that should be included so we pick up 'medium_large' in 4.4.
80 | if ( in_array( $name, $intermediates ) ) {
81 | $expected[$size['width']] = 'http://example.org/wp-content/uploads/' . $year_month = date('Y/m') . '/' . $size['file'] . ' ' . $size['width'] . 'w';
82 | }
83 | }
84 |
85 | // Add the full size width at the end.
86 | $expected[$image_meta['width']] = 'http://example.org/wp-content/uploads/' . $image_meta['file'] . ' ' . $image_meta['width'] .'w';
87 |
88 | $this->assertSame( $expected, $srcset );
89 | }
90 |
91 | /**
92 | * A test filter for tevkori_get_srcset_array() that removes any sources
93 | * that are larger than 500px wide.
94 | */
95 | function _test_tevkori_srcset_array( $array ) {
96 | foreach ( $array as $size => $file ) {
97 | if ( $size > 500 ) {
98 | unset( $array[ $size ] );
99 | }
100 | }
101 | return $array;
102 | }
103 |
104 | /**
105 | * @expectedDeprecated tevkori_get_srcset_array
106 | * @expectedException PHPUnit_Framework_Error_Notice
107 | */
108 | function test_filter_tevkori_srcset_array() {
109 | // Add test filter.
110 | add_filter( 'tevkori_srcset_array', array( $this, '_test_tevkori_srcset_array' ) );
111 |
112 | // Set up our test.
113 | $id = self::$large_id;
114 | $srcset = tevkori_get_srcset_array( $id, 'medium' );
115 |
116 | // Evaluate that the sizes returned is what we expected.
117 | foreach( $srcset as $width => $source ) {
118 | $this->assertTrue( $width <= 500 );
119 | }
120 |
121 | // Remove test filter.
122 | remove_filter( 'tevkori_srcset_array', array( $this, '_test_tevkori_srcset_array' ) );
123 | }
124 |
125 | /**
126 | * @expectedDeprecated tevkori_get_srcset_array
127 | */
128 | function test_tevkori_get_srcset_array_false() {
129 | // Make an image.
130 | $id = self::$large_id;
131 | $srcset = tevkori_get_srcset_array( 99999, 'foo' );
132 |
133 | // For canola.jpg we should return.
134 | $this->assertFalse( $srcset );
135 | }
136 |
137 | /**
138 | * @expectedDeprecated tevkori_get_srcset_array
139 | */
140 | function test_tevkori_get_srcset_array_random_size_name() {
141 | global $_wp_additional_image_sizes;
142 |
143 | // Make an image.
144 | $id = self::$large_id;
145 | $srcset = tevkori_get_srcset_array( $id, 'foo' );
146 |
147 | $year_month = date('Y/m');
148 | $image_meta = wp_get_attachment_metadata( $id );
149 |
150 | $intermediates = array( 'medium', 'medium_large', 'large', 'full' );
151 |
152 | // Add any soft crop intermediate sizes.
153 | foreach ( $_wp_additional_image_sizes as $name => $additional_size ) {
154 | if ( ! $_wp_additional_image_sizes[$name]['crop'] || 0 === $_wp_additional_image_sizes[$name]['height'] ) {
155 | $intermediates[] = $name;
156 | }
157 | }
158 |
159 | foreach( $image_meta['sizes'] as $name => $size ) {
160 | // Whitelist the sizes that should be included so we pick up 'medium_large' in 4.4.
161 | if ( in_array( $name, $intermediates ) ) {
162 | $expected[$size['width']] = 'http://example.org/wp-content/uploads/' . $year_month = date('Y/m') . '/' . $size['file'] . ' ' . $size['width'] . 'w';
163 | }
164 | }
165 |
166 | // Add the full size width at the end.
167 | $expected[$image_meta['width']] = 'http://example.org/wp-content/uploads/' . $image_meta['file'] . ' ' . $image_meta['width'] .'w';
168 |
169 | $this->assertSame( $expected, $srcset );
170 | }
171 |
172 | /**
173 | * @expectedDeprecated tevkori_get_srcset_array
174 | */
175 | function test_tevkori_get_srcset_array_no_date_upoads() {
176 | global $_wp_additional_image_sizes;
177 |
178 | // Save the current setting for uploads folders.
179 | $uploads_use_yearmonth_folders = get_option( 'uploads_use_yearmonth_folders' );
180 |
181 | // Disable date organized uploads.
182 | update_option( 'uploads_use_yearmonth_folders', 0 );
183 |
184 | // Make an image.
185 | $id = self::create_upload_object( self::$test_file_name );
186 | $srcset = tevkori_get_srcset_array( $id, 'medium' );
187 | $image_meta = wp_get_attachment_metadata( $id );
188 |
189 | $intermediates = array( 'medium', 'medium_large', 'large', 'full' );
190 |
191 | // Add any soft crop intermediate sizes.
192 | foreach ( $_wp_additional_image_sizes as $name => $additional_size ) {
193 | if ( ! $_wp_additional_image_sizes[$name]['crop'] || 0 === $_wp_additional_image_sizes[$name]['height'] ) {
194 | $intermediates[] = $name;
195 | }
196 | }
197 |
198 | foreach( $image_meta['sizes'] as $name => $size ) {
199 | // Whitelist the sizes that should be included so we pick up 'medium_large' in 4.4.
200 | if ( in_array( $name, $intermediates ) ) {
201 | $expected[$size['width']] = 'http://example.org/wp-content/uploads/' . $size['file'] . ' ' . $size['width'] . 'w';
202 | }
203 | }
204 |
205 | // Add the full size width at the end.
206 | $expected[$image_meta['width']] = 'http://example.org/wp-content/uploads/' . $image_meta['file'] . ' ' . $image_meta['width'] .'w';
207 |
208 | $this->assertSame( $expected, $srcset );
209 |
210 | // Leave the uploads option the way you found it.
211 | update_option( 'uploads_use_yearmonth_folders', $uploads_use_yearmonth_folders );
212 | }
213 |
214 | /**
215 | * @expectedDeprecated tevkori_get_srcset
216 | * @expectedDeprecated tevkori_get_srcset_array
217 | */
218 | function test_tevkori_get_srcset_single_srcset() {
219 | // Make an image.
220 | $id = self::$large_id;
221 | /*
222 | * In our tests, thumbnails would only return a single srcset candidate,
223 | * in which case we don't bother returning a srcset array.
224 | */
225 | $this->assertTrue( 1 === count( tevkori_get_srcset_array( $id, 'thumbnail' ) ) );
226 | $this->assertFalse( tevkori_get_srcset( $id, 'thumbnail' ) );
227 | }
228 |
229 | /**
230 | * Test for filtering out leftover sizes after an image is edited.
231 | * @group 155
232 | * @expectedDeprecated tevkori_get_srcset_array
233 | */
234 | function test_tevkori_get_srcset_array_with_edits() {
235 | // Make an image.
236 | $id = self::$large_id;
237 |
238 | /*
239 | * For this test we're going to mock metadata changes from an edit.
240 | * Start by getting the attachment metadata.
241 | */
242 | $meta = wp_get_attachment_metadata( $id );
243 |
244 | // Mimick hash generation method used in wp_save_image().
245 | $hash = 'e' . time() . rand( 100, 999 );
246 |
247 | // Replace file paths for full and medium sizes with hashed versions.
248 | $filename_base = basename( $meta['file'], '.png' );
249 | $meta['file'] = str_replace( $filename_base, $filename_base . '-' . $hash, $meta['file'] );
250 | $meta['sizes']['medium']['file'] = str_replace( $filename_base, $filename_base . '-' . $hash, $meta['sizes']['medium']['file'] );
251 |
252 | // Save edited metadata.
253 | wp_update_attachment_metadata( $id, $meta );
254 |
255 | // Get the edited image and observe that a hash was created.
256 | $img_url = wp_get_attachment_url( $id );
257 |
258 | // Calculate a srcset array.
259 | $srcset = tevkori_get_srcset_array( $id, 'medium' );
260 |
261 | // Test to confirm all sources in the array include the same edit hash.
262 | foreach ( $srcset as $source ) {
263 | $this->assertTrue( false !== strpos( $source, $hash ) );
264 | }
265 | }
266 |
267 | /**
268 | * Helper function to filter image_downsize and return zero values for width and height.
269 | */
270 | public function _filter_image_downsize( $out, $id, $size ) {
271 | $img_url = wp_get_attachment_url( $id );
272 | return array( $img_url, 0, 0 );
273 | }
274 |
275 | /**
276 | * @expectedDeprecated tevkori_get_srcset_array
277 | */
278 | function test_tevkori_get_srcset_array_no_width() {
279 | // Filter image_downsize() output.
280 | add_filter( 'image_downsize', array( $this, '_filter_image_downsize' ), 10, 3 );
281 |
282 | // Make our attachment.
283 | $id = self::create_upload_object( self::$test_file_name );
284 | $srcset = tevkori_get_srcset_array( $id, 'medium' );
285 |
286 | // The srcset should be false.
287 | $this->assertFalse( $srcset );
288 |
289 | // Remove filter.
290 | remove_filter( 'image_downsize', array( $this, '_filter_image_downsize' ) );
291 | }
292 |
293 | function test_wp_calculate_image_srcset_ratio_variance() {
294 | // Mock data for this test.
295 | $size_array = array( 218, 300);
296 | $image_src = 'http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/2015/12/test-768x1055-218x300.png';
297 | $image_meta = array(
298 | 'width' => 768,
299 | 'height' => 1055,
300 | 'file' => '2015/12/test-768x1055.png',
301 | 'sizes' => array(
302 | 'thumbnail' => array(
303 | 'file' => 'test-768x1055-150x150.png',
304 | 'width' => 150,
305 | 'height' => 150,
306 | 'mime-type' => 'image/png',
307 | ),
308 | 'medium' => array(
309 | 'file' => 'test-768x1055-218x300.png',
310 | 'width' => 218,
311 | 'height' => 300,
312 | 'mime-type' => 'image/png',
313 | ),
314 | 'custom-600' => array(
315 | 'file' => 'test-768x1055-600x824.png',
316 | 'width' => 600,
317 | 'height' => 824,
318 | 'mime-type' => 'image/png',
319 | ),
320 | 'post-thumbnail' => array(
321 | 'file' => 'test-768x1055-768x510.png',
322 | 'width' => 768,
323 | 'height' => 510,
324 | 'mime-type' => 'image/png',
325 | ),
326 | ),
327 | );
328 |
329 | $expected_srcset = 'http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/2015/12/test-768x1055-218x300.png 218w, http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/2015/12/test-768x1055-600x824.png 600w, http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/2015/12/test-768x1055.png 768w';
330 |
331 | $this->assertSame( $expected_srcset, wp_calculate_image_srcset( $size_array, $image_src, $image_meta ) );
332 | }
333 |
334 | /**
335 | * @expectedDeprecated tevkori_get_srcset_string
336 | */
337 | function test_tevkori_get_srcset_string() {
338 | global $_wp_additional_image_sizes;
339 |
340 | // Make an image.
341 | $id = self::$large_id;
342 |
343 | $srcset = tevkori_get_srcset_string( $id, 'full' );
344 | $image_meta = wp_get_attachment_metadata( $id );
345 | $year_month = date('Y/m');
346 |
347 | $intermediates = array( 'medium', 'medium_large', 'large', 'full' );
348 |
349 | // Add any soft crop intermediate sizes.
350 | foreach ( $_wp_additional_image_sizes as $name => $additional_size ) {
351 | if ( ! $_wp_additional_image_sizes[$name]['crop'] || 0 === $_wp_additional_image_sizes[$name]['height'] ) {
352 | $intermediates[] = $name;
353 | }
354 | }
355 |
356 | $expected = '';
357 |
358 | foreach( $image_meta['sizes'] as $name => $size ) {
359 | // Whitelist the sizes that should be included so we pick up 'medium_large' in 4.4.
360 | if ( in_array( $name, $intermediates ) ) {
361 | $expected .= 'http://example.org/wp-content/uploads/' . $year_month = date('Y/m') . '/' . $size['file'] . ' ' . $size['width'] . 'w, ';
362 | }
363 | }
364 | // Add the full size width at the end.
365 | $expected .= 'http://example.org/wp-content/uploads/' . $image_meta['file'] . ' ' . $image_meta['width'] .'w';
366 |
367 | $expected = sprintf( 'srcset="%s"', $expected );
368 |
369 | $this->assertSame( $expected, $srcset );
370 | }
371 |
372 | /**
373 | * @expectedDeprecated tevkori_get_sizes
374 | */
375 | function test_tevkori_get_sizes() {
376 | // Make an image.
377 | $id = self::$large_id;
378 |
379 | global $content_width;
380 |
381 | // Test sizes against the default WP sizes.
382 | $intermediates = array( 'thumbnail', 'medium', 'large' );
383 |
384 | // Make sure themes aren't filtering the sizes array.
385 | remove_all_filters( 'wp_calculate_image_sizes' );
386 |
387 | foreach( $intermediates as $int ) {
388 | $width = get_option( $int . '_size_w' );
389 |
390 | $width = ( $width <= $content_width ) ? $width : $content_width;
391 |
392 | $expected = '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
393 | $sizes = tevkori_get_sizes( $id, $int );
394 |
395 | $this->assertSame( $expected, $sizes );
396 | }
397 | }
398 |
399 | /**
400 | * @group 226
401 | * @expectedDeprecated tevkori_get_sizes
402 | */
403 | function test_tevkori_get_sizes_with_args() {
404 | // Make an image.
405 | $id = self::$large_id;
406 |
407 | $args = array(
408 | 'sizes' => array(
409 | array(
410 | 'size_value' => '10em',
411 | 'mq_value' => '60em',
412 | 'mq_name' => 'min-width'
413 | ),
414 | array(
415 | 'size_value' => '20em',
416 | 'mq_value' => '30em',
417 | 'mq_name' => 'min-width'
418 | ),
419 | array(
420 | 'size_value' => 'calc(100vw - 30px)'
421 | ),
422 | )
423 | );
424 |
425 | $expected = '(min-width: 60em) 10em, (min-width: 30em) 20em, calc(100vw - 30px)';
426 | $sizes = tevkori_get_sizes( $id, 'medium', $args );
427 |
428 | $this->assertSame( $expected, $sizes );
429 | }
430 |
431 | /**
432 | * A simple test filter for tevkori_get_sizes().
433 | */
434 | function _test_tevkori_image_sizes_args( $args ) {
435 | $args['sizes'] = "100vw";
436 | return $args;
437 | }
438 |
439 | /**
440 | * @group 226
441 | * @expectedDeprecated tevkori_get_sizes
442 | * @expectedException PHPUnit_Framework_Error_Notice
443 | */
444 | function test_filter_tevkori_get_sizes() {
445 | // Add our test filter.
446 | add_filter( 'tevkori_image_sizes_args', array( $this, '_test_tevkori_image_sizes_args' ) );
447 |
448 | // Set up our test.
449 | $id = self::$large_id;
450 | $sizes = tevkori_get_sizes($id, 'medium');
451 |
452 | // Evaluate that the sizes returned is what we expected.
453 | $this->assertSame( $sizes, '100vw' );
454 |
455 | remove_filter( 'tevkori_image_sizes_args', array( $this, '_test_tevkori_image_sizes_args' ) );
456 | }
457 |
458 | /**
459 | * @group 226
460 | * @expectedException PHPUnit_Framework_Error_Notice
461 | */
462 | function test_filter_shim_calculate_image_sizes() {
463 | // Add our test filter.
464 | add_filter( 'tevkori_image_sizes_args', array( $this, '_test_tevkori_image_sizes_args' ) );
465 |
466 | // A size array is the min required data for `wp_calculate_image_sizes()`.
467 | $size = array( 300, 150 );
468 | $sizes = wp_calculate_image_sizes( $size, null, null );
469 |
470 | // Evaluate that the sizes returned is what we expected.
471 | $this->assertSame( $sizes, '100vw' );
472 |
473 | remove_filter( 'tevkori_image_sizes_args', array( $this, '_test_tevkori_image_sizes_args' ) );
474 | }
475 |
476 | /**
477 | * @expectedDeprecated tevkori_get_sizes
478 | * @expectedDeprecated tevkori_get_sizes_string
479 | */
480 | function test_tevkori_get_sizes_string() {
481 | // Make an image.
482 | $id = self::$large_id;
483 |
484 | $sizes = tevkori_get_sizes( $id, 'medium' );
485 | $sizes_string = tevkori_get_sizes_string( $id, 'medium' );
486 |
487 | $expected = 'sizes="' . $sizes . '"';
488 |
489 | $this->assertSame( $expected, $sizes_string );
490 | }
491 |
492 | /**
493 | * @group 170
494 | */
495 | function test_wp_make_content_images_responsive() {
496 | // Make an image.
497 | $image_meta = wp_get_attachment_metadata( self::$large_id );
498 | $size_array = array( $image_meta['sizes']['medium']['width'], $image_meta['sizes']['medium']['height'] );
499 |
500 | $srcset = sprintf( 'srcset="%s"', esc_attr( wp_get_attachment_image_srcset( self::$large_id, 'medium', $image_meta ) ) );
501 | $sizes = sprintf( 'sizes="%s"', esc_attr( wp_get_attachment_image_sizes( self::$large_id, 'medium', $image_meta ) ) );
502 |
503 | // Function used to build HTML for the editor.
504 | $img = get_image_tag( self::$large_id, '', '', '', 'medium' );
505 | $img_no_size_in_class = str_replace( 'size-', '', $img );
506 | $img_no_width_height = str_replace( ' width="' . $size_array[0] . '"', '', $img );
507 | $img_no_width_height = str_replace( ' height="' . $size_array[1] . '"', '', $img_no_width_height );
508 | $img_no_size_id = str_replace( 'wp-image-', 'id-', $img );
509 | $img_with_sizes_attr = str_replace( 'Image, standard. Should have srcset and sizes.
523 | %1$s 524 | 525 |Image, no size class. Should have srcset and sizes.
526 | %2$s 527 | 528 |Image, no width and height attributes. Should have srcset and sizes (from matching the file name).
529 | %3$s 530 | 531 |Image, no attachment ID class. Should NOT have srcset and sizes.
532 | %4$s 533 | 534 |Image, with sizes attribute. Should NOT have two sizes attributes.
535 | %5$s 536 | 537 |Image, XHTML 1.0 style (no space before the closing slash). Should have srcset and sizes.
538 | %6$s 539 | 540 |Image, HTML 5.0 style. Should have srcset and sizes.
541 | %7$s'; 542 | 543 | $content_unfiltered = sprintf( $content, $img, $img_no_size_in_class, $img_no_width_height, $img_no_size_id, $img_with_sizes_attr, $img_xhtml, $img_html5 ); 544 | $content_filtered = sprintf( $content, $respimg, $respimg_no_size_in_class, $respimg_no_width_height, $img_no_size_id, $respimg_with_sizes_attr, $respimg_xhtml, $respimg_html5 ); 545 | 546 | $this->assertSame( $content_filtered, wp_make_content_images_responsive( $content_unfiltered ) ); 547 | } 548 | 549 | /** 550 | * When rendering attributes for responsive images, 551 | * we rely on the 'wp-image-*' class to find the image by ID. 552 | * The class name may not be consistent with attachment IDs in DB when 553 | * working with imported content or when a user has edited 554 | * the 'src' attribute manually. To avoid incorrect images 555 | * being displayed, ensure we don't add attributes in this case. 556 | */ 557 | function test_wp_make_content_images_responsive_wrong() { 558 | $image = get_image_tag( self::$large_id, '', '', '', 'medium' ); 559 | 560 | // Replace the src URL. 561 | $image_wrong_src = preg_replace( '|src="[^"]+"|', 'src="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/foo.jpg"', $image ); 562 | 563 | $this->assertSame( $image_wrong_src, wp_make_content_images_responsive( $image_wrong_src ) ); 564 | } 565 | 566 | /** 567 | * @group 170 568 | * @expectedDeprecated tevkori_filter_content_images 569 | */ 570 | function test_tevkori_filter_content_images_with_preexisting_srcset() { 571 | // Make an image. 572 | $id = self::$large_id; 573 | 574 | // Generate HTML and add a dummy srcset attribute. 575 | $image_html = get_image_tag( $id, '', '', '', 'medium' ); 576 | $image_html = preg_replace('|Image, http: protocol. Should have srcset and sizes.
698 | %1$s 699 | 700 |Image, http: protocol. Should have srcset and sizes.
701 | %2$s 702 | 703 |Image, protocol-relative. Should have srcset and sizes.
704 | %3$s'; 705 | 706 | $unfiltered = sprintf( $content, $img, $img_https, $img_relative ); 707 | $expected = sprintf( $content, $respimg, $respimg_https, $respimg_relative ); 708 | $actual = wp_make_content_images_responsive( $unfiltered ); 709 | 710 | $this->assertSame( $expected, $actual ); 711 | } 712 | } 713 | --------------------------------------------------------------------------------