fix: avif tracking + new generate-missing-siblings command (v0.2.1)
Two related fixes to the AVIF pipeline: Fix #1 — postmeta tracking Format_Generator::process_avif_job() now updates _h4b_img_optim's avif_status from 'queued' → 'done' (with byte size) or 'error' (with reason) after the cron job runs. Previously the postmeta said 'queued' forever even when AVIF files existed on disk. Fix #2 — root cause of missing AVIFs on rds.ink bulk run wp_schedule_single_event(time()+30, …) coalesces identical args at the same timestamp, so bulk-queueing hundreds of AVIF jobs in the same second silently dropped many. Added wp h4b-img generate-missing-siblings that walks attachment metadata, finds files missing .webp/.avif, and generates them SYNCHRONOUSLY (no queue, no coalescing). Only processes registered sizes by default; --include-orphans flag for disk-walk mode. Verified on prod rds.ink: 1,134 of 1,737 registered images >=20KB have AVIF, 603 are missing. Of 389 orphan files >=20KB missing AVIF, those aren't referenced from any post/postmeta — correctly excluded. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -119,14 +119,88 @@ final class Format_Generator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cron entry point — encodes one queued path.
|
||||
* Cron entry point — encodes one queued path and updates per-attachment meta.
|
||||
*/
|
||||
public static function process_avif_job( string $source ): void {
|
||||
if ( ! is_readable( $source ) ) {
|
||||
self::record_avif_outcome( $source, [ 'status' => 'error', 'error' => 'source_unreadable' ] );
|
||||
return;
|
||||
}
|
||||
$settings = Settings::all();
|
||||
self::encode_avif_now( $source, $settings );
|
||||
$result = self::encode_avif_now( $source, $settings );
|
||||
self::record_avif_outcome( $source, $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the attachment + size_key that owns a given absolute path on disk,
|
||||
* then update its h4b postmeta with the AVIF outcome.
|
||||
*/
|
||||
private static function record_avif_outcome( string $source_path, array $result ): void {
|
||||
global $wpdb;
|
||||
$uploads = wp_get_upload_dir();
|
||||
$basedir = trailingslashit( $uploads['basedir'] );
|
||||
if ( strpos( $source_path, $basedir ) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
$rel = substr( $source_path, strlen( $basedir ) );
|
||||
$dir = dirname( $rel );
|
||||
$name = basename( $rel );
|
||||
|
||||
// Reverse the -<W>x<H> filename suffix to find the parent attachment file
|
||||
if ( preg_match( '/^(.+)-\d+x\d+(\.[a-z]+)$/i', $name, $m ) ) {
|
||||
$parent_name = $m[1] . $m[2];
|
||||
} else {
|
||||
$parent_name = $name;
|
||||
}
|
||||
$parent_rel = ( $dir === '.' ) ? $parent_name : "$dir/$parent_name";
|
||||
|
||||
$att_id = (int) $wpdb->get_var( $wpdb->prepare(
|
||||
"SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key=%s AND meta_value=%s LIMIT 1",
|
||||
'_wp_attached_file', $parent_rel
|
||||
) );
|
||||
if ( $att_id <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the size key that matches this file
|
||||
$meta = wp_get_attachment_metadata( $att_id );
|
||||
$size_key = null;
|
||||
if ( $name === $parent_name ) {
|
||||
$size_key = 'full';
|
||||
} elseif ( is_array( $meta ) && ! empty( $meta['sizes'] ) ) {
|
||||
foreach ( $meta['sizes'] as $sk => $sd ) {
|
||||
if ( ( $sd['file'] ?? '' ) === $name ) {
|
||||
$size_key = (string) $sk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $size_key === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$h4b_meta = Attachment_Meta::get( $att_id );
|
||||
if ( ! isset( $h4b_meta['sizes'][ $size_key ] ) ) {
|
||||
$h4b_meta['sizes'][ $size_key ] = [];
|
||||
}
|
||||
$entry = &$h4b_meta['sizes'][ $size_key ];
|
||||
if ( $result['status'] === 'done' ) {
|
||||
$entry['avif'] = $result['size'] ?? null;
|
||||
$entry['avif_status'] = 'done';
|
||||
} elseif ( $result['status'] === 'skipped' ) {
|
||||
$entry['avif_status'] = 'skipped';
|
||||
} else {
|
||||
$entry['avif_status'] = 'error';
|
||||
$entry['avif_error'] = $result['error'] ?? 'unknown';
|
||||
}
|
||||
// Clear from the pending bag too
|
||||
if ( isset( $h4b_meta['avif_pending'][ $size_key ] ) ) {
|
||||
unset( $h4b_meta['avif_pending'][ $size_key ] );
|
||||
if ( empty( $h4b_meta['avif_pending'] ) ) {
|
||||
unset( $h4b_meta['avif_pending'] );
|
||||
}
|
||||
}
|
||||
Attachment_Meta::set( $att_id, $h4b_meta );
|
||||
}
|
||||
|
||||
private static function encode_avif_now( string $source, array $settings ): array {
|
||||
|
||||
Reference in New Issue
Block a user