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
imagify / classes / Abilities / RestoreMedia.php

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

191 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. Provide media_filename or media_url instead when the ID is unknown.', 'imagify' ),
41 ],
42 ] + MediaResolver::get_input_schema_properties(),
43 ],
44 'output_schema' => [
45 'type' => 'object',
46 'properties' => [
47 'status' => [
48 'type' => 'string',
49 'description' => __( 'Result status: "success" or "error".', 'imagify' ),
50 'enum' => [ 'success', 'error' ],
51 ],
52 'restored_size' => [
53 'type' => [ 'integer', 'null' ],
54 'description' => __( 'Restored original file size in bytes, or null on error.', 'imagify' ),
55 ],
56 'error_message' => [
57 'type' => [ 'string', 'null' ],
58 'description' => __( 'Human-readable error message on failure, or null on success.', 'imagify' ),
59 ],
60 ],
61 ],
62 'execute_callback' => [ $this, 'execute' ],
63 'permission_callback' => [ $this, 'check_permissions' ],
64 'meta' => [
65 'show_in_rest' => true,
66 'mcp' => [
67 'public' => true,
68 ],
69 'annotations' => [
70 'readonly' => false,
71 'destructive' => true,
72 'idempotent' => false,
73 ],
74 ],
75 ]
76 );
77 }
78
79 /**
80 * Check if the current user has permission to execute this ability.
81 *
82 * @return bool True when the current user has the `manage_options` capability.
83 */
84 public function check_permissions(): bool {
85 return (bool) current_user_can( 'manage_options' );
86 }
87
88 /**
89 * Execute the ability: restore the media to its original state.
90 *
91 * @param array $args Input arguments. Expects `media_id` (int) — the WordPress attachment ID.
92 * @return array{status: string, restored_size: int|null, error_message: string|null}
93 */
94 public function execute( array $args = [] ): array {
95 $media_id = MediaResolver::resolve_id( $args );
96
97 if ( is_wp_error( $media_id ) ) {
98 return [
99 'status' => 'error',
100 'restored_size' => null,
101 'error_message' => $media_id->get_error_message(),
102 ];
103 }
104
105 $process = $this->get_process( $media_id );
106
107 if ( null === $process ) {
108 return [
109 'status' => 'error',
110 'restored_size' => null,
111 'error_message' => 'Invalid media.',
112 ];
113 }
114
115 if ( ! $process->get_data()->is_optimized() ) {
116 return [
117 'status' => 'error',
118 'restored_size' => null,
119 'error_message' => 'This media is not optimized and cannot be restored.',
120 ];
121 }
122
123 $result = $process->restore();
124
125 if ( is_wp_error( $result ) ) {
126 return [
127 'status' => 'error',
128 'restored_size' => null,
129 'error_message' => $result->get_error_message(),
130 ];
131 }
132
133 $restored_size = $this->get_restored_size( $process );
134
135 return [
136 'status' => 'success',
137 'restored_size' => $restored_size,
138 'error_message' => null,
139 ];
140 }
141
142 /**
143 * Resolve the optimization process for the given media ID.
144 *
145 * Tries the `wp` context first, then falls back to `custom-folders`.
146 * Returns null when neither context recognises the media.
147 *
148 * Extracted into a protected method so unit tests can inject a mock process.
149 *
150 * @param int $media_id The attachment ID.
151 * @return \Imagify\Optimization\Process\ProcessInterface|null
152 */
153 protected function get_process( int $media_id ) {
154 if ( get_post_type( $media_id ) === 'attachment' ) {
155 return imagify_get_optimization_process( $media_id, 'wp' );
156 }
157
158 $process = imagify_get_optimization_process( $media_id, 'custom-folders' );
159
160 if ( $process->is_valid() ) {
161 return $process;
162 }
163
164 return null;
165 }
166
167 /**
168 * Get the restored original file size in bytes.
169 *
170 * Extracted into a protected method so unit tests can override.
171 *
172 * @param \Imagify\Optimization\Process\ProcessInterface $process The restore process.
173 * @return int File size in bytes, or 0 if unavailable.
174 */
175 protected function get_restored_size( $process ): int {
176 $media = $process->get_media();
177
178 if ( ! $media ) {
179 return 0;
180 }
181
182 $path = $media->get_raw_original_path();
183
184 if ( ! $path || ! file_exists( $path ) ) {
185 return 0;
186 }
187
188 return (int) filesize( $path );
189 }
190 }
191