Make WordPress Core

Ticket #35725: 35725.23.diff

File 35725.23.diff, 28.7 KB (added by adamsilverstein, 4 years ago)
  • src/wp-admin/includes/image-edit.php

    diff --git src/wp-admin/includes/image-edit.php src/wp-admin/includes/image-edit.php
    index 0430dbefbf..942dffb2e8 100644
    function wp_stream_image( $image, $mime_type, $attachment_id ) { 
    306306                        case 'image/gif':
    307307                                header( 'Content-Type: image/gif' );
    308308                                return imagegif( $image );
     309                        case 'image/webp':
     310                                if ( function_exists( 'imagewebp' ) ) {
     311                                        header( 'Content-Type: image/webp' );
     312                                        return imagewebp( $image, null, 90 );
     313                                }
     314                                return false;
    309315                        default:
    310316                                return false;
    311317                }
    function wp_save_image_file( $filename, $image, $mime_type, $post_id ) { 
    391397                                return imagepng( $image, $filename );
    392398                        case 'image/gif':
    393399                                return imagegif( $image, $filename );
     400                        case 'image/webp':
     401                                if ( function_exists( 'imagewebp' ) ) {
     402                                        /**
     403                                         * Filters the WebP compression quality for image file saves.
     404                                         *
     405                                         * @since 5.8.0
     406                                         *
     407                                         * @param int    $quality Quality level between 0 (low) and 100 (high) of the WebP.
     408                                         */
     409                                        return imagewebp( $image, null, apply_filters( 'webp_quality', 75 ) );
     410                                }
     411                                return false;
    394412                        default:
    395413                                return false;
    396414                }
  • src/wp-admin/includes/image.php

    diff --git src/wp-admin/includes/image.php src/wp-admin/includes/image.php
    index 673c1dff01..142c245f89 100644
    function wp_generate_attachment_metadata( $attachment_id, $file ) { 
    517517                                case 'image/png':
    518518                                        $ext = '.png';
    519519                                        break;
     520                                case 'image/webp':
     521                                        $ext = '.webp';
     522                                        break;
    520523                        }
    521524                        $basename = str_replace( '.', '-', wp_basename( $file ) ) . '-image' . $ext;
    522525                        $uploaded = wp_upload_bits( $basename, '', $metadata['image']['data'] );
    function file_is_valid_image( $path ) { 
    913916 * @return bool True if suitable, false if not suitable.
    914917 */
    915918function file_is_displayable_image( $path ) {
    916         $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO );
     919        $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound
    917920
    918921        $info = wp_getimagesize( $path );
    919922        if ( empty( $info ) ) {
    function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) { 
    963966                case 'image/gif':
    964967                        $image = imagecreatefromgif( $filepath );
    965968                        break;
     969                case 'image/webp':
     970                        $image = false;
     971                        if ( function_exists( 'imagecreatefromwebp' ) ) {
     972                                $image = imagecreatefromwebp( $filepath );
     973                        }
     974                        break;
    966975                default:
    967976                        $image = false;
    968977                        break;
  • src/wp-admin/includes/media.php

    diff --git src/wp-admin/includes/media.php src/wp-admin/includes/media.php
    index 14a8d99b49..bdfb65d103 100644
    function wp_media_upload_handler() { 
    993993function media_sideload_image( $file, $post_id = 0, $desc = null, $return = 'html' ) {
    994994        if ( ! empty( $file ) ) {
    995995
    996                 $allowed_extensions = array( 'jpg', 'jpeg', 'jpe', 'png', 'gif' );
     996                $allowed_extensions = array( 'jpg', 'jpeg', 'jpe', 'png', 'gif', 'webp' );
    997997
    998998                /**
    999999                 * Filters the list of allowed file extensions when sideloading an image from a URL.
  • src/wp-admin/includes/schema.php

    diff --git src/wp-admin/includes/schema.php src/wp-admin/includes/schema.php
    index a59c7c36ce..6f528f2288 100644
    We hope you enjoy your new site. Thanks! 
    12151215                'jpeg',
    12161216                'png',
    12171217                'gif',
     1218                'webp',
    12181219                // Video.
    12191220                'mov',
    12201221                'avi',
  • src/wp-includes/class-wp-image-editor-gd.php

    diff --git src/wp-includes/class-wp-image-editor-gd.php src/wp-includes/class-wp-image-editor-gd.php
    index ed0a7be279..42a8929ff8 100644
    class WP_Image_Editor_GD extends WP_Image_Editor { 
    6969                                return ( $image_types & IMG_PNG ) != 0;
    7070                        case 'image/gif':
    7171                                return ( $image_types & IMG_GIF ) != 0;
     72                        case 'image/webp':
     73                                return ( $image_types & IMG_WEBP ) != 0; // phpcs:ignore PHPCompatibility.Constants.NewConstants.img_webpFound
    7274                }
    7375
    7476                return false;
    class WP_Image_Editor_GD extends WP_Image_Editor { 
    99101                        return new WP_Error( 'error_loading_image', __( 'File doesn’t exist?' ), $this->file );
    100102                }
    101103
    102                 $this->image = @imagecreatefromstring( $file_contents );
     104                // WebP may not work with imagecreatefromstring().
     105                if (
     106                        function_exists( 'imagecreatefromwebp' ) &&
     107                        ( 'image/webp' === wp_get_image_mime( $this->file ) )
     108                ) {
     109                        $this->image = @imagecreatefromwebp( $this->file );
     110                } else {
     111                        $this->image = @imagecreatefromstring( $file_contents );
     112                }
    103113
    104114                if ( ! is_gd_image( $this->image ) ) {
    105115                        return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file );
    class WP_Image_Editor_GD extends WP_Image_Editor { 
    459469                        if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) {
    460470                                return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
    461471                        }
     472                } elseif ( 'image/webp' == $mime_type ) {
     473                        if ( ! function_exists( 'imagewebp' ) || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) ) {
     474                                return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
     475                        }
    462476                } else {
    463477                        return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
    464478                }
    class WP_Image_Editor_GD extends WP_Image_Editor { 
    502516                        case 'image/gif':
    503517                                header( 'Content-Type: image/gif' );
    504518                                return imagegif( $this->image );
     519                        case 'image/webp':
     520                                if ( function_exists( 'imagewebp' ) ) {
     521                                        header( 'Content-Type: image/webp' );
     522                                        return imagewebp( $this->image, null, $this->get_quality() );
     523                                }
     524                                // Fall back to the default if webp isn't supported.
    505525                        default:
    506526                                header( 'Content-Type: image/jpeg' );
    507527                                return imagejpeg( $this->image, null, $this->get_quality() );
  • src/wp-includes/class-wp-image-editor-imagick.php

    diff --git src/wp-includes/class-wp-image-editor-imagick.php src/wp-includes/class-wp-image-editor-imagick.php
    index e4f1ea1b16..36a344b15b 100644
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    197197                }
    198198
    199199                try {
    200                         if ( 'image/jpeg' === $this->mime_type ) {
    201                                 $this->image->setImageCompressionQuality( $quality );
    202                                 $this->image->setImageCompression( imagick::COMPRESSION_JPEG );
    203                         } else {
    204                                 $this->image->setImageCompressionQuality( $quality );
     200                        switch ( $this->mime_type ) {
     201                                case 'image/jpeg':
     202                                        $this->image->setImageCompressionQuality( $quality );
     203                                        $this->image->setImageCompression( imagick::COMPRESSION_JPEG );
     204                                        break;
     205                                case 'image/webp':
     206                                        if ( _wp_webp_is_lossy( $this->file ) ) {
     207                                                $this->image->setImageCompressionQuality( $quality );
     208                                        } else {
     209                                                // Use WebP lossless settings.
     210                                                $this->image->setImageCompressionQuality( 100 );
     211                                                $this->image->setOption( 'webp:lossless', 'true' );
     212                                        }
     213                                        break;
     214                                default:
     215                                        $this->image->setImageCompressionQuality( $quality );
    205216                        }
    206217                } catch ( Exception $e ) {
    207218                        return new WP_Error( 'image_quality_error', $e->getMessage() );
    208219                }
    209 
    210220                return true;
    211221        }
    212222
     223
    213224        /**
    214225         * Sets or updates current image size.
    215226         *
  • src/wp-includes/class-wp-theme.php

    diff --git src/wp-includes/class-wp-theme.php src/wp-includes/class-wp-theme.php
    index d9ccf6b6ba..b365f45715 100644
    final class WP_Theme implements ArrayAccess { 
    11411141                        return false;
    11421142                }
    11431143
    1144                 foreach ( array( 'png', 'gif', 'jpg', 'jpeg' ) as $ext ) {
     1144                foreach ( array( 'png', 'gif', 'jpg', 'jpeg', 'webp' ) as $ext ) {
    11451145                        if ( file_exists( $this->get_stylesheet_directory() . "/screenshot.$ext" ) ) {
    11461146                                $this->cache_add( 'screenshot', 'screenshot.' . $ext );
    11471147                                if ( 'relative' === $uri ) {
  • src/wp-includes/compat.php

    diff --git src/wp-includes/compat.php src/wp-includes/compat.php
    index 7f6c59f03c..59e5700439 100644
    if ( ! function_exists( 'is_iterable' ) ) { 
    370370                return ( is_array( $var ) || $var instanceof Traversable );
    371371        }
    372372}
     373
     374// WebP constants may not be defined, even in cases where the format is supported.
     375if ( ! defined( 'IMAGETYPE_WEBP' ) ) {
     376        define( 'IMAGETYPE_WEBP', 18 );
     377}
     378if ( ! defined( 'IMG_WEBP' ) ) {
     379        define( 'IMG_WEBP', IMAGETYPE_WEBP ); // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound
     380}
  • src/wp-includes/customize/class-wp-customize-media-control.php

    diff --git src/wp-includes/customize/class-wp-customize-media-control.php src/wp-includes/customize/class-wp-customize-media-control.php
    index d327a4fa38..22bf75dad5 100644
    class WP_Customize_Media_Control extends WP_Customize_Control { 
    9191                                // Fake an attachment model - needs all fields used by template.
    9292                                // Note that the default value must be a URL, NOT an attachment ID.
    9393                                $ext  = substr( $this->setting->default, -3 );
    94                                 $type = in_array( $ext, array( 'jpg', 'png', 'gif', 'bmp' ), true ) ? 'image' : 'document';
     94                                $type = in_array( $ext, array( 'jpg', 'png', 'gif', 'bmp', 'webp' ), true ) ? 'image' : 'document';
    9595
    9696                                $default_attachment = array(
    9797                                        'id'    => 1,
  • src/wp-includes/deprecated.php

    diff --git src/wp-includes/deprecated.php src/wp-includes/deprecated.php
    index 72a23cd836..2c5f24bde0 100644
    function gd_edit_image_support($mime_type) { 
    33403340                                return (imagetypes() & IMG_PNG) != 0;
    33413341                        case 'image/gif':
    33423342                                return (imagetypes() & IMG_GIF) != 0;
     3343                        case 'image/webp':
     3344                                return (imagetypes() & IMG_WEBP) != 0; // phpcs:ignore PHPCompatibility.Constants.NewConstants.img_webpFound
    33433345                }
    33443346        } else {
    33453347                switch( $mime_type ) {
    function gd_edit_image_support($mime_type) { 
    33493351                                return function_exists('imagecreatefrompng');
    33503352                        case 'image/gif':
    33513353                                return function_exists('imagecreatefromgif');
     3354                        case 'image/webp':
     3355                                return function_exists('imagecreatefromwebp');
    33523356                }
    33533357        }
    33543358        return false;
  • src/wp-includes/formatting.php

    diff --git src/wp-includes/formatting.php src/wp-includes/formatting.php
    index b716c6bc1f..8dda8c738d 100644
    function translate_smiley( $matches ) { 
    33183318
    33193319        $matches    = array();
    33203320        $ext        = preg_match( '/\.([^.]+)$/', $img, $matches ) ? strtolower( $matches[1] ) : false;
    3321         $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
     3321        $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp' );
    33223322
    33233323        // Don't convert smilies that aren't images - they're probably emoji.
    33243324        if ( ! in_array( $ext, $image_exts, true ) ) {
  • src/wp-includes/functions.php

    diff --git src/wp-includes/functions.php src/wp-includes/functions.php
    index 56d5fd9f43..83aa62e827 100644
    function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { 
    28862886                                        'image/gif'  => 'gif',
    28872887                                        'image/bmp'  => 'bmp',
    28882888                                        'image/tiff' => 'tif',
     2889                                        'image/webp' => 'webp',
    28892890                                )
    28902891                        );
    28912892
    function wp_get_image_mime( $file ) { 
    30633064                } else {
    30643065                        $mime = false;
    30653066                }
     3067
     3068                if ( false !== $mime ) {
     3069                        return $mime;
     3070                }
     3071
     3072                $handle = fopen( $file, 'rb' );
     3073                if ( false === $handle ) {
     3074                        return false;
     3075                }
     3076
     3077                $magic = fread( $handle, 12 );
     3078                if ( false === $magic ) {
     3079                        return false;
     3080                }
     3081
     3082                // Add WebP fallback detection when image library doesn't support WebP.
     3083                $magic = bin2hex( $magic );
     3084                if (
     3085                        // RIFF.
     3086                        ( 0 === strpos( $magic, '52494646' ) ) &&
     3087                        // WEBP.
     3088                        ( 16 === strpos( $magic, '57454250' ) )
     3089                ) {
     3090                        $mime = 'image/webp';
     3091                }
     3092
     3093                fclose( $handle );
    30663094        } catch ( Exception $e ) {
    30673095                $mime = false;
    30683096        }
    function wp_get_mime_types() { 
    31013129                        'png'                          => 'image/png',
    31023130                        'bmp'                          => 'image/bmp',
    31033131                        'tiff|tif'                     => 'image/tiff',
     3132                        'webp'                         => 'image/webp',
    31043133                        'ico'                          => 'image/x-icon',
    31053134                        'heic'                         => 'image/heic',
    31063135                        // Video formats.
    function wp_get_ext_types() { 
    32223251        return apply_filters(
    32233252                'ext2type',
    32243253                array(
    3225                         'image'       => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic' ),
     3254                        'image'       => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'webp' ),
    32263255                        'audio'       => array( 'aac', 'ac3', 'aif', 'aiff', 'flac', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
    32273256                        'video'       => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
    32283257                        'document'    => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
  • src/wp-includes/media.php

    diff --git src/wp-includes/media.php src/wp-includes/media.php
    index f5b6a39968..88c8af89f2 100644
    function wp_show_heic_upload_error( $plupload_settings ) { 
    49804980 * Allows PHP's getimagesize() to be debuggable when necessary.
    49814981 *
    49824982 * @since 5.7.0
     4983 * @since 5.8.0 Added support for WebP images.
    49834984 *
    49844985 * @param string $filename   The file path.
    49854986 * @param array  $image_info Optional. Extended image information (passed by reference).
    function wp_getimagesize( $filename, array &$image_info = null ) { 
    49944995                defined( 'WP_DEBUG' ) && WP_DEBUG
    49954996        ) {
    49964997                if ( 2 === func_num_args() ) {
    4997                         return getimagesize( $filename, $image_info );
     4998                        return _wp_get_image_size( $filename, $image_info );
    49984999                } else {
    4999                         return getimagesize( $filename );
     5000                        return _wp_get_image_size( $filename );
    50005001                }
    50015002        }
    50025003
    function wp_getimagesize( $filename, array &$image_info = null ) { 
    50115012         */
    50125013        if ( 2 === func_num_args() ) {
    50135014                // phpcs:ignore WordPress.PHP.NoSilencedErrors
    5014                 return @getimagesize( $filename, $image_info );
     5015                return @_wp_get_image_size( $filename, $image_info );
    50155016        } else {
    50165017                // phpcs:ignore WordPress.PHP.NoSilencedErrors
    5017                 return @getimagesize( $filename );
     5018                return @_wp_get_image_size( $filename );
    50185019        }
    50195020}
     5021
     5022/**
     5023 * Extract meta information about a webp file: width, height and type.
     5024 *
     5025 * @param [type] $filename Path to a WebP file.
     5026 * @return array $webp_info {
     5027 *     An array of WebP image information.
     5028 *
     5029 *     @type array $size {
     5030 *         @type int  $width  Image width.
     5031 *         @type int  $height Image height.
     5032 *         @type bool $type   The WebP type: one of 'lossy', 'lossless' or 'animated-alpha'.
     5033 *     }
     5034
     5035 */
     5036function wp_get_webp_info( $filename ) {
     5037        $width  = false;
     5038        $height = false;
     5039        $type   = false;
     5040        if ( ! 'image/webp' === wp_get_image_mime( $filename ) ) {
     5041                return compact( 'width', 'height', 'type' );
     5042        }
     5043        try {
     5044                $handle = fopen( $filename, 'rb' );
     5045                if ( $handle ) {
     5046                        $magic = fread( $handle, 40 );
     5047                        fclose( $handle );
     5048
     5049                        // Make sure we got enough bytes.
     5050                        if ( strlen( $magic ) < 40 ) {
     5051                                return compact( 'width', 'height', 'type' );
     5052                        }
     5053
     5054                        // The headers are a little different for each of the three formats.
     5055                        switch ( substr( $magic, 12, 4 ) ) {
     5056                                // Lossy WebP.
     5057                                case 'VP8 ':
     5058                                        $parts  = unpack( 'v2', substr( $magic, 26, 4 ) );
     5059                                        $width  = (int) ( $parts[1] & 0x3FFF );
     5060                                        $height = (int) ( $parts[2] & 0x3FFF );
     5061                                        $type   = 'lossy';
     5062                                        break;
     5063                                // Lossless WebP.
     5064                                case 'VP8L':
     5065                                        $parts  = unpack( 'C4', substr( $magic, 21, 4 ) );
     5066                                        $width  = (int) ( $parts[1] | ( ( $parts[2] & 0x3F ) << 8 ) ) + 1;
     5067                                        $height = (int) ( ( ( $parts[2] & 0xC0 ) >> 6 ) | ( $parts[3] << 2 ) | ( ( $parts[4] & 0x03 ) << 10 ) ) + 1;
     5068                                        $type   = 'lossless';
     5069                                        break;
     5070                                // Animated/alpha WebP.
     5071                                case 'VP8X':
     5072                                        // Pad 24-bit int.
     5073                                        $width = unpack( 'V', substr( $magic, 24, 3 ) . "\x00" );
     5074                                        $width = (int) ( $width[1] & 0xFFFFFF ) + 1;
     5075                                        // Pad 24-bit int.
     5076                                        $height = unpack( 'V', substr( $magic, 27, 3 ) . "\x00" );
     5077                                        $height = (int) ( $height[1] & 0xFFFFFF ) + 1;
     5078                                        $type   = 'animated-alpha';
     5079                                        break;
     5080                        }
     5081                }
     5082        } catch ( Exception $e ) {
     5083        }
     5084        return compact( 'width', 'height', 'type' );
     5085}
     5086
     5087/**
     5088 * Determine if a passed image is a lossy WebP image.
     5089 *
     5090 * @param [type] $filename
     5091 * @return void
     5092 */
     5093function _wp_webp_is_lossy( $filename ) {
     5094        $webp_info = wp_get_webp_info( $filename );
     5095        $type      = $webp_info['type'];
     5096        return $type && 'lossy' === $type;
     5097}
     5098
     5099/**
     5100 * Get the image size, with support for WebP images.
     5101 *
     5102 * @since 5.8.0
     5103 * @access private
     5104 *
     5105 * @param string $filename  The file path.
     5106 * @param array  $imageinfo Extended image information, passed by reference.
     5107 */
     5108function _wp_get_image_size( $filename, &$imageinfo = array() ) {
     5109        // Try getimagesize() first.
     5110        $info = getimagesize( $filename, $imageinfo );
     5111        if ( false !== $info ) {
     5112                return $info;
     5113        }
     5114        // For PHP versions that don't support WebP images, extract the image
     5115        // size info from the file headers.
     5116        if ( 'image/webp' === wp_get_image_mime( $filename ) ) {
     5117                $webp_info = wp_get_webp_info( $filename );
     5118                $width     = $webp_info['width'];
     5119                $height    = $webp_info['height'];
     5120
     5121                        // Mimic the native return format.
     5122                if ( $width && $height ) {
     5123                        return array(
     5124                                $width,
     5125                                $height,
     5126                                IMAGETYPE_WEBP, // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound
     5127                                sprintf(
     5128                                        'width="%d" height="%d"',
     5129                                        $width,
     5130                                        $height
     5131                                ),
     5132                                'mime' => 'image/webp',
     5133                        );
     5134                }
     5135        }
     5136
     5137        // The image could not be parsed.
     5138        return false;
     5139}
  • src/wp-includes/post.php

    diff --git src/wp-includes/post.php src/wp-includes/post.php
    index abf6f1df46..56cd4a8cd5 100644
    function wp_attachment_is( $type, $post = null ) { 
    65396539
    65406540        switch ( $type ) {
    65416541                case 'image':
    6542                         $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
     6542                        $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp' );
    65436543                        return in_array( $ext, $image_exts, true );
    65446544
    65456545                case 'audio':
  • src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php

    diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
    index ea4ae947cc..007cee774b 100644
    class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { 
    438438                        );
    439439                }
    440440
    441                 $supported_types = array( 'image/jpeg', 'image/png', 'image/gif' );
     441                $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp' );
    442442                $mime_type       = get_post_mime_type( $attachment_id );
    443443                if ( ! in_array( $mime_type, $supported_types, true ) ) {
    444444                        return new WP_Error(
  • tests/phpunit/tests/functions.php

    diff --git tests/phpunit/data/images/test-image.webp tests/phpunit/data/images/test-image.webp
    new file mode 100644
    index 0000000000..37ab153807
    Binary files /dev/null and tests/phpunit/data/images/test-image.webp differ
    diff --git tests/phpunit/data/images/webp-animated.webp tests/phpunit/data/images/webp-animated.webp
    new file mode 100644
    index 0000000000..c60d334a82
    Binary files /dev/null and tests/phpunit/data/images/webp-animated.webp differ
    diff --git tests/phpunit/data/images/webp-lossless.webp tests/phpunit/data/images/webp-lossless.webp
    new file mode 100644
    index 0000000000..7a3a06e0b4
    Binary files /dev/null and tests/phpunit/data/images/webp-lossless.webp differ
    diff --git tests/phpunit/data/images/webp-lossy.webp tests/phpunit/data/images/webp-lossy.webp
    new file mode 100644
    index 0000000000..c8b0e25391
    Binary files /dev/null and tests/phpunit/data/images/webp-lossy.webp differ
    diff --git tests/phpunit/data/images/webp-transparent.webp tests/phpunit/data/images/webp-transparent.webp
    new file mode 100644
    index 0000000000..c4b24a08be
    Binary files /dev/null and tests/phpunit/data/images/webp-transparent.webp differ
    diff --git tests/phpunit/tests/functions.php tests/phpunit/tests/functions.php
    index f485d3b4ec..75a2ecf5e0 100644
    class Tests_Functions extends WP_UnitTestCase { 
    12251225                $this->assertSame( $expected, wp_get_image_mime( $file ) );
    12261226        }
    12271227
     1228        /**
     1229         * @ticket 35725
     1230         * @dataProvider _wp_getimagesize
     1231         */
     1232        public function test_wp_getimagesize( $file, $expected ) {
     1233                if ( ! is_callable( 'exif_imagetype' ) && ! function_exists( 'getimagesize' ) ) {
     1234                        $this->markTestSkipped( 'The exif PHP extension is not loaded.' );
     1235                }
     1236
     1237                $result = wp_getimagesize( $file );
     1238
     1239                // The getimagesize() function varies in its response, so
     1240                // let's restrict comparison to expected keys only.
     1241                if ( is_array( $expected ) ) {
     1242                        foreach ( $expected as $k => $v ) {
     1243                                $this->assertEquals( true, isset( $result[ $k ] ) );
     1244                                $this->assertEquals( $expected[ $k ], $result[ $k ] );
     1245                        }
     1246                } else {
     1247                        $this->assertEquals( $expected, $result );
     1248                }
     1249        }
     1250
    12281251        /**
    12291252         * @ticket 39550
    12301253         * @dataProvider _wp_check_filetype_and_ext_data
    class Tests_Functions extends WP_UnitTestCase { 
    13131336                                DIR_TESTDATA . '/images/test-image-mime-jpg.png',
    13141337                                'image/jpeg',
    13151338                        ),
     1339                        // Animated WebP.
     1340                        array(
     1341                                DIR_TESTDATA . '/images/webp-animated.webp',
     1342                                'image/webp',
     1343                        ),
     1344                        // Lossless WebP.
     1345                        array(
     1346                                DIR_TESTDATA . '/images/webp-lossless.webp',
     1347                                'image/webp',
     1348                        ),
     1349                        // Lossy WebP.
     1350                        array(
     1351                                DIR_TESTDATA . '/images/webp-lossy.webp',
     1352                                'image/webp',
     1353                        ),
     1354                        // Transparent WebP.
     1355                        array(
     1356                                DIR_TESTDATA . '/images/webp-transparent.webp',
     1357                                'image/webp',
     1358                        ),
     1359                        // Not an image.
     1360                        array(
     1361                                DIR_TESTDATA . '/uploads/dashicons.woff',
     1362                                false,
     1363                        ),
     1364                );
     1365
     1366                return $data;
     1367        }
     1368
     1369        /**
     1370         * Data profider for test_wp_getimagesize();
     1371         */
     1372        public function _wp_getimagesize() {
     1373                $data = array(
     1374                        // Standard JPEG.
     1375                        array(
     1376                                DIR_TESTDATA . '/images/test-image.jpg',
     1377                                array(
     1378                                        50,
     1379                                        50,
     1380                                        IMAGETYPE_JPEG,
     1381                                        'width="50" height="50"',
     1382                                        'mime' => 'image/jpeg',
     1383                                ),
     1384                        ),
     1385                        // Standard GIF.
     1386                        array(
     1387                                DIR_TESTDATA . '/images/test-image.gif',
     1388                                array(
     1389                                        50,
     1390                                        50,
     1391                                        IMAGETYPE_GIF,
     1392                                        'width="50" height="50"',
     1393                                        'mime' => 'image/gif',
     1394                                ),
     1395                        ),
     1396                        // Standard PNG.
     1397                        array(
     1398                                DIR_TESTDATA . '/images/test-image.png',
     1399                                array(
     1400                                        50,
     1401                                        50,
     1402                                        IMAGETYPE_PNG,
     1403                                        'width="50" height="50"',
     1404                                        'mime' => 'image/png',
     1405                                ),
     1406                        ),
     1407                        // Image with wrong extension.
     1408                        array(
     1409                                DIR_TESTDATA . '/images/test-image-mime-jpg.png',
     1410                                array(
     1411                                        50,
     1412                                        50,
     1413                                        IMAGETYPE_JPEG,
     1414                                        'width="50" height="50"',
     1415                                        'mime' => 'image/jpeg',
     1416                                ),
     1417                        ),
     1418                        // Animated WebP.
     1419                        array(
     1420                                DIR_TESTDATA . '/images/webp-animated.webp',
     1421                                array(
     1422                                        100,
     1423                                        100,
     1424                                        IMAGETYPE_WEBP,
     1425                                        'width="100" height="100"',
     1426                                        'mime' => 'image/webp',
     1427                                ),
     1428                        ),
     1429                        // Lossless WebP.
     1430                        array(
     1431                                DIR_TESTDATA . '/images/webp-lossless.webp',
     1432                                array(
     1433                                        1200,
     1434                                        675,
     1435                                        IMAGETYPE_WEBP,
     1436                                        'width="1200" height="675"',
     1437                                        'mime' => 'image/webp',
     1438                                ),
     1439                        ),
     1440                        // Lossy WebP.
     1441                        array(
     1442                                DIR_TESTDATA . '/images/webp-lossy.webp',
     1443                                array(
     1444                                        1200,
     1445                                        675,
     1446                                        IMAGETYPE_WEBP,
     1447                                        'width="1200" height="675"',
     1448                                        'mime' => 'image/webp',
     1449                                ),
     1450                        ),
     1451                        // Transparent WebP.
     1452                        array(
     1453                                DIR_TESTDATA . '/images/webp-transparent.webp',
     1454                                array(
     1455                                        1200,
     1456                                        675,
     1457                                        IMAGETYPE_WEBP,
     1458                                        'width="1200" height="675"',
     1459                                        'mime' => 'image/webp',
     1460                                ),
     1461                        ),
    13161462                        // Not an image.
    13171463                        array(
    13181464                                DIR_TESTDATA . '/uploads/dashicons.woff',
  • tests/phpunit/tests/image/editor.php

    diff --git tests/phpunit/tests/image/editor.php tests/phpunit/tests/image/editor.php
    index 47ee30a658..42061d4da4 100644
    class Tests_Image_Editor extends WP_Image_UnitTestCase { 
    195195
    196196                $this->assertSame( '100x50', $editor->get_suffix() );
    197197        }
     198
     199        /**
     200         * Test wp_get_webp_info.
     201         *
     202         * @ticket 35725
     203         * @dataProvider _test_wp_get_webp_info
     204         *
     205         */
     206        public function test_wp_get_webp_info( $file, $expected ) {
     207                $editor = wp_get_image_editor( $file );
     208                if ( is_wp_error( $editor ) || ! $editor->supports_mime_type( 'image/webp' ) ) {
     209                        $this->markTestSkipped( sprintf( 'Skipping test: no WebP support in the editor engine %s on this system.', $this->editor_engine ) );
     210                } else {
     211                        $file_data = wp_get_webp_info( $file );
     212                        $this->assertSame( $file_data, $expected );
     213                }
     214        }
     215
     216        /**
     217         * Data provider for test_wp_get_webp_info();
     218         */
     219        public function _test_wp_get_webp_info() {
     220                return array(
     221                        // Standard JPEG.
     222                        array(
     223                                DIR_TESTDATA . '/images/test-image.jpg',
     224                                array(
     225                                        'width' => false,
     226                                        'height' => false,
     227                                        'type' => false,
     228                                ),
     229                        ),
     230                        // Standard GIF.
     231                        array(
     232                                DIR_TESTDATA . '/images/test-image.gif',
     233                                array(
     234                                        'width' => false,
     235                                        'height' => false,
     236                                        'type' => false,
     237                                ),
     238                        ),
     239                        // Animated WebP.
     240                        array(
     241                                DIR_TESTDATA . '/images/webp-animated.webp',
     242                                array(
     243                                        'width' => 100,
     244                                        'height' => 100,
     245                                        'type' => 'animated-alpha',
     246                                ),
     247                        ),
     248                        // Lossless WebP.
     249                        array(
     250                                DIR_TESTDATA . '/images/webp-lossless.webp',
     251                                array(
     252                                        'width' => 1200,
     253                                        'height' => 675,
     254                                        'type' => 'lossless',
     255                                ),
     256                        ),
     257                        // Lossy WebP.
     258                        array(
     259                                DIR_TESTDATA . '/images/webp-lossy.webp',
     260                                array(
     261                                        'width' => 1200,
     262                                        'height' => 675,
     263                                        'type' => 'lossy',
     264                                ),
     265                        ),
     266                        // Transparent WebP.
     267                        array(
     268                                DIR_TESTDATA . '/images/webp-transparent.webp',
     269                                array(
     270                                        'width' => 1200,
     271                                        'height' => 675,
     272                                        'type' => 'animated-alpha',
     273                                ),
     274                        ),
     275                );
     276        }
     277
    198278}
  • tests/phpunit/tests/image/functions.php

    diff --git tests/phpunit/tests/image/functions.php tests/phpunit/tests/image/functions.php
    index 1694c1e7f1..0658e45117 100644
    class Tests_Image_Functions extends WP_UnitTestCase { 
    5959                        'test-image.psd',
    6060                        'test-image-zip.tiff',
    6161                        'test-image.jpg',
     62                        'webp-animated.webp',
     63                        'webp-lossless.webp',
     64                        'webp-lossy.webp',
     65                        'webp-transparent.webp',
    6266                );
    6367
    6468                // IMAGETYPE_ICO is only defined in PHP 5.3+.
    class Tests_Image_Functions extends WP_UnitTestCase { 
    9296                        'test-image.jpg',
    9397                );
    9498
     99                // Add WebP images if the image editor supports them.
     100                $file   = DIR_TESTDATA . '/images/test-image.webp';
     101                $editor = wp_get_image_editor( $file );
     102                if ( ( ! is_wp_error( $editor ) ) && $editor->supports_mime_type( 'image/webp' ) ) {
     103                        $files = array_merge(
     104                                $files,
     105                                array(
     106                                        'webp-animated.webp',
     107                                        'webp-lossless.webp',
     108                                        'webp-lossy.webp',
     109                                        'webp-transparent.webp',
     110                                )
     111                        );
     112                }
     113
    95114                // IMAGETYPE_ICO is only defined in PHP 5.3+.
    96115                if ( defined( 'IMAGETYPE_ICO' ) ) {
    97116                        $files[] = 'test-image.ico';
    class Tests_Image_Functions extends WP_UnitTestCase { 
    174193                        'image/png',
    175194                );
    176195
     196                // Include WebP in tests when platform supports it.
     197                if ( function_exists( 'imagewebp' ) ) {
     198                        array_push( $mime_types, 'image/webp' );
     199                }
     200
    177201                // Test each image editor engine.
    178202                foreach ( $classes as $class ) {
    179203                        $img    = new $class( DIR_TESTDATA . '/images/canola.jpg' );
    class Tests_Image_Functions extends WP_UnitTestCase { 
    270294                        'jpe'  => 'image/jpeg',
    271295                        'gif'  => 'image/gif',
    272296                        'png'  => 'image/png',
    273                         'unk'  => 'image/jpeg', // Default, unknown.
     297                        'webp' => 'image/webp',
     298                        'unk'  => 'image/jpeg',   // Default, unknown.
    274299                );
    275300
    276301                // Test each image editor engine.
  • tests/phpunit/tests/image/resize.php

    diff --git tests/phpunit/tests/image/resize.php tests/phpunit/tests/image/resize.php
    index 3e3255e6a5..517ab45389 100644
    abstract class WP_Tests_Image_Resize_UnitTestCase extends WP_Image_UnitTestCase 
    6464                unlink( $image );
    6565        }
    6666
     67        function test_resize_webp() {
     68                $file   = DIR_TESTDATA . '/images/test-image.webp';
     69                $editor = wp_get_image_editor( $file );
     70
     71                // Check if the editor supports the webp mime type.
     72                if ( is_wp_error( $editor ) || ! $editor->supports_mime_type( 'image/webp' ) ) {
     73                        $this->markTestSkipped( sprintf( 'Skipping test: no WebP support in the editor engine %s on this system.', $this->editor_engine ) );
     74                } else {
     75                        $image = $this->resize_helper( $file, 25, 25 );
     76                        $this->assertSame( 'test-image-25x25.webp', wp_basename( $image ) );
     77                        list($w, $h, $type) = wp_getimagesize( $image );
     78                        $this->assertSame( 25, $w );
     79                        $this->assertSame( 25, $h );
     80                        $this->assertSame( IMAGETYPE_WEBP, $type );
     81                        unlink( $image );
     82                }
     83        }
     84
    6785        function test_resize_larger() {
    6886                // image_resize() should refuse to make an image larger.
    6987                $image = $this->resize_helper( DIR_TESTDATA . '/images/test-image.jpg', 100, 100 );