PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / 2.13.1
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder v2.13.1
2.13.0 2.13.1 2.12.0 2.11.1 2.11.0 2.10.0 2.9.0 2.7.4 2.7.5 2.7.6 2.7.7 2.8.0 2.8.1 2.9.1 trunk 1.0 1.0-beta1 1.0-beta2 1.0-beta3 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 All 80 releases
ablocks / includes / classes / images / cli.php

cli.php in aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder 2.13.1, at includes/classes/images/cli.php

283 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace ABlocks\Classes\Images;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 /**
9 * Image tools — WP-CLI commands.
10 *
11 * Bulk work belongs on the command line as much as in the browser: an admin
12 * page optimising ten thousand images depends on a tab staying open, and the
13 * same job from WP-CLI does not.
14 */
15 class Cli {
16
17 /**
18 * Register the command with WP-CLI.
19 */
20 public static function register() {
21 \WP_CLI::add_command( 'ablocks image', __CLASS__ );
22 }
23
24 /**
25 * Recompress images.
26 *
27 * ## OPTIONS
28 *
29 * [--level=<level>]
30 * : Compression strength.
31 * ---
32 * default: 2x
33 * options:
34 * - 1x
35 * - 2x
36 * - 5x
37 * ---
38 *
39 * [--limit=<count>]
40 * : How many attachments to process.
41 * ---
42 * default: 50
43 * ---
44 *
45 * [--all]
46 * : Include attachments that were already optimized.
47 *
48 * [--webp]
49 * : Also write .webp siblings.
50 *
51 * ## EXAMPLES
52 *
53 * wp ablocks image optimize --level=2x --limit=200 --webp
54 *
55 * @param array $args Positional arguments.
56 * @param array $assoc_args Named arguments.
57 */
58 public function optimize( $args, $assoc_args ) {
59 $level = isset( $assoc_args['level'] ) ? (string) $assoc_args['level'] : '2x';
60 $limit = isset( $assoc_args['limit'] ) ? (int) $assoc_args['limit'] : 50;
61 $webp = isset( $assoc_args['webp'] );
62 $all = isset( $assoc_args['all'] );
63
64 $ids = Compressor::pending_ids( $limit, $all );
65 if ( empty( $ids ) ) {
66 \WP_CLI::success( 'Nothing to optimize.' );
67 return;
68 }
69
70 $progress = \WP_CLI\Utils\make_progress_bar( sprintf( 'Optimizing (%s)', $level ), count( $ids ) );
71 $before = 0;
72 $after = 0;
73
74 foreach ( $ids as $id ) {
75 $result = Compressor::optimize_attachment( $id, $level, $webp );
76 $before += (int) $result['before'];
77 $after += (int) $result['after'];
78 $progress->tick();
79 }
80 $progress->finish();
81
82 $saved = $before - $after;
83
84 \WP_CLI::success(
85 sprintf(
86 '%d image(s): %s -> %s, saved %s (%.1f%%).',
87 count( $ids ),
88 size_format( $before, 1 ),
89 size_format( $after, 1 ),
90 size_format( max( 0, $saved ), 1 ),
91 $before > 0 ? ( 100 * $saved / $before ) : 0
92 )
93 );
94 }
95
96 /**
97 * Put optimized images back to their originals.
98 *
99 * ## OPTIONS
100 *
101 * [<id>]
102 * : Restore a single attachment instead of all of them.
103 *
104 * ## EXAMPLES
105 *
106 * wp ablocks image restore
107 * wp ablocks image restore 543
108 *
109 * @param array $args Positional arguments.
110 * @param array $assoc_args Named arguments.
111 */
112 public function restore( $args, $assoc_args ) {
113 if ( ! empty( $args[0] ) ) {
114 $count = Compressor::restore_attachment( (int) $args[0] );
115 \WP_CLI::success( sprintf( '%d file(s) restored.', $count ) );
116 return;
117 }
118
119 $ids = Compressor::pending_ids( 10000, true );
120 $total = 0;
121 foreach ( $ids as $id ) {
122 $total += Compressor::restore_attachment( $id );
123 }
124
125 \WP_CLI::success( sprintf( '%d file(s) restored across %d attachment(s).', $total, count( $ids ) ) );
126 }
127
128 /**
129 * List images with no evidence of being used.
130 *
131 * Absence of evidence is not proof: an image can be referenced from places a
132 * scan cannot see. Review the list before acting on it.
133 *
134 * ## OPTIONS
135 *
136 * [--limit=<count>]
137 * : How many attachments to examine.
138 * ---
139 * default: 200
140 * ---
141 *
142 * [--format=<format>]
143 * : Output format.
144 * ---
145 * default: table
146 * options:
147 * - table
148 * - csv
149 * - json
150 * ---
151 *
152 * @param array $args Positional arguments.
153 * @param array $assoc_args Named arguments.
154 */
155 public function unused( $args, $assoc_args ) {
156 $limit = isset( $assoc_args['limit'] ) ? (int) $assoc_args['limit'] : 200;
157 $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table';
158
159 $found = [];
160 $offset = 0;
161 $bytes = 0;
162 $scanned = 0;
163
164 do {
165 $batch = UnusedScanner::scan( 50, $offset );
166 $offset = $batch['scanned'];
167 $scanned = $batch['scanned'];
168 foreach ( $batch['items'] as $item ) {
169 $found[] = [
170 'id' => $item['id'],
171 'title' => $item['title'],
172 'size' => size_format( $item['bytes'], 1 ),
173 'date' => $item['date'],
174 ];
175 $bytes += (int) $item['bytes'];
176 }
177 } while ( ! $batch['done'] && $scanned < $limit );
178
179 if ( empty( $found ) ) {
180 \WP_CLI::success( sprintf( 'Scanned %d image(s); none look unused.', $scanned ) );
181 return;
182 }
183
184 \WP_CLI\Utils\format_items( $format, $found, [ 'id', 'title', 'size', 'date' ] );
185 \WP_CLI::log( sprintf( '%d candidate(s), %s total. Verify before removing.', count( $found ), size_format( $bytes, 1 ) ) );
186 }
187
188 /**
189 * Move unused images into quarantine, or manage what is already there.
190 *
191 * Nothing is destroyed: files move aside and the attachment is trashed, both
192 * reversible until the retention window passes.
193 *
194 * ## OPTIONS
195 *
196 * [<id>...]
197 * : Attachment IDs to quarantine. Omit to act on the whole scan.
198 *
199 * [--list]
200 * : Show what is currently quarantined.
201 *
202 * [--restore=<id>]
203 * : Bring one attachment back.
204 *
205 * [--sweep]
206 * : Permanently delete items past the retention window.
207 *
208 * [--days=<days>]
209 * : Override the retention window for --sweep.
210 *
211 * [--yes]
212 * : Skip the confirmation prompt.
213 *
214 * ## EXAMPLES
215 *
216 * wp ablocks image quarantine --list
217 * wp ablocks image quarantine 543 544
218 * wp ablocks image quarantine --restore=543
219 * wp ablocks image quarantine --sweep --days=30
220 *
221 * @param array $args Positional arguments.
222 * @param array $assoc_args Named arguments.
223 */
224 public function quarantine( $args, $assoc_args ) {
225 if ( isset( $assoc_args['list'] ) ) {
226 $records = Quarantine::records();
227 if ( empty( $records ) ) {
228 \WP_CLI::success( 'Quarantine is empty.' );
229 return;
230 }
231 $rows = [];
232 foreach ( $records as $record ) {
233 $rows[] = [
234 'id' => $record['id'],
235 'title' => $record['title'],
236 'size' => size_format( $record['bytes'], 1 ),
237 'held' => gmdate( 'Y-m-d H:i', $record['time'] ) . ' UTC',
238 ];
239 }
240 \WP_CLI\Utils\format_items( 'table', $rows, [ 'id', 'title', 'size', 'held' ] );
241 return;
242 }
243
244 if ( ! empty( $assoc_args['restore'] ) ) {
245 $ok = Quarantine::restore( (int) $assoc_args['restore'] );
246 if ( $ok ) {
247 \WP_CLI::success( sprintf( 'Attachment %d restored.', (int) $assoc_args['restore'] ) );
248 } else {
249 \WP_CLI::warning( 'Nothing to restore for that ID.' );
250 }
251 return;
252 }
253
254 if ( isset( $assoc_args['sweep'] ) ) {
255 $days = isset( $assoc_args['days'] ) ? (int) $assoc_args['days'] : null;
256 \WP_CLI::confirm( 'Permanently delete quarantined images past the retention window?', $assoc_args );
257 $result = Quarantine::sweep( $days );
258 \WP_CLI::success( sprintf( '%d image(s) deleted, %s reclaimed.', $result['deleted'], size_format( $result['bytes'], 1 ) ) );
259 return;
260 }
261
262 $ids = array_map( 'intval', $args );
263 if ( empty( $ids ) ) {
264 \WP_CLI::warning( 'Pass attachment IDs, or use --list / --restore / --sweep. Run `wp ablocks image unused` first.' );
265 return;
266 }
267
268 $held = 0;
269 $bytes = 0;
270 foreach ( $ids as $id ) {
271 $result = Quarantine::hold( $id );
272 if ( $result['ok'] ) {
273 $held++;
274 $bytes += (int) $result['bytes'];
275 } else {
276 \WP_CLI::warning( sprintf( '%d: %s', $id, $result['message'] ) );
277 }
278 }
279
280 \WP_CLI::success( sprintf( '%d image(s) quarantined, %s freed. Restore with --restore=<id>.', $held, size_format( $bytes, 1 ) ) );
281 }
282 }
283