PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.3.2
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.3.2
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
imagify / classes / Abilities / RestoreMedia.php

RestoreMedia.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.3.2, at classes/Abilities/RestoreMedia.php

192 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 declare(strict_types=1);
3
4 namespace Imagify\Abilities;
5
6 /**
7 * MCP ability: restore a media to its original state from backup.
8 *
9 * Registers itself with the WP Abilities API under the slug
10 * `imagify/restore-media` and delegates to the existing
11 * `Imagify\Optimization\Process\AbstractProcess::restore()` method.
12 *
13 * @since 2.3.0
14 */
15 class RestoreMedia implements AbilitiesInterface {
16
17 /**
18 * Register the ability with the WP Abilities API.
19 *
20 * No-ops gracefully when the API is not available (WP < 6.9).
21 *
22 * @return void
23 */
24 public function register(): void {
25 if ( ! function_exists( 'wp_register_ability' ) ) {
26 return;
27 }
28
29 wp_register_ability(
30 'imagify/restore-media',
31 [
32 'label' => __( 'Restore media', 'imagify' ),
33 'description' => __( 'Restores an optimized media to its original state using the stored backup file.', 'imagify' ),
34 'category' => 'imagify',
35 'input_schema' => [
36 'type' => 'object',
37 'properties' => [
38 'media_id' => [
39 'type' => 'integer',
40 'description' => __( 'The WordPress attachment ID to restore.', 'imagify' ),
41 ],
42 ],
43 'required' => [ 'media_id' ],
44 ],
45 'output_schema' => [
46 'type' => 'object',
47 'properties' => [
48 'status' => [
49 'type' => 'string',
50 'description' => __( 'Result status: "success" or "error".', 'imagify' ),
51 'enum' => [ 'success', 'error' ],
52 ],
53 'restored_size' => [
54 'type' => [ 'integer', 'null' ],
55 'description' => __( 'Restored original file size in bytes, or null on error.', 'imagify' ),
56 ],
57 'error_message' => [
58 'type' => [ 'string', 'null' ],
59 'description' => __( 'Human-readable error message on failure, or null on success.', 'imagify' ),
60 ],
61 ],
62 ],
63 'execute_callback' => [ $this, 'execute' ],
64 'permission_callback' => [ $this, 'check_permissions' ],
65 'meta' => [
66 'show_in_rest' => true,
67 'mcp' => [
68 'public' => true,
69 ],
70 'annotations' => [
71 'readonly' => false,
72 'destructive' => true,
73 'idempotent' => false,
74 ],
75 ],
76 ]
77 );
78 }
79
80 /**
81 * Check if the current user has permission to execute this ability.
82 *
83 * @return bool True when the current user has the `manage_options` capability.
84 */
85 public function check_permissions(): bool {
86 return (bool) current_user_can( 'manage_options' );
87 }
88
89 /**
90 * Execute the ability: restore the media to its original state.
91 *
92 * @param array $args Input arguments. Expects `media_id` (int) — the WordPress attachment ID.
93 * @return array{status: string, restored_size: int|null, error_message: string|null}
94 */
95 public function execute( array $args = [] ): array {
96 $media_id = isset( $args['media_id'] ) ? (int) $args['media_id'] : 0;
97
98 if ( $media_id <= 0 ) {
99 return [
100 'status' => 'error',
101 'restored_size' => null,
102 'error_message' => 'Invalid or missing media_id.',
103 ];
104 }
105
106 $process = $this->get_process( $media_id );
107
108 if ( null === $process ) {
109 return [
110 'status' => 'error',
111 'restored_size' => null,
112 'error_message' => 'Invalid media.',
113 ];
114 }
115
116 if ( ! $process->get_data()->is_optimized() ) {
117 return [
118 'status' => 'error',
119 'restored_size' => null,
120 'error_message' => 'This media is not optimized and cannot be restored.',
121 ];
122 }
123
124 $result = $process->restore();
125
126 if ( is_wp_error( $result ) ) {
127 return [
128 'status' => 'error',
129 'restored_size' => null,
130 'error_message' => $result->get_error_message(),
131 ];
132 }
133
134 $restored_size = $this->get_restored_size( $process );
135
136 return [
137 'status' => 'success',
138 'restored_size' => $restored_size,
139 'error_message' => null,
140 ];
141 }
142
143 /**
144 * Resolve the optimization process for the given media ID.
145 *
146 * Tries the `wp` context first, then falls back to `custom-folders`.
147 * Returns null when neither context recognises the media.
148 *
149 * Extracted into a protected method so unit tests can inject a mock process.
150 *
151 * @param int $media_id The attachment ID.
152 * @return \Imagify\Optimization\Process\ProcessInterface|null
153 */
154 protected function get_process( int $media_id ) {
155 if ( get_post_type( $media_id ) === 'attachment' ) {
156 return imagify_get_optimization_process( $media_id, 'wp' );
157 }
158
159 $process = imagify_get_optimization_process( $media_id, 'custom-folders' );
160
161 if ( $process->is_valid() ) {
162 return $process;
163 }
164
165 return null;
166 }
167
168 /**
169 * Get the restored original file size in bytes.
170 *
171 * Extracted into a protected method so unit tests can override.
172 *
173 * @param \Imagify\Optimization\Process\ProcessInterface $process The restore process.
174 * @return int File size in bytes, or 0 if unavailable.
175 */
176 protected function get_restored_size( $process ): int {
177 $media = $process->get_media();
178
179 if ( ! $media ) {
180 return 0;
181 }
182
183 $path = $media->get_raw_original_path();
184
185 if ( ! $path || ! file_exists( $path ) ) {
186 return 0;
187 }
188
189 return (int) filesize( $path );
190 }
191 }
192