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/Media/Subscriber.php +137 -0 2.2.8 → trunk View file →
@@ -4,8 +4,10 @@
4 4 namespace Imagify\Media;
5 5
6 6 use Imagify\EventManagement\SubscriberInterface;
7 7 use Imagify\Media\Upload\Upload;
8 +use Imagify\Optimization\NextGenMarker;
9 +use WP_Query;
8 10
9 11 /**
10 12 * Media Subscriber
11 13 */
@@ -34,8 +36,10 @@
34 36 public static function get_subscribed_events(): array {
35 37 return [
36 38 // @action
37 39 'restrict_manage_posts' => 'imagify_attachments_filter_dropdown',
40 + // @action
41 + 'pre_get_posts' => 'filter_missing_nextgen_query',
38 42 ];
39 43 }
40 44
41 45 /**
@@ -47,6 +51,139 @@
47 51 if ( ! \Imagify_Views::get_instance()->is_wp_library_page() ) {
48 52 return;
49 53 }
50 54 $this->upload->add_imagify_filter_to_attachments_dropdown();
55 + }
56 +
57 + /**
58 + * Narrows the Media Library list table (list mode only, `WP_Query`-based) to attachments that
59 + * are optimized but have no successful next-gen size recorded, when
60 + * `?imagify-status=missing-nextgen` is requested.
61 + *
62 + * The predicate mirrors `Imagify\Bulk\WP::get_optimized_media_ids_without_format()` on purpose:
63 + * the list and the "missing next-gen" count it feeds must never disagree.
64 + *
65 + * @param WP_Query $query The current query, by reference.
66 + *
67 + * @return void
68 + */
69 + public function filter_missing_nextgen_query( WP_Query $query ) {
70 + if ( ! is_admin() || ! $query->is_main_query() ) {
71 + return;
72 + }
73 +
74 + if ( ! \Imagify_Views::get_instance()->is_wp_library_page() ) {
75 + return;
76 + }
77 +
78 + $status = isset( $_GET['imagify-status'] ) ? sanitize_text_field( wp_unslash( $_GET['imagify-status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
79 +
80 + if ( 'missing-nextgen' !== $status ) {
81 + return;
82 + }
83 +
84 + $formats = imagify_nextgen_images_formats();
85 +
86 + if ( empty( $formats ) ) {
87 + // No next-gen format is enabled: nothing can be "missing" a format that isn't
88 + // generated in the first place. Show no results rather than the whole library.
89 + $query->set( 'post__in', [ 0 ] );
90 + return;
91 + }
92 +
93 + $format = $this->get_enabled_format( $formats );
94 + $nextgen_suffix = $this->get_nextgen_suffix( $format );
95 +
96 + if ( '' === $nextgen_suffix ) {
97 + // The enabled format is not one we know how to detect: showing the whole library
98 + // would be worse than showing nothing.
99 + $query->set( 'post__in', [ 0 ] );
100 + return;
101 + }
102 +
103 + $query->set(
104 + 'meta_query', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
105 + [
106 + 'relation' => 'AND',
107 + [
108 + 'key' => '_imagify_status',
109 + 'value' => [ 'success', 'already_optimized' ],
110 + 'compare' => 'IN',
111 + ],
112 + [
113 + 'key' => '_imagify_data',
114 + 'value' => NextGenMarker::success( $nextgen_suffix ),
115 + 'compare' => 'NOT LIKE',
116 + ],
117 + [
118 + 'key' => '_imagify_data',
119 + 'value' => NextGenMarker::permanent_error( $nextgen_suffix ),
120 + 'compare' => 'NOT LIKE',
121 + ],
122 + ]
123 + );
124 +
125 + if ( ! $query->get( 'post_mime_type' ) ) {
126 + $query->set( 'post_mime_type', $this->get_convertible_mime_types( $format ) );
127 + }
128 + }
129 +
130 + /**
131 + * Reads the first enabled next-gen format.
132 + *
133 + * `imagify_nextgen_images_formats()` is filterable by third parties, so the array may come
134 + * back as a list (`[ 'webp' ]`) rather than the keyed shape core builds (`[ 'webp' => 'webp' ]`).
135 + * Reading the key would then yield the integer `0` — which is what made `strtoupper()` fatal
136 + * on PHP 8 — so the value is read instead, and anything that is not a string is discarded.
137 + *
138 + * @param array $formats The enabled next-gen formats.
139 + *
140 + * @return string The format in lowercase, or an empty string if it is unusable.
141 + */
142 + private function get_enabled_format( array $formats ): string {
143 + $format = current( $formats );
144 +
145 + return is_string( $format ) ? strtolower( $format ) : '';
146 + }
147 +
148 + /**
149 + * Resolves the next-gen suffix (e.g. `@imagify-webp`) for the given format.
150 + *
151 + * An unrecognised format resolves to an empty string rather than raising an error, since the
152 + * format ultimately comes from a public filter.
153 + *
154 + * @param string $format The next-gen format, lowercase.
155 + *
156 + * @return string The suffix, or an empty string if the format is not recognised.
157 + */
158 + private function get_nextgen_suffix( string $format ): string {
159 + $process_class = imagify_get_optimization_process_class_name( 'wp' );
160 + $suffixes = [
161 + 'avif' => constant( $process_class . '::AVIF_SUFFIX' ),
162 + 'webp' => constant( $process_class . '::WEBP_SUFFIX' ),
163 + ];
164 +
165 + return isset( $suffixes[ $format ] ) ? $suffixes[ $format ] : '';
166 + }
167 +
168 + /**
169 + * Lists the mime types that can hold a next-gen version of the given format.
170 + *
171 + * Mirrors `Imagify\Bulk\WP::get_optimized_media_ids_without_format()`: images only — a PDF has
172 + * no next-gen version, so it can never be "missing" one — minus the target format's own mime
173 + * type, since an image that already *is* WebP is not missing a WebP version.
174 + *
175 + * @param string $format The next-gen format being looked for, e.g. `webp`.
176 + *
177 + * @return array The mime types, as extension => mime type pairs.
178 + */
179 + private function get_convertible_mime_types( string $format ): array {
180 + $mime_types = imagify_get_mime_types( 'image' );
181 +
182 + return array_filter(
183 + $mime_types,
184 + function ( $mime ) use ( $format ) {
185 + return 'image/' . strtolower( $format ) !== $mime;
186 + }
187 + );
51 188 }
52 189 }