PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / trunk
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF vtrunk
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
← All changes | classes/Context/WP.php +118 -39 1.10 → trunk View file →
@@ -1,8 +1,8 @@
1 1 <?php
2 2 namespace Imagify\Context;
3 3
4 -defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
4 +use Imagify\Traits\InstanceGetterTrait;
5 5
6 6 /**
7 7 * Context class used for the WP media library.
8 8 *
@@ -8,10 +8,10 @@
8 8 *
9 9 * @since 1.9
10 10 * @author Grégory Viguier
11 11 */
12 -class WP extends AbstractContext {
13 - use \Imagify\Traits\InstanceGetterTrait;
12 +final class WP extends AbstractContext {
13 + use InstanceGetterTrait;
14 14
15 15 /**
16 16 * Context "short name".
17 17 *
@@ -16,9 +16,8 @@
16 16 * Context "short name".
17 17 *
18 18 * @var string
19 19 * @since 1.9
20 - * @access protected
21 20 * @author Grégory Viguier
22 21 */
23 22 protected $context = 'wp';
24 23
@@ -26,18 +25,27 @@
26 25 * Images max width for this context. This is used when resizing.
27 26 *
28 27 * @var int
29 28 * @since 1.9.8
30 - * @access protected
31 29 * @author Grégory Viguier
32 30 */
33 - protected $resizing_threshold;
31 + protected $resizing_threshold = 0;
34 32
35 33 /**
34 + * True once WordPress has said the browser is scaling the upload being created.
35 + *
36 + * Set on `rest_after_insert_attachment`, read by the threshold filter later in the same
37 + * request. One request creates one attachment, so there is nothing to key it by.
38 + *
39 + * @var bool
40 + * @since 2.3.3
41 + */
42 + protected $browser_is_scaling = false;
43 +
44 + /**
36 45 * Get the thumbnail sizes for this context, except the full size.
37 46 *
38 47 * @since 1.9
39 - * @access public
40 48 * @author Grégory Viguier
41 49 *
42 50 * @return array {
43 51 * Data for the currently registered thumbnail sizes.
@@ -49,12 +57,8 @@
49 57 * @type string $name The size name.
50 58 * }
51 59 */
52 60 public function get_thumbnail_sizes() {
53 - if ( isset( $this->thumbnail_sizes ) ) {
54 - return $this->thumbnail_sizes;
55 - }
56 -
57 61 $this->thumbnail_sizes = get_imagify_thumbnail_sizes();
58 62
59 63 return $this->thumbnail_sizes;
60 64 }
@@ -63,63 +67,139 @@
63 67 * Get images max width for this context. This is used when resizing.
64 68 * 0 means to not resize.
65 69 *
66 70 * @since 1.9.8
67 - * @access public
68 71 * @author Grégory Viguier
69 72 *
70 73 * @return int
71 74 */
72 75 public function get_resizing_threshold() {
73 - if ( isset( $this->resizing_threshold ) ) {
74 - return $this->resizing_threshold;
76 + if ( get_imagify_option( 'resize_larger' ) ) {
77 + $this->resizing_threshold = max( 0, get_imagify_option( 'resize_larger_w' ) );
75 78 }
76 79
77 - if ( ! get_imagify_option( 'resize_larger' ) ) {
78 - $this->resizing_threshold = 0;
79 - } else {
80 - $this->resizing_threshold = max( 0, get_imagify_option( 'resize_larger_w' ) );
80 + return $this->resizing_threshold;
81 + }
82 +
83 + /**
84 + * Filter WP's "big images threshold" with Imagify's resizing value.
85 + *
86 + * Imagify stands down for one case only: the upload WordPress 7.1 handed to the browser,
87 + * which supplies its own scaled file through the sideload endpoint. Scaling again on the
88 + * server would leave a conflicting "-scaled" file behind and point `original_image` at it
89 + * instead of the real upload, which is why core switches its own downscaling off there.
90 + *
91 + * Nothing is lost by standing down: the value the browser scales to is produced by this
92 + * same filter, in {@see WP_REST_Server::get_index()}, so Imagify's setting still governs
93 + * the result.
94 + *
95 + * A `false` coming from anywhere else is deliberately overridden, exactly as before. Only
96 + * the browser flow leaves a scaled file behind, so treating every `false` as "already
97 + * scaled" would mean an image nobody resized: not WordPress, because it was told not to,
98 + * and not Imagify, because it believed the work was done.
99 + *
100 + * @since 2.3.3
101 + *
102 + * @param int|false $threshold The threshold value in pixels, or false to disable resizing.
103 + * @return int|false
104 + */
105 + public function filter_big_image_size_threshold( $threshold ) {
106 + if ( false === $threshold && $this->browser_is_scaling ) {
107 + return $threshold;
81 108 }
82 109
83 - return $this->resizing_threshold;
110 + return $this->get_resizing_threshold();
84 111 }
85 112
86 113 /**
87 - * Tell if the optimization process is allowed to backup in this context.
114 + * Remember that the browser is supplying the scaled version of an attachment.
88 115 *
89 - * @since 1.9
90 - * @access public
91 - * @author Grégory Viguier
116 + * Taken from where WordPress declares it rather than guessed: this runs on
117 + * `rest_after_insert_attachment`, just before the metadata is generated, and the request
118 + * carries `generate_sub_sizes` as `false` exactly when the browser owns the sub sizes.
92 119 *
93 - * @return bool
120 + * @since 2.3.3
121 + *
122 + * The threshold filter runs later in this same request, so a property is enough for it. The
123 + * transient is for the optimization, which runs in a later request of its own.
124 + *
125 + * @param object $attachment Inserted or updated attachment object. A \WP_Post when WordPress fires this.
126 + * @param object $request Request object. A \WP_REST_Request when WordPress fires this.
127 + * @param bool $creating True when creating an attachment, false when updating.
94 128 */
95 - public function can_backup() {
96 - if ( isset( $this->can_backup ) ) {
97 - return $this->can_backup;
129 + public function maybe_flag_client_side_scaling( $attachment, $request, $creating ) {
130 + if ( ! $creating || ! is_object( $attachment ) || ! isset( $attachment->ID ) ) {
131 + return;
98 132 }
99 133
100 - $this->can_backup = get_imagify_option( 'backup' );
134 + if ( ! is_object( $request ) || ! is_callable( [ $request, 'get_param' ] ) ) {
135 + return;
136 + }
101 137
102 - return $this->can_backup;
138 + if ( false !== $request->get_param( 'generate_sub_sizes' ) ) {
139 + return;
140 + }
141 +
142 + $this->browser_is_scaling = true;
143 +
144 + self::flag_client_side_scaling( $attachment->ID );
103 145 }
104 146
105 147 /**
106 - * Tell if the optimization process is allowed to keep exif in this context.
148 + * Remember that the browser is supplying the scaled version of an attachment.
107 149 *
150 + * Optimization runs in a later, asynchronous request, where the filters WordPress
151 + * set up during the upload are long gone, so the state has to be stored.
152 + *
153 + * The flag is left to expire rather than deleted after use: it is read once per size
154 + * being optimized, so deleting it on the first read would let the remaining sizes
155 + * resize the file. An hour is far longer than the queue needs, and the pattern is
156 + * registered in {@see \Imagify\Tools\InternalStateList} so a reset clears it.
157 + *
158 + * @since 2.3.3
159 + *
160 + * @param int $attachment_id Attachment post ID.
161 + */
162 + public static function flag_client_side_scaling( $attachment_id ) {
163 + set_transient( self::get_client_side_scaling_flag( $attachment_id ), 1, HOUR_IN_SECONDS );
164 + }
165 +
166 + /**
167 + * Tell if the browser supplied the scaled version of an attachment.
168 + *
169 + * @since 2.3.3
170 + *
171 + * @param int $attachment_id Attachment post ID.
172 + * @return bool
173 + */
174 + public static function is_client_side_scaled( $attachment_id ) {
175 + return (bool) get_transient( self::get_client_side_scaling_flag( $attachment_id ) );
176 + }
177 +
178 + /**
179 + * Get the transient name used to flag client side scaling for an attachment.
180 + *
181 + * @since 2.3.3
182 + *
183 + * @param int $attachment_id Attachment post ID.
184 + * @return string
185 + */
186 + private static function get_client_side_scaling_flag( $attachment_id ) {
187 + return 'imagify_client_side_scaled_' . (int) $attachment_id;
188 + }
189 +
190 + /**
191 + * Tell if the optimization process is allowed to backup in this context.
192 + *
108 193 * @since 1.9
109 - * @access public
110 194 * @author Grégory Viguier
111 195 *
112 196 * @return bool
113 197 */
114 - public function can_keep_exif() {
115 - if ( isset( $this->can_keep_exif ) ) {
116 - return $this->can_keep_exif;
117 - }
198 + public function can_backup() {
199 + $this->can_backup = get_imagify_option( 'backup' );
118 200
119 - $this->can_keep_exif = get_imagify_option( 'exif' );
120 -
121 - return $this->can_keep_exif;
201 + return $this->can_backup;
122 202 }
123 203
124 204 /**
125 205 * Get user capacity to operate Imagify in this context.
@@ -124,9 +204,8 @@
124 204 /**
125 205 * Get user capacity to operate Imagify in this context.
126 206 *
127 207 * @since 1.9
128 - * @access public
129 208 * @author Grégory Viguier
130 209 *
131 210 * @param string $describer Capacity describer. Possible values are like 'manage', 'bulk-optimize', 'manual-optimize', 'auto-optimize'.
132 211 * @return string