PluginProbe ʕ •ᴥ•ʔ
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback / 5.1.3
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback v5.1.3
5.1.3 5.1.2 5.1.1 5.1 5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / third-party / image-optimizer / ewww / class-avcf-ewww-helpers.php
atarim-visual-collaboration / third-party / image-optimizer / ewww Last commit date
class-avcf-abilities-ewww.php 4 days ago class-avcf-ewww-detector.php 4 days ago class-avcf-ewww-helpers.php 4 days ago
class-avcf-ewww-helpers.php
168 lines
1 <?php
2 /**
3 * EWWW Image Optimizer integration helpers.
4 *
5 * Static, reusable logic shared by the EWWW ability class(es). Drives EWWW's
6 * own procedural API; never reads the API key, never reimplements compression.
7 * Every EWWW call is guarded (function/method existence + try/catch) so a
8 * plugin version change degrades to a clear message rather than a fatal.
9 *
10 * Verified against EWWW Image Optimizer 8.7.5:
11 * - single (sync) : ewww_image_optimizer_resize_from_meta_data( $meta, $id )
12 * - single (async) : ewww_image_optimizer_add_attachment_to_queue( $id, ... )
13 * - sync vs async : ewww_image_optimizer_test_background_opt()
14 * - bulk (all) : ewwwio()->async_scan->data([...])->dispatch() + background_media->dispatch()
15 * - per-image state: {prefix}ewwwio_images WHERE attachment_id = %d AND gallery = 'media'
16 *
17 * @package atarim-visual-collaboration
18 */
19
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit;
22 }
23
24 class AVCF_EWWW_Helpers {
25
26 public static function write_meta() {
27 return [
28 'mcp' => [ 'public' => true, 'type' => 'tool' ],
29 'annotations' => [ 'readonly' => false, 'destructive' => false, 'idempotent' => false ],
30 ];
31 }
32
33 public static function read_meta() {
34 return [
35 'mcp' => [ 'public' => true, 'type' => 'tool' ],
36 'annotations' => [ 'readonly' => true, 'destructive' => false, 'idempotent' => true ],
37 ];
38 }
39
40 /**
41 * Gate: EWWW active. NOTE: no "configured" check — EWWW optimizes locally
42 * without an API key, so being active is sufficient. Returns a refusal array
43 * or null to proceed.
44 */
45 public static function guard() {
46 $detector = new AVCF_EWWW_Detector();
47 if ( ! $detector->avcf_ewww_is_available() ) {
48 return [ 'success' => false, 'message' => 'EWWW Image Optimizer is not active on this site.' ];
49 }
50 return null;
51 }
52
53 public static function clean_ids( $ids ) {
54 if ( ! is_array( $ids ) ) {
55 return [];
56 }
57 $out = [];
58 foreach ( $ids as $one ) {
59 $one = (int) $one;
60 if ( $one > 0 ) {
61 $out[] = $one;
62 }
63 }
64 return array_values( array_unique( $out ) );
65 }
66
67 /**
68 * Optimize a list of attachments. When $force_async is true (bulk), always
69 * enqueue to EWWW's background process. Otherwise respect the site's setting
70 * (ewww_image_optimizer_test_background_opt): async → enqueue, else optimize
71 * synchronously and read back per-image savings.
72 */
73 public static function optimize_ids( $ids, $force_async = false ) {
74 if ( ! function_exists( 'ewwwio' ) || ! function_exists( 'ewww_image_optimizer_resize_from_meta_data' ) ) {
75 return [ 'success' => false, 'message' => 'EWWW optimization functions are unavailable.' ];
76 }
77 $use_async = $force_async
78 || ( function_exists( 'ewww_image_optimizer_test_background_opt' ) && ewww_image_optimizer_test_background_opt() );
79
80 $results = [];
81 $processed = 0;
82 foreach ( $ids as $id ) {
83 if ( 'attachment' !== get_post_type( $id ) || ! wp_attachment_is_image( $id ) ) {
84 $results[] = [ 'id' => $id, 'done' => false, 'message' => 'Not an image attachment; skipped.' ];
85 continue;
86 }
87 try {
88 if ( $use_async ) {
89 if ( ! function_exists( 'ewww_image_optimizer_add_attachment_to_queue' ) ) {
90 $results[] = [ 'id' => $id, 'done' => false, 'message' => 'Background optimization unavailable on this version.' ];
91 continue;
92 }
93 ewww_image_optimizer_add_attachment_to_queue( $id );
94 $processed++;
95 $results[] = [ 'id' => $id, 'done' => true, 'queued' => true, 'message' => 'Queued for background optimization.' ];
96 } else {
97 $meta = wp_get_attachment_metadata( $id );
98 ewww_image_optimizer_resize_from_meta_data( $meta, $id );
99 $status = self::attachment_status( $id );
100 $processed++;
101 $results[] = array_merge( [ 'id' => $id, 'done' => true, 'queued' => false, 'message' => 'Optimized.' ], $status );
102 }
103 } catch ( \Throwable $e ) {
104 $results[] = [ 'id' => $id, 'done' => false, 'message' => 'Failed: ' . $e->getMessage() ];
105 }
106 }
107 return [
108 'success' => true,
109 'mode' => $use_async ? 'async' : 'sync',
110 'processed' => $processed,
111 'results' => $results,
112 'message' => $use_async
113 ? sprintf( 'Queued %d of %d image(s) for EWWW background optimization — poll ewww-status.', $processed, count( $ids ) )
114 : sprintf( 'Optimized %d of %d image(s) synchronously.', $processed, count( $ids ) ),
115 ];
116 }
117
118 /** Kick EWWW's library-wide scan (queues all unoptimized) + start the background process. */
119 public static function start_bulk_all() {
120 if ( ! function_exists( 'ewwwio' ) ) {
121 return [ 'success' => false, 'message' => 'EWWW is unavailable.' ];
122 }
123 try {
124 $ewwwio = ewwwio();
125 if ( ! is_object( $ewwwio ) || ! isset( $ewwwio->async_scan ) || ! isset( $ewwwio->background_media ) ) {
126 return [ 'success' => false, 'message' => 'EWWW background/scan processes are unavailable on this version.' ];
127 }
128 $ewwwio->async_scan->data( [ 'ewww_scan' => 'scheduled' ] )->dispatch();
129 $ewwwio->background_media->dispatch();
130 } catch ( \Throwable $e ) {
131 return [ 'success' => false, 'message' => 'Could not start EWWW bulk scan: ' . $e->getMessage() ];
132 }
133 return [
134 'success' => true,
135 'started' => true,
136 'message' => 'Started an EWWW library scan; unoptimized images are queued and optimized in the background. Poll ewww-status for progress.',
137 ];
138 }
139
140 /** Per-attachment optimization status from EWWW's own ewwwio_images table. */
141 public static function attachment_status( $id ) {
142 global $wpdb;
143 if ( 'attachment' !== get_post_type( $id ) || ! wp_attachment_is_image( $id ) ) {
144 return [ 'optimized' => false, 'message' => 'Not an image attachment.' ];
145 }
146 $table = $wpdb->prefix . 'ewwwio_images';
147 $rows = $wpdb->get_results( $wpdb->prepare( "SELECT orig_size, image_size FROM {$table} WHERE attachment_id = %d AND gallery = %s", $id, 'media' ), ARRAY_A ); // phpcs:ignore WordPress.DB
148 if ( empty( $rows ) ) {
149 return [ 'optimized' => false, 'records' => 0 ];
150 }
151 $orig = 0;
152 $now = 0;
153 foreach ( $rows as $r ) {
154 $orig += (int) $r['orig_size'];
155 $now += (int) $r['image_size'];
156 }
157 $saved = max( 0, $orig - $now );
158 return [
159 'optimized' => true,
160 'records' => count( $rows ),
161 'original_bytes' => $orig,
162 'optimized_bytes' => $now,
163 'saved_bytes' => $saved,
164 'savings_percentage' => $orig > 0 ? round( ( $saved / $orig ) * 100, 1 ) : 0,
165 ];
166 }
167 }
168