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/Abilities/OptimizeMedia.php +46 -17 2.3.0 → trunk View file →
@@ -11,9 +11,9 @@
11 11 * `Imagify\Optimization\Process\WP` class.
12 12 *
13 13 * @since 2.3.0
14 14 */
15 -class OptimizeMedia extends AbstractAbility {
15 +class OptimizeMedia extends AbstractAbility implements CreditConsumingAbilityInterface {
16 16
17 17 const ABILITY_ID = 'imagify/optimize-media';
18 18 const ABILITY_NAME = 'Optimize media';
19 19
@@ -46,8 +46,15 @@
46 46 if ( ! function_exists( 'wp_register_ability' ) ) {
47 47 return;
48 48 }
49 49
50 + $media_properties = [
51 + 'media_id' => [
52 + 'type' => 'integer',
53 + 'description' => __( 'The WordPress attachment ID to optimize. Provide media_filename or media_url instead when the ID is unknown.', 'imagify' ),
54 + ],
55 + ] + MediaResolver::get_input_schema_properties();
56 +
50 57 wp_register_ability(
51 58 'imagify/optimize-media',
52 59 [
53 60 'label' => __( 'Optimize media', 'imagify' ),
@@ -54,13 +61,9 @@
54 61 'description' => __( 'Optimizes a specific media on-demand using Imagify.', 'imagify' ),
55 62 'category' => 'imagify',
56 63 'input_schema' => [
57 64 'type' => 'object',
58 - 'properties' => [
59 - 'media_id' => [
60 - 'type' => 'integer',
61 - 'description' => __( 'The WordPress attachment ID to optimize.', 'imagify' ),
62 - ],
65 + 'properties' => $media_properties + [
63 66 'optimization_level' => [
64 67 'type' => 'integer',
65 68 'description' => __( 'Optimization level: 0 (normal), 1 (aggressive), or 2 (ultra). If omitted, uses the global setting.', 'imagify' ),
66 69 'minimum' => 0,
@@ -65,10 +68,14 @@
65 68 'description' => __( 'Optimization level: 0 (normal), 1 (aggressive), or 2 (ultra). If omitted, uses the global setting.', 'imagify' ),
66 69 'minimum' => 0,
67 70 'maximum' => 2,
68 71 ],
72 + 'confirm' => [
73 + 'type' => 'boolean',
74 + 'description' => __( 'Set to true to execute after reviewing the credit-consumption preview returned by a prior call without this flag.', 'imagify' ),
75 + 'default' => false,
76 + ],
69 77 ],
70 - 'required' => [ 'media_id' ],
71 78 ],
72 79 'output_schema' => [
73 80 'type' => 'object',
74 81 'properties' => [
@@ -73,10 +80,10 @@
73 80 'type' => 'object',
74 81 'properties' => [
75 82 'status' => [
76 83 'type' => 'string',
77 - 'description' => __( 'Result status: "success" or "error".', 'imagify' ),
78 - 'enum' => [ 'success', 'error' ],
84 + 'description' => __( 'Result status: "success", "error", "confirmation_required", "insufficient_quota", or "invalid_api_key".', 'imagify' ),
85 + 'enum' => [ 'success', 'error', 'confirmation_required', 'insufficient_quota', 'invalid_api_key' ],
79 86 ],
80 87 'original_size' => [
81 88 'type' => [ 'integer', 'null' ],
82 89 'description' => __( 'Original file size in bytes before optimization, or null on error.', 'imagify' ),
@@ -129,19 +136,41 @@
129 136 return imagify_get_context( 'wp' )->current_user_can( 'manage' );
130 137 }
131 138
132 139 /**
140 + * Returns the credit-consumption impact estimate for a single media optimization.
141 + *
142 + * @param array $args Input arguments (unused: optimizing a single media always costs 1 unit).
143 + * @return array{unit: string, count: int, label: string}
144 + */
145 + public function get_impact_estimate( array $args ): array {
146 + return [
147 + 'unit' => 'image',
148 + 'count' => 1,
149 + 'label' => 'this media',
150 + ];
151 + }
152 +
153 + /**
133 154 * Execute the ability: optimize the media.
134 155 *
135 - * Fires `imagify_mcp_ability_executed` after the ability resolves so that
136 - * tracking and other subscribers can react to both success and failure outcomes.
156 + * Wraps the real execution behind `guard_credit_confirmation()` so the
157 + * caller must pass `confirm: true` once quota is confirmed (and is not
158 + * over quota, and the API key is valid). Fires `imagify_mcp_ability_executed`
159 + * after the ability resolves so that tracking and other subscribers can
160 + * react to every outcome (previews included).
137 161 *
138 - * @param array $args Input arguments. Expects `media_id` (int) and optionally `optimization_level` (int).
139 - * @return array{status: string, original_size: int|null, optimized_size: int|null, savings_percent: float|null, error_message: string|null}
162 + * @param array $args Input arguments. Expects `media_id` (int) and optionally `optimization_level` (int), `confirm` (bool).
163 + * @return array<string, mixed> Guard response (invalid_api_key/insufficient_quota/confirmation_required) or the do_execute() result shape.
140 164 */
141 165 public function execute( array $args = [] ): array {
142 166 $start_time = microtime( true );
143 - $result = $this->do_execute( $args );
167 + $result = $this->guard_credit_confirmation(
168 + $args,
169 + function ( array $a ) {
170 + return $this->do_execute( $a );
171 + }
172 + );
144 173
145 174 $this->fire_executed( $result, $start_time, $args );
146 175
147 176 return $result;
@@ -156,12 +185,12 @@
156 185 * @param array $args Input arguments.
157 186 * @return array{status: string, original_size: int|null, optimized_size: int|null, savings_percent: float|null, error_message: string|null}
158 187 */
159 188 private function do_execute( array $args ): array {
160 - $media_id = isset( $args['media_id'] ) ? (int) $args['media_id'] : 0;
189 + $media_id = MediaResolver::resolve_id( $args );
161 190
162 - if ( $media_id <= 0 ) {
163 - return $this->error_response( 'Invalid or missing media_id.' );
191 + if ( is_wp_error( $media_id ) ) {
192 + return $this->error_response( $media_id->get_error_message() );
164 193 }
165 194
166 195 // Verify the attachment exists.
167 196 $post = get_post( $media_id );