$ids) { if (!is_array($ids)) { continue; } $sidebars[$area] = array_values(array_diff($ids, [$widget_id])); } $option_name = 'widget_' . $id_base; $instances = get_option($option_name, []); if (is_array($instances) && array_key_exists($number, $instances)) { unset($instances[$number]); update_option($option_name, $instances, false); } } wp_set_sidebars_widgets($sidebars); foreach (array_reverse((array) ($manifest['comments'] ?? [])) as $id) { wp_delete_comment((int) $id, true); } foreach (array_reverse((array) ($manifest['posts'] ?? [])) as $id) { wp_delete_post((int) $id, true); } foreach (array_reverse((array) ($manifest['attachments'] ?? [])) as $id) { wp_delete_attachment((int) $id, true); } foreach (array_reverse((array) ($manifest['users'] ?? [])) as $id) { if (function_exists('wp_delete_user')) { wp_delete_user((int) $id); } } foreach (array_reverse((array) ($manifest['terms'] ?? [])) as $term) { wp_delete_term((int) ($term['id'] ?? 0), (string) ($term['taxonomy'] ?? 'category')); } delete_option($fixture_option); }; $existing = get_option($fixture_option, []); if ($fixture_action === 'cleanup') { if (!is_array($existing) || empty($existing)) { WP_CLI::success('No AKSRT visual fixtures found.'); return; } $cleanup($existing); WP_CLI::success('AKSRT visual fixtures removed.'); return; } if (is_array($existing) && !empty($existing)) { WP_CLI::error('Fixtures already exist. Run cleanup first.'); } if (!is_file($fixture_json)) { WP_CLI::error('Golden fixture JSON is missing.'); } $golden = json_decode((string) file_get_contents($fixture_json), true); if (!is_array($golden)) { WP_CLI::error('Golden fixture JSON is invalid.'); } $manifest = [ 'prefix' => $fixture_prefix, 'created_at' => gmdate('c'), 'terms' => [], 'users' => [], 'attachments' => [], 'posts' => [], 'comments' => [], 'widgets' => [], ]; update_option($fixture_option, $manifest, false); try { $term_map = []; foreach ((array) ($golden['dataset']['terms'] ?? []) as $source) { $taxonomy = (string) ($source['taxonomy'] ?? 'category'); $result = wp_insert_term( (string) ($source['name'] ?? 'Fixture'), $taxonomy, ['slug' => $fixture_prefix . (int) ($source['id'] ?? 0)] ); if (is_wp_error($result)) { throw new RuntimeException($result->get_error_message()); } $term_id = (int) $result['term_id']; $term_map[(int) $source['id']] = $term_id; $manifest['terms'][] = ['id' => $term_id, 'taxonomy' => $taxonomy]; } $user_map = []; foreach ((array) ($golden['dataset']['users'] ?? []) as $index => $source) { $login = $fixture_prefix . 'user_' . ((int) $index + 1); $user_id = wp_insert_user([ 'user_login' => $login, 'user_pass' => 'AKSRT-Visual-2026!', 'user_email' => $login . '@example.test', 'display_name' => (string) ($source['name'] ?? $login), 'role' => 'subscriber', ]); if (is_wp_error($user_id)) { throw new RuntimeException($user_id->get_error_message()); } $user_id = (int) $user_id; $user_map[(int) ($source['id'] ?? 0)] = $user_id; $manifest['users'][] = $user_id; update_user_meta($user_id, 'aksrt_points', (int) ($source['points'] ?? 0)); if ($index === 0) { update_user_meta($user_id, 'aksrt_vip_level', 2); update_user_meta($user_id, 'aksrt_vip_expires', time() + YEAR_IN_SECONDS); } } require_once ABSPATH . 'wp-admin/includes/image.php'; $media_sources = [ $fixture_theme_dir . '/assets/img/slider-bg.jpg', $fixture_theme_dir . '/assets/img/user_t.jpg', $fixture_theme_dir . '/assets/img/user-level-7.png', ]; foreach ($media_sources as $source_path) { if (!is_file($source_path)) { continue; } $upload = wp_upload_dir(); $filename = wp_unique_filename($upload['path'], $fixture_prefix . basename($source_path)); $target = trailingslashit($upload['path']) . $filename; if (!copy($source_path, $target)) { throw new RuntimeException('Unable to copy fixture media.'); } $attachment_id = wp_insert_attachment([ 'post_mime_type' => wp_check_filetype($target)['type'], 'post_title' => $fixture_prefix . pathinfo($filename, PATHINFO_FILENAME), 'post_status' => 'inherit', ], $target); 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, $target)); $manifest['attachments'][] = $attachment_id; } $post_map = []; foreach ((array) ($golden['dataset']['posts'] ?? []) as $index => $source) { $post_id = wp_insert_post([ 'post_title' => $fixture_prefix . (string) ($source['title'] ?? 'Fixture post'), 'post_name' => $fixture_prefix . (int) ($source['id'] ?? $index), 'post_status' => 'publish', 'post_type' => 'post', 'post_author' => (int) ($user_map[(int) ($source['author'] ?? 0)] ?? 1), 'post_excerpt' => '用于 AKSRT 与 Zibll 同内容视觉比较的固定摘要。', 'post_content' => '
固定正文内容,用于检查排版、目录、付费状态和响应式布局。
', ], true); if (is_wp_error($post_id)) { throw new RuntimeException($post_id->get_error_message()); } $post_id = (int) $post_id; $post_map[(int) ($source['id'] ?? 0)] = $post_id; $manifest['posts'][] = $post_id; $category_id = (int) ($term_map[(int) ($source['category'] ?? 0)] ?? 0); if ($category_id > 0) { wp_set_post_terms($post_id, [$category_id], 'category'); } if (!empty($manifest['attachments'])) { set_post_thumbnail($post_id, (int) $manifest['attachments'][$index % count($manifest['attachments'])]); } $pay_type = sanitize_key((string) ($source['pay_type'] ?? 'no')); $pay = class_exists('AKSRT\\Core\\DomainModel') ? \AKSRT\Core\DomainModel::default_pay_meta() : []; $pay['pay_type'] = $pay_type; $pay['price'] = $pay_type === 'no' ? 0 : 19.9 + $index; $pay['pay_limit'] = $pay_type === 'vip' ? 1 : 0; update_post_meta($post_id, '_aksrt_pay', $pay); update_post_meta($post_id, '_aksrt_pay_type', $pay_type); update_post_meta($post_id, '_aksrt_pay_price', $pay['price']); update_post_meta($post_id, 'aksrt_post_views', 1200 + ($index * 137)); } $no_image = wp_insert_post([ 'post_title' => $fixture_prefix . '无图长标题文章用于检查纯文字模式和两行截断行为', 'post_name' => $fixture_prefix . 'no-image', 'post_status' => 'publish', 'post_type' => 'post', 'post_content' => '无缩略图场景。
', ], true); if (!is_wp_error($no_image)) { $manifest['posts'][] = (int) $no_image; } if (!empty($manifest['posts'])) { stick_post((int) $manifest['posts'][0]); } $components = (array) ($golden['components'] ?? []); $sidebars = wp_get_sidebars_widgets(); $sidebars['home_top_content'] = is_array($sidebars['home_top_content'] ?? null) ? $sidebars['home_top_content'] : []; $sidebars['home_sidebar'] = is_array($sidebars['home_sidebar'] ?? null) ? $sidebars['home_sidebar'] : []; $number = 9100; foreach ($components as $slug => $component) { $id_base = sanitize_key((string) ($component['id_base'] ?? '')); if ($id_base === '') { continue; } $number++; $settings = (array) ($component['settings'] ?? []); $settings['title'] = $fixture_prefix . (string) ($settings['title'] ?? $slug); $option_name = 'widget_' . $id_base; $instances = get_option($option_name, []); $instances = is_array($instances) ? $instances : []; $instances[$number] = $settings; $instances['_multiwidget'] = 1; update_option($option_name, $instances, false); $widget_id = $id_base . '-' . $number; $area = (($component['size'] ?? '') === 'sidebar') ? 'home_sidebar' : 'home_top_content'; $sidebars[$area][] = $widget_id; $manifest['widgets'][] = ['id_base' => $id_base, 'number' => $number, 'area' => $area]; } wp_set_sidebars_widgets($sidebars); update_option($fixture_option, $manifest, false); WP_CLI::success('Created reversible AKSRT visual fixtures. Login password: AKSRT-Visual-2026!'); } catch (Throwable $error) { $cleanup($manifest); WP_CLI::error('Fixture creation rolled back: ' . $error->getMessage()); }