$offset = isset($assoc_args['start']) ? (int)$assoc_args['start'] : 0;
$max = isset($assoc_args['max']) ? (int)$assoc_args['max'] : -1;
$processed = 0;
while (true) {
$posts = get_posts([
'post_type' => 'post',
'post_status' => ['publish', 'draft'],
'numberposts' => $batch,
'offset' => $offset,
]);
if (empty($posts)) {
WP_CLI::log("â
Done. All posts scanned.");
break;
}
foreach ($posts as $post) {
if ($max > 0 && $processed >= $max) {
WP_CLI::log("âšī¸ Reached max limit ({$max}). Stopping.");
return;
}
WP_CLI::log("đ Scanning post ID {$post->ID}");
if (has_post_thumbnail($post->ID)) {
WP_CLI::log("đ Already has featured image. Skipping.");
continue;
}
preg_match_all('/]+src=["\']([^"\']+)["\']/i', $post->post_content, $matches);
if (empty($matches[1])) {
WP_CLI::log("â ī¸ No images found in post content. Skipping.");
file_put_contents('skipped_posts.log', "{$post->ID}\n", FILE_APPEND);
continue;
}
foreach ($matches[1] as $img_url) {
if (strpos($img_url, 'data:image') === 0) {
WP_CLI::log("â Skipping base64-encoded image.");
continue;
}
WP_CLI::log("đŧī¸ Trying: $img_url");
$image_id = media_sideload_image($img_url, $post->ID, null, 'id');
if (!is_wp_error($image_id)) {
$meta = wp_get_attachment_metadata($image_id);
$width = $meta['width'] ?? 0;
$height = $meta['height'] ?? 0;
if ($width < 300 || $height < 300) {
WP_CLI::log("â Too small ({$width}x{$height}). Deleting.");
wp_delete_attachment($image_id, true);
continue;
}
set_post_thumbnail($post->ID, $image_id);
WP_CLI::success("â
Set image for post {$post->ID}");
break;
} else {
WP_CLI::warning("Failed to sideload image: " . $image_id->get_error_message());
file_put_contents('skipped_posts.log', "{$post->ID}\n", FILE_APPEND);
}
}
$processed++;
}
$offset += $batch;
gc_collect_cycles();
sleep(2); // Throttle to avoid system strain
}