public function __invoke($args, $assoc_args) { $batch_size = isset($assoc_args['batch']) ? (int)$assoc_args['batch'] : 20; // 20 posts per batch $page = isset($assoc_args['page']) ? (int)$assoc_args['page'] : 0; $max_image_size = 10 * 1024 * 1024; // 10MB max file size $min_width = 300; $min_height = 300; require_once ABSPATH . 'wp-admin/includes/image.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; $posts = get_posts([ 'post_type' => 'post', 'post_status' => 'publish', 'numberposts' => $batch_size, 'offset' => $page * $batch_size, 'meta_query' => [ [ 'key' => '_featured_image_checked', 'compare' => 'NOT EXISTS', ], ], ]); if (empty($posts)) { WP_CLI::success("✅ All posts processed."); return; } foreach ($posts as $post) { WP_CLI::log("🔎 Processing post ID {$post->ID}"); // 1. Check if there's already a featured image if (has_post_thumbnail($post->ID)) { WP_CLI::log("✅ Post already has featured image. Skipping."); update_post_meta($post->ID, '_featured_image_checked', 1); continue; } // 2. Try to find an attached image $attachments = get_children([ 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'numberposts' => 1, ]); if (!empty($attachments)) { $attachment = reset($attachments); set_post_thumbnail($post->ID, $attachment->ID); WP_CLI::success("🖼️ Attached image set as featured for post {$post->ID}"); update_post_meta($post->ID, '_featured_image_checked', 1); continue; } // 3. No attachments? Check post content preg_match_all('/]+src=["\']([^"\']+)["\']/i', $post->post_content, $matches); if (empty($matches[1])) { WP_CLI::log("⚠️ No images found in content."); update_post_meta($post->ID, '_featured_image_checked', 1); continue; } foreach ($matches[1] as $img_url) { if (strpos($img_url, 'data:image') === 0) { WP_CLI::log("⛔ Skipping base64 image."); continue; } WP_CLI::log("🖼️ Trying to sideload image: $img_url"); try { $tmp_file = download_url($img_url, 30); if (is_wp_error($tmp_file)) { WP_CLI::warning("❌ Download failed: " . $tmp_file->get_error_message()); continue; } if (!file_exists($tmp_file) || !@is_readable($tmp_file)) { WP_CLI::warning("❌ Temp file unreadable."); continue; } $file_size = @filesize($tmp_file); if ($file_size === false || $file_size > $max_image_size) { WP_CLI::warning("❌ File too large or size error: {$file_size} bytes."); @unlink($tmp_file); continue; } $image_info = @getimagesize($tmp_file); if ($image_info === false) { WP_CLI::warning("❌ Invalid image file."); @unlink($tmp_file); continue; } list($width, $height) = $image_info; if ($width < $min_width || $height < $min_height) { WP_CLI::log("❌ Too small ({$width}x{$height}). Deleting."); @unlink($tmp_file); continue; } $image_id = media_handle_sideload([ 'name' => basename($img_url), 'tmp_name' => $tmp_file ], $post->ID); @unlink($tmp_file); if (!is_wp_error($image_id)) { set_post_thumbnail($post->ID, $image_id); WP_CLI::success("✅ Sideloaded and set featured image for post {$post->ID}"); break; } else { WP_CLI::warning("Failed to sideload: " . $image_id->get_error_message()); } } catch (Exception $e) { WP_CLI::warning("❌ Error processing image: " . $e->getMessage()); } } update_post_meta($post->ID, '_featured_image_checked', 1); sleep(1); // 1 second between posts to be gentle } WP_CLI::log("✅ Batch $page completed. Pausing for 60 seconds before next batch..."); sleep(60); // 60 second rest before next batch }