Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Image_CDN_Image_Sizes
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 6
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 generate_sizes
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
42
 filtered_sizes
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 standardize_size_data
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 generate_sizes_meta
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 resize
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * The Image Sizes library.
4 *
5 * @package automattic/jetpack-image-cdn
6 */
7
8namespace Automattic\Jetpack\Image_CDN;
9
10/**
11 * Class Image_CDN_Image_Sizes
12 *
13 * Manages image resizing via Jetpack CDN Service.
14 */
15class Image_CDN_Image_Sizes {
16
17    /**
18     * Attachment metadata.
19     *
20     * @var array
21     */
22    public $data;
23
24    /**
25     * Image to be resized.
26     *
27     * @var Image_CDN_Image
28     */
29    public $image;
30
31    /**
32     * Intermediate sizes.
33     *
34     * @var null|array
35     */
36    public static $sizes = null;
37
38    /**
39     * Construct new sizes meta
40     *
41     * @param int   $attachment_id Attachment ID.
42     * @param array $data          Attachment metadata.
43     */
44    public function __construct( $attachment_id, $data ) {
45        $this->data  = $data;
46        $this->image = new Image_CDN_Image( $data, get_post_mime_type( $attachment_id ) );
47        $this->generate_sizes();
48    }
49
50    /**
51     * Generate sizes for attachment.
52     *
53     * @return array Array of sizes; empty array as failure fallback.
54     */
55    protected function generate_sizes() {
56
57        // There is no need to generate the sizes anew for every single image.
58        if ( null !== self::$sizes ) {
59            return self::$sizes;
60        }
61
62        /*
63         * The following logic is copied over from wp_generate_attachment_metadata
64         */
65        $_wp_additional_image_sizes = wp_get_additional_image_sizes();
66
67        $sizes = array();
68
69        $intermediate_image_sizes = get_intermediate_image_sizes();
70
71        foreach ( $intermediate_image_sizes as $s ) {
72            $sizes[ $s ] = array(
73                'width'  => '',
74                'height' => '',
75                'crop'   => false,
76            );
77            if ( isset( $_wp_additional_image_sizes[ $s ]['width'] ) ) {
78                // For theme-added sizes.
79                $sizes[ $s ]['width'] = (int) $_wp_additional_image_sizes[ $s ]['width'];
80            } else {
81                // For default sizes set in options.
82                $sizes[ $s ]['width'] = get_option( "{$s}_size_w" );
83            }
84
85            if ( isset( $_wp_additional_image_sizes[ $s ]['height'] ) ) {
86                // For theme-added sizes.
87                $sizes[ $s ]['height'] = (int) $_wp_additional_image_sizes[ $s ]['height'];
88            } else {
89                // For default sizes set in options.
90                $sizes[ $s ]['height'] = get_option( "{$s}_size_h" );
91            }
92
93            if ( isset( $_wp_additional_image_sizes[ $s ]['crop'] ) ) {
94                // For theme-added sizes.
95                $sizes[ $s ]['crop'] = $_wp_additional_image_sizes[ $s ]['crop'];
96            } else {
97                // For default sizes set in options.
98                $sizes[ $s ]['crop'] = get_option( "{$s}_crop" );
99            }
100        }
101
102        self::$sizes = $sizes;
103
104        return $sizes;
105    }
106
107    /**
108     * Add filtered sizes.
109     *
110     * @return array
111     */
112    public function filtered_sizes() {
113        // Remove filter preventing the creation of advanced sizes.
114        remove_filter(
115            'intermediate_image_sizes_advanced',
116            array( Image_CDN::class, 'filter_photon_noresize_intermediate_sizes' )
117        );
118
119        // Compatibility fix: Ensure that Jetpack's inbuilt Photon does not get in the way.
120        // No need to re-enable this filter if present, as its functionality will be handled
121        // by the Image_CDN filter added below.
122        remove_filter(
123            'intermediate_image_sizes_advanced',
124            array( 'Jetpack_Photon', 'filter_photon_noresize_intermediate_sizes' )
125        );
126
127        /** This filter is documented in wp-admin/includes/image.php */
128        $sizes = apply_filters( 'intermediate_image_sizes_advanced', self::$sizes, $this->data );
129
130        // Re-add the filter removed above.
131        add_filter(
132            'intermediate_image_sizes_advanced',
133            array( Image_CDN::class, 'filter_photon_noresize_intermediate_sizes' )
134        );
135
136        return (array) $sizes;
137    }
138
139    /**
140     * Standardises and validates the size_data array.
141     *
142     * @param array $size_data Size data array - at least containing height or width key. Can contain crop as well.
143     *
144     * @return array Array with populated width, height and crop keys; empty array if no width and height are provided.
145     */
146    public function standardize_size_data( $size_data ) {
147        $has_at_least_width_or_height = ( isset( $size_data['width'] ) || isset( $size_data['height'] ) );
148        if ( ! $has_at_least_width_or_height ) {
149            return array();
150        }
151
152        $defaults = array(
153            'width'  => null,
154            'height' => null,
155            'crop'   => false,
156        );
157
158        return array_merge( $defaults, $size_data );
159    }
160
161    /**
162     * Get sizes for attachment post meta.
163     *
164     * @return array ImageSizes for attachment postmeta.
165     */
166    public function generate_sizes_meta() {
167
168        $metadata = array();
169
170        foreach ( $this->filtered_sizes() as $size => $size_data ) {
171
172            $size_data = $this->standardize_size_data( $size_data );
173
174            if ( empty( $size_data ) ) {
175                continue;
176            }
177
178            $resized_image = $this->resize( $size_data );
179
180            if ( is_array( $resized_image ) ) {
181                $metadata[ $size ] = $resized_image;
182            }
183        }
184
185        return $metadata;
186    }
187
188    /**
189     * Resize image.
190     *
191     * @param array $size_data Resize parameters.
192     *
193     * @return array|\WP_Error Array for usage in $metadata['sizes']; WP_Error on failure.
194     */
195    protected function resize( $size_data ) {
196
197        return $this->image->get_size( $size_data );
198    }
199}