$state) { if (!empty($state['exists'])) { update_option((string) $name, $state['value'], false); } else { delete_option((string) $name); } } delete_option($manifest_key); }; $existing = get_option($manifest_key, []); if ($action === 'cleanup') { if (!is_array($existing) || !$existing) { WP_CLI::success('No article visual fixtures found.'); return; } $cleanup($existing); WP_CLI::success('Article visual fixtures removed.'); return; } if (is_array($existing) && $existing) { WP_CLI::error('Fixtures already exist. Run cleanup first.'); } $manifest = [ 'created_at' => gmdate('c'), 'users' => [], 'terms' => [], 'attachments' => [], 'posts' => [], 'files' => [], 'options' => [], ]; foreach (['aksrt_settings', 'zibll_options'] as $option_name) { $manifest['options'][$option_name] = [ 'exists' => get_option($option_name, null) !== null, 'value' => get_option($option_name), ]; } update_option($manifest_key, $manifest, false); try { $visual_options = [ 'list_type' => 'thumb', 'list_show_type' => 'separate', 'list_list_option' => ['style' => 'null', 'img_position' => 'left', 'scale' => 70], 'list_card_option' => ['style' => 'null', 'scale' => 70], 'post_list_author' => true, 'post_list_time' => true, 'post_time_source' => 'modified', 'list_meta_show' => 'like', 'list_badge_show' => ['pay', 'cat', 'tag'], 'list_thumb_slides_s' => true, 'list_thumb_video_s' => true, 'list_thumb_video_mute_s' => true, 'thumb_postfirstimg_s' => true, 'thumb_catimg_s' => true, 'list_thumb_fit' => '', 'paging_ajax_s' => '1', 'paging_ajax_ias_s' => true, 'ias_max' => 3, 'post_related_s' => true, 'post_related_type' => 'img', 'post_related_n' => 6, 'post_related_orderby' => 'views', 'related_title' => '相关推荐', ]; foreach (['aksrt_settings', 'zibll_options'] as $option_name) { $current = get_option($option_name, []); update_option($option_name, array_merge(is_array($current) ? $current : [], $visual_options), false); } $authors = [ ['login' => $prefix . 'author_a', 'name' => '视觉作者甲'], ['login' => $prefix . 'author_b', 'name' => '视觉作者乙'], ]; $author_ids = []; foreach ($authors as $author) { $user_id = wp_insert_user([ 'user_login' => $author['login'], 'user_pass' => 'AKSRT-Visual-2026!', 'user_email' => $author['login'] . '@example.test', 'display_name' => $author['name'], 'description' => '固定作者简介,用于文章卡片视觉对比。', 'role' => 'author', ]); if (is_wp_error($user_id)) { throw new RuntimeException($user_id->get_error_message()); } $author_ids[] = (int) $user_id; $manifest['users'][] = (int) $user_id; } $category = wp_insert_term('视觉文章', 'category', ['slug' => 'zibll-article-fixture']); $tag = wp_insert_term('视觉标签', 'post_tag', ['slug' => 'zibll-visual-tag']); if (is_wp_error($category) || is_wp_error($tag)) { throw new RuntimeException('Unable to create article fixture terms.'); } $category_id = (int) $category['term_id']; $tag_id = (int) $tag['term_id']; $manifest['terms'][] = ['id' => $category_id, 'taxonomy' => 'category']; $manifest['terms'][] = ['id' => $tag_id, 'taxonomy' => 'post_tag']; require_once ABSPATH . 'wp-admin/includes/image.php'; $upload = wp_upload_dir(); if (!empty($upload['error'])) { throw new RuntimeException((string) $upload['error']); } $attachment_ids = []; $colors = [ [240, 68, 148], [58, 134, 255], [92, 191, 147], [255, 175, 56], [126, 87, 194], ]; foreach ($colors as $index => $rgb) { $filename = $prefix . 'image-' . ($index + 1) . '.jpg'; $filepath = trailingslashit($upload['path']) . $filename; if (function_exists('imagecreatetruecolor')) { $image = imagecreatetruecolor(1200, 800); $background = imagecolorallocate($image, $rgb[0], $rgb[1], $rgb[2]); $foreground = imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $background); imagestring($image, 5, 48, 48, 'Zibll 9.0 Article Fixture ' . ($index + 1), $foreground); imagejpeg($image, $filepath, 92); imagedestroy($image); } else { $pixel = base64_decode('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAP//////////////////////////////////////////////////////////////////////////////////////2wBDAf//////////////////////////////////////////////////////////////////////////////////////wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAX/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAEf/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwF//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwF//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQAGPwJ//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABPyF//9oADAMBAAIAAwAAABAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABPxB//9k=', true); file_put_contents($filepath, $pixel); } $attachment_id = wp_insert_attachment([ 'post_mime_type' => 'image/jpeg', 'post_title' => '视觉图片 ' . ($index + 1), 'post_status' => 'inherit', ], $filepath); if (is_wp_error($attachment_id)) { throw new RuntimeException($attachment_id->get_error_message()); } $attachment_id = (int) $attachment_id; wp_update_attachment_metadata($attachment_id, wp_generate_attachment_metadata($attachment_id, $filepath)); $attachment_ids[] = $attachment_id; $manifest['attachments'][] = $attachment_id; } $image_urls = array_map(static fn(int $id): string => (string) wp_get_attachment_image_url($id, 'full'), $attachment_ids); $video_path = trailingslashit($upload['path']) . $prefix . 'fixture-video.mp4'; file_put_contents($video_path, ''); $manifest['files'][] = $video_path; $video_url = trailingslashit($upload['url']) . basename($video_path); $term_other = (array) get_term_meta($category_id, 'zib_other_data', true); $term_other['cover_image'] = $image_urls[4]; update_term_meta($category_id, 'zib_other_data', $term_other); update_term_meta($category_id, 'cover_image', $image_urls[4]); update_term_meta($category_id, 'aksrt_category_cover_id', $attachment_ids[4]); $scenarios = [ ['slug' => 'featured', 'title' => '特色图文章:标准列表与卡片基线', 'featured' => 0], ['slug' => 'no-image', 'title' => '无图长标题文章用于检查纯文字模式与两行截断', 'no_image' => true], ['slug' => 'multi', 'title' => '多图文章:四张真实内容图片', 'featured' => 1, 'gallery' => true], ['slug' => 'external', 'title' => '自定义外链封面文章', 'external' => 2], ['slug' => 'slides', 'title' => '幻灯片封面文章', 'featured' => 3, 'slides' => true], ['slug' => 'video', 'title' => '视频悬停封面文章', 'featured' => 4, 'video' => true], ['slug' => 'paid', 'title' => '付费阅读文章价格徽章', 'featured' => 0, 'pay' => 'reading'], ['slug' => 'vip', 'title' => '会员专属文章 VIP 徽章', 'featured' => 1, 'pay' => 'vip'], ['slug' => 'first-image', 'title' => '文章首图作为缩略图', 'first_image' => 3], ]; foreach ($scenarios as $index => $scenario) { $content = '

固定摘要正文,用于 Zibll 与 AKSRT 的文章列表逐像素比较。

'; if (!empty($scenario['gallery'])) { $content .= implode('', array_map(static fn(string $url): string => '', array_slice($image_urls, 0, 4))); } elseif (isset($scenario['first_image'])) { $content .= ''; } $post_id = wp_insert_post([ 'post_type' => 'post', 'post_status' => 'publish', 'post_author' => $author_ids[$index % 2], 'post_title' => $scenario['title'], 'post_name' => $prefix . $scenario['slug'], 'post_excerpt' => '固定文章摘要用于检查字号、行高、留白和截断。', 'post_content' => $content, 'post_date' => gmdate('Y-m-d H:i:s', strtotime('2026-07-01 08:00:00') + ($index * DAY_IN_SECONDS)), 'post_date_gmt' => gmdate('Y-m-d H:i:s', strtotime('2026-07-01 00:00:00') + ($index * DAY_IN_SECONDS)), ], true); if (is_wp_error($post_id)) { throw new RuntimeException($post_id->get_error_message()); } $post_id = (int) $post_id; $manifest['posts'][] = $post_id; wp_set_post_terms($post_id, [$category_id], 'category'); wp_set_post_terms($post_id, [$tag_id], 'post_tag'); if (isset($scenario['featured'])) { set_post_thumbnail($post_id, $attachment_ids[(int) $scenario['featured']]); } if (!empty($scenario['gallery'])) { set_post_format($post_id, 'gallery'); } $post_meta = [ 'subtitle' => ' · 固定副标题', ]; $zib_meta = (array) get_post_meta($post_id, 'zib_other_data', true); $zib_meta['subtitle'] = $post_meta['subtitle']; if (isset($scenario['external'])) { $post_meta['thumbnail_url'] = $image_urls[(int) $scenario['external']]; $zib_meta['thumbnail_url'] = $post_meta['thumbnail_url']; } if (!empty($scenario['slides'])) { $post_meta['featured_slide'] = implode(',', array_slice($attachment_ids, 0, 4)); $zib_meta['featured_slide'] = $post_meta['featured_slide']; } if (!empty($scenario['video'])) { $post_meta['featured_video'] = $video_url; $zib_meta['featured_video'] = $video_url; } $zib_meta['views'] = 1200 + ($index * 137); $zib_meta['like'] = 30 + ($index * 7); update_post_meta($post_id, 'zib_other_data', $zib_meta); update_post_meta($post_id, 'aksrt_post_meta', $post_meta); update_post_meta($post_id, 'aksrt_post_views', $zib_meta['views']); update_post_meta($post_id, '_aksrt_like_count', $zib_meta['like']); update_post_meta($post_id, '_aksrt_favorite_count', 10 + $index); $pay_type = (string) ($scenario['pay'] ?? 'no'); $pay_limit = $pay_type === 'vip' ? 2 : 0; $pay_price = $pay_type === 'reading' ? 19.9 : 0; update_post_meta($post_id, '_aksrt_pay', [ 'pay_type' => $pay_type, 'pay_modo' => '0', 'price' => $pay_price, 'pay_limit' => $pay_limit, ]); update_post_meta($post_id, 'posts_zibpay', [ 'pay_type' => $pay_type, 'pay_modo' => '0', 'pay_price' => $pay_price, 'pay_limit' => $pay_limit, ]); } if ($manifest['posts']) { stick_post((int) $manifest['posts'][0]); } update_option($manifest_key, $manifest, false); WP_CLI::success('Created identical Zibll/AKSRT article fixtures.'); } catch (Throwable $error) { $cleanup($manifest); WP_CLI::error('Fixture creation rolled back: ' . $error->getMessage()); }