array( 'name' => __( '服务项目', 'fragrance-trade' ), 'singular_name' => __( '服务项目', 'fragrance-trade' ), 'add_new' => __( '添加服务项目', 'fragrance-trade' ), 'edit_item' => __( '编辑服务项目', 'fragrance-trade' ), 'all_items' => __( '全部服务项目', 'fragrance-trade' ), ), 'public' => true, 'has_archive' => 'services', 'rewrite' => array( 'slug' => 'services' ), 'menu_position' => 20, 'menu_icon' => 'dashicons-admin-customizer', 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ), 'show_in_rest' => true, ) ); register_post_type( 'case', array( 'labels' => array( 'name' => __( '案例作品', 'fragrance-trade' ), 'singular_name' => __( '案例', 'fragrance-trade' ), 'add_new' => __( '添加案例', 'fragrance-trade' ), 'edit_item' => __( '编辑案例', 'fragrance-trade' ), 'all_items' => __( '全部案例', 'fragrance-trade' ), ), 'public' => true, 'has_archive' => 'cases', 'rewrite' => array( 'slug' => 'cases' ), 'menu_position' => 21, 'menu_icon' => 'dashicons-format-gallery', 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ), 'show_in_rest' => true, ) ); register_taxonomy( 'case_type', 'case', array( 'labels' => array( 'name' => __( '案例分类', 'fragrance-trade' ), 'singular_name' => __( '案例分类', 'fragrance-trade' ), ), 'public' => true, 'hierarchical' => false, 'show_in_rest' => true, 'rewrite' => array( 'slug' => 'case-type' ), ) ); } add_action( 'init', 'fragrance_trade_register_post_types' ); /** Filter the case archive by the case_type query argument. */ function fragrance_trade_filter_cases_archive( $query ) { if ( is_admin() || ! $query->is_main_query() ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public archive filtering is read-only. if ( $query->is_post_type_archive( 'case' ) && ! empty( $_GET['case_type'] ) ) { $query->set( 'case_type', sanitize_text_field( wp_unslash( $_GET['case_type'] ) ) ); } } add_action( 'pre_get_posts', 'fragrance_trade_filter_cases_archive' ); /** Return the default service records created for a fresh installation. */ function fragrance_trade_service_seeds() { return array( 'b2b_product_1' => array( 'title' => __( '隐形车衣(TPU 保护膜)', 'fragrance-trade' ), 'content' => __( '透明保护膜覆盖车漆表面,可帮助降低日常轻微划痕、飞石和污渍对漆面的影响。具体性能取决于所选产品系列。', 'fragrance-trade' ), 'excerpt' => __( '车漆保护 · 透明外观 · 日常养护', 'fragrance-trade' ), ), 'b2b_product_2' => array( 'title' => __( '彩色改色膜', 'fragrance-trade' ), 'content' => __( '通过不同颜色和表面质感改变车辆外观,可根据车型、原车颜色和日常使用场景选择亮面、哑光等效果。', 'fragrance-trade' ), 'excerpt' => __( '颜色选择 · 表面质感 · 外观焕新', 'fragrance-trade' ), ), 'b2b_product_3' => array( 'title' => __( '隔热防爆膜', 'fragrance-trade' ), 'content' => __( '用于车窗隔热与紫外线防护,可结合透光需求、隐私需求和法规要求选择适合的产品参数。', 'fragrance-trade' ), 'excerpt' => __( '隔热需求 · 紫外线防护 · 车窗适用', 'fragrance-trade' ), ), 'b2b_product_4' => array( 'title' => __( '陶瓷隔热膜', 'fragrance-trade' ), 'content' => __( '陶瓷类隔热膜适合关注隔热表现和车内电子信号使用的车主,实际参数与适用位置以具体产品说明为准。', 'fragrance-trade' ), 'excerpt' => __( '陶瓷膜料 · 信号兼容 · 隔热方案', 'fragrance-trade' ), ), 'b2b_product_5' => array( 'title' => __( '天窗冰甲', 'fragrance-trade' ), 'content' => __( '面向全景天窗的隔热保护项目,需要结合天窗结构、玻璃状况和所选膜料确认是否适合施工。', 'fragrance-trade' ), 'excerpt' => __( '全景天窗 · 隔热需求 · 安装评估', 'fragrance-trade' ), ), 'b2b_product_6' => array( 'title' => __( '前挡专用膜', 'fragrance-trade' ), 'content' => __( '前挡膜重点平衡透光视野、隔热需求和夜间驾驶体验,选购时应核对产品参数及当地法规要求。', 'fragrance-trade' ), 'excerpt' => __( '前挡适用 · 透光视野 · 隔热需求', 'fragrance-trade' ), ), 'b2b_product_7' => array( 'title' => __( '个性定制彩绘膜', 'fragrance-trade' ), 'content' => __( '可根据参考图和车辆尺寸沟通定制外观方案,制作前确认图案、颜色、覆盖范围与交付效果。', 'fragrance-trade' ), 'excerpt' => __( '图案沟通 · 方案确认 · 定制施工', 'fragrance-trade' ), ), ); } /** Hashes of the previous untouched seed copy, used to avoid overwriting edited services. */ function fragrance_trade_legacy_service_hashes() { return array( 'b2b_product_1' => array( 'content' => '4ceefcf5b0d6835b2043eb974862641c4605408b249c47142a1384f8c6aba5a0', 'excerpt' => '474adc2b0a9cb84519f25b32f2aebaf66b7530c582d33a63fc428a70063982dd' ), 'b2b_product_2' => array( 'content' => 'c587d08672a5a73bd9d675a1aaa105b1dec46331a099649474a4669097c41707', 'excerpt' => 'edbbf896ccab06c5cbc79922f2130c190cb4dcd9720d427abd861c5d866d9de2' ), 'b2b_product_3' => array( 'content' => '49a236ff415f92de3c0a789ee42a7ea1083c60779f4dab3d80a162e9fbc534f7', 'excerpt' => '3be7e723aa8cfe1b5ce753e1ede8ceb5eb7122242a8bfde5dc6870e26291111e' ), 'b2b_product_4' => array( 'content' => '96db23ecaebbe16a7fd90254f098d9d652367ea200fe658792a7097082017d56', 'excerpt' => '3e59947da9a09130aeb65c0695c4b0ca1b78737e2cc320184a05ab0b4ca18424' ), 'b2b_product_5' => array( 'content' => '36d83bd3a439f92cdd89c4fb1e863e748d843733a9865b4740e9466c9ba0c916', 'excerpt' => '7e1985099340d070b75b2caa292cb877850bd7e7ed74a14d181dc98780d09666' ), 'b2b_product_6' => array( 'content' => 'caf3a595cc58b69861d66dbb92a04cfdddbe6ebfe7ef10a47e00e5cbbc112ea1', 'excerpt' => '1f1fb96587343da8d3fd938ec47f8f7abfb0a57c52a447c7b84997973ce57999' ), 'b2b_product_7' => array( 'content' => 'b1fda0e7a0c7b3445c61ac1ee1e53c7e27c0612c2e8706901f4a1c07d26959a0', 'excerpt' => '0815c3e0d55c9c491ecfa80d264f2c18e5112ab87e3366bc3bd7ca89c76a951c' ), ); } /** Find an existing seed by marker so a failed setup can be retried safely. */ function fragrance_trade_find_seeded_service( $seed_key ) { $ids = get_posts( array( 'post_type' => 'service', 'post_status' => array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' ), 'posts_per_page' => 1, 'fields' => 'ids', 'meta_key' => '_fragrance_seed_key', 'meta_value' => $seed_key, 'no_found_rows' => true, ) ); return $ids ? (int) $ids[0] : 0; } /** Locate an untouched service created by an older theme version and add its seed marker. */ function fragrance_trade_find_legacy_seed_service( $seed_key, $seed, $legacy_hashes ) { $posts = get_posts( array( 'post_type' => 'service', 'post_status' => array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' ), 'title' => $seed['title'], 'posts_per_page' => 5, 'no_found_rows' => true, ) ); foreach ( $posts as $post ) { if ( hash_equals( $legacy_hashes['content'], hash( 'sha256', $post->post_content ) ) && hash_equals( $legacy_hashes['excerpt'], hash( 'sha256', $post->post_excerpt ) ) ) { update_post_meta( $post->ID, '_fragrance_seed_key', $seed_key ); return (int) $post->ID; } } return 0; } /** Update only untouched seed copy; preserve every service that an administrator edited. */ function fragrance_trade_migrate_seed_service_copy( &$errors ) { $changed = false; $legacy_hashes = fragrance_trade_legacy_service_hashes(); foreach ( fragrance_trade_service_seeds() as $seed_key => $seed ) { $post_id = fragrance_trade_find_seeded_service( $seed_key ); if ( ! $post_id && isset( $legacy_hashes[ $seed_key ] ) ) { $post_id = fragrance_trade_find_legacy_seed_service( $seed_key, $seed, $legacy_hashes[ $seed_key ] ); } if ( ! $post_id || ! isset( $legacy_hashes[ $seed_key ] ) ) { continue; } $post = get_post( $post_id ); $update = array( 'ID' => $post_id ); if ( hash_equals( $legacy_hashes[ $seed_key ]['content'], hash( 'sha256', $post->post_content ) ) ) { $update['post_content'] = $seed['content']; } if ( hash_equals( $legacy_hashes[ $seed_key ]['excerpt'], hash( 'sha256', $post->post_excerpt ) ) ) { $update['post_excerpt'] = $seed['excerpt']; } if ( 1 === count( $update ) ) { continue; } $updated = wp_update_post( $update, true ); if ( is_wp_error( $updated ) ) { $errors[] = sprintf( /* translators: 1: service title, 2: error message. */ __( '无法更新服务“%1$s”的默认文案:%2$s', 'fragrance-trade' ), $seed['title'], $updated->get_error_message() ); continue; } $changed = true; } return $changed; } /** Create seed services while preserving legacy Customizer product values. */ function fragrance_trade_create_seed_services( &$errors ) { if ( get_option( 'fragrance_trade_setup_done' ) ) { return false; } $changed = false; foreach ( fragrance_trade_service_seeds() as $seed_key => $seed ) { if ( fragrance_trade_find_seeded_service( $seed_key ) ) { continue; } $title = get_theme_mod( $seed_key . '_title', $seed['title'] ); if ( ! $title ) { continue; } $post_id = wp_insert_post( array( 'post_type' => 'service', 'post_title' => $title, 'post_content' => get_theme_mod( $seed_key . '_text', $seed['content'] ), 'post_excerpt' => get_theme_mod( $seed_key . '_specs', $seed['excerpt'] ), 'post_status' => 'publish', ), true ); if ( is_wp_error( $post_id ) ) { $errors[] = sprintf( /* translators: 1: service title, 2: error message. */ __( '无法创建服务“%1$s”:%2$s', 'fragrance-trade' ), $title, $post_id->get_error_message() ); continue; } update_post_meta( $post_id, '_fragrance_seed_key', $seed_key ); $image = get_theme_mod( $seed_key . '_image', '' ); if ( $image ) { update_post_meta( $post_id, '_service_image', $image ); } $changed = true; } return $changed; } /** Find a conventional page, including the renamed slug WordPress uses in Trash. */ function fragrance_trade_find_required_page( $slug ) { $pages = get_posts( array( 'post_type' => 'page', 'post_status' => array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' ), 'post_name__in' => array( $slug, $slug . '__trashed' ), 'posts_per_page' => 1, 'orderby' => 'post_name__in', 'no_found_rows' => true, ) ); return $pages ? $pages[0] : null; } /** Create or repair the required pages without changing existing content or status. */ function fragrance_trade_create_required_pages( &$errors ) { $pages = array( 'home' => array( 'post_title' => __( '首页', 'fragrance-trade' ), 'template' => '' ), 'about' => array( 'post_title' => __( '关于门店', 'fragrance-trade' ), 'template' => 'page-about.php' ), 'faq' => array( 'post_title' => __( '常见问题', 'fragrance-trade' ), 'template' => 'page-faq.php' ), 'contact' => array( 'post_title' => __( '联系我们', 'fragrance-trade' ), 'template' => 'page-contact.php' ), ); $result = array( 'changed' => false, 'pages' => array() ); foreach ( $pages as $slug => $data ) { $page = fragrance_trade_find_required_page( $slug ); if ( $page ) { if ( $data['template'] && get_page_template_slug( $page->ID ) !== $data['template'] ) { $updated = wp_update_post( array( 'ID' => $page->ID, 'page_template' => $data['template'], ), true ); if ( is_wp_error( $updated ) ) { $errors[] = sprintf( /* translators: 1: page title, 2: error message. */ __( '无法更新页面“%1$s”的模板:%2$s', 'fragrance-trade' ), $page->post_title, $updated->get_error_message() ); } else { $result['changed'] = true; } } if ( 'publish' !== $page->post_status ) { // Preserve user-owned draft and trash states; the admin notice below explains the impact. } else { $result['pages'][ $slug ] = $page->ID; } continue; } $page_id = wp_insert_post( array( 'post_type' => 'page', 'post_name' => $slug, 'post_title' => $data['post_title'], 'post_status' => 'publish', 'page_template' => $data['template'], ), true ); if ( is_wp_error( $page_id ) ) { $errors[] = sprintf( /* translators: 1: page title, 2: error message. */ __( '无法创建页面“%1$s”:%2$s', 'fragrance-trade' ), $data['post_title'], $page_id->get_error_message() ); continue; } $result['changed'] = true; $result['pages'][ $slug ] = $page_id; } return $result; } /** * Preserve an existing posts page or create the conventional news page. * * @param string[] $errors Setup errors collected by the caller. * @return array{id:int,changed:bool} */ function fragrance_trade_ensure_news_page( &$errors ) { $result = array( 'id' => 0, 'changed' => false ); $current_page_id = absint( get_option( 'page_for_posts', 0 ) ); $current_page = $current_page_id ? get_post( $current_page_id ) : null; if ( $current_page && 'page' === $current_page->post_type ) { $result['id'] = $current_page_id; return $result; } $news_page = fragrance_trade_find_required_page( 'news' ); if ( ! $news_page ) { $news_page_id = wp_insert_post( array( 'post_type' => 'page', 'post_name' => 'news', 'post_title' => __( '新闻资讯', 'fragrance-trade' ), 'post_status' => 'publish', ), true ); if ( is_wp_error( $news_page_id ) ) { $errors[] = sprintf( /* translators: %s: error message. */ __( '无法创建新闻资讯页面:%s', 'fragrance-trade' ), $news_page_id->get_error_message() ); return $result; } $news_page = get_post( $news_page_id ); $result['changed'] = true; } $news_page_id = (int) $news_page->ID; if ( $current_page_id !== $news_page_id ) { update_option( 'page_for_posts', $news_page_id ); if ( $news_page_id !== absint( get_option( 'page_for_posts', 0 ) ) ) { $errors[] = __( '无法将新闻资讯页面设置为 WordPress 文章页。', 'fragrance-trade' ); return $result; } $result['changed'] = true; } $result['id'] = $news_page_id; return $result; } /** Versioned and retryable site setup. */ function fragrance_trade_maybe_setup_site() { $target_version = 4; if ( (int) get_option( 'fragrance_trade_schema_version', 0 ) >= $target_version ) { return; } $errors = array(); $seed_changed = fragrance_trade_create_seed_services( $errors ); $copy_changed = fragrance_trade_migrate_seed_service_copy( $errors ); $page_result = fragrance_trade_create_required_pages( $errors ); $news_result = fragrance_trade_ensure_news_page( $errors ); if ( ! empty( $page_result['pages']['home'] ) ) { update_option( 'page_on_front', $page_result['pages']['home'] ); update_option( 'show_on_front', 'page' ); } if ( $seed_changed || $copy_changed || $page_result['changed'] || $news_result['changed'] ) { flush_rewrite_rules(); } if ( $errors ) { update_option( 'fragrance_trade_setup_errors', array_values( array_unique( $errors ) ), false ); return; } delete_option( 'fragrance_trade_setup_errors' ); update_option( 'fragrance_trade_setup_done', 1 ); update_option( 'fragrance_trade_schema_version', $target_version ); } add_action( 'after_switch_theme', 'fragrance_trade_maybe_setup_site' ); add_action( 'admin_init', 'fragrance_trade_maybe_setup_site' ); /** Show actionable setup failures until they are resolved. */ function fragrance_trade_setup_errors_notice() { if ( ! current_user_can( 'switch_themes' ) ) { return; } $errors = get_option( 'fragrance_trade_setup_errors', array() ); if ( ! $errors || ! is_array( $errors ) ) { return; } ?>

post_status ) { $unpublished[] = $page->post_title; } } $posts_page_id = absint( get_option( 'page_for_posts', 0 ) ); $posts_page = $posts_page_id ? get_post( $posts_page_id ) : null; if ( $posts_page && 'page' === $posts_page->post_type && 'publish' !== $posts_page->post_status && ! in_array( $posts_page->post_title, $unpublished, true ) ) { $unpublished[] = $posts_page->post_title; } if ( ! $unpublished ) { return; } ?>