get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = 'aksrt_resource' LIMIT 500"); if (empty($ids)) { // 无历史数据:直接打标记 update_option(self::OPT_RESOURCE_MIGRATED, time()); return; } foreach ($ids as $id) { $id = (int) $id; // 转 post_type $wpdb->update( $wpdb->posts, ['post_type' => 'post'], ['ID' => $id], ['%s'], ['%d'] ); update_post_meta($id, '_aksrt_is_resource', 1); clean_post_cache($id); } // 若一批迁移满 500,留待下次触发;否则收尾 if (count($ids) < 500) { update_option(self::OPT_RESOURCE_MIGRATED, time()); // 触发重写规则刷新(因为 /resource/{slug} 旧链接需要 301 重定向) delete_option('rewrite_rules'); } } /** * v4 形态归一迁移: * - aksrt_settings 中的 site_profile / opening_mode / archive_layout * / default_archive_layout / post_layout 全部 unset * - aksrt_basic_settings 中的 opening_mode / post_layout 全部 unset * - 全部分类的 aksrt_flow term meta 删除 * * 幂等。 */ private static function maybe_migrate_cms_format(): void { if (get_option(self::OPT_CMS_FORMAT_MIGRATED)) return; // 1. aksrt_settings $settings = get_option('aksrt_settings', []); if (is_array($settings)) { $changed = false; foreach (['site_profile', 'opening_mode', 'archive_layout', 'default_archive_layout', 'post_layout'] as $k) { if (array_key_exists($k, $settings)) { unset($settings[$k]); $changed = true; } } if ($changed) { update_option('aksrt_settings', $settings); } } // 2. aksrt_basic_settings $basic = get_option('aksrt_basic_settings', []); if (is_array($basic)) { $changed = false; foreach (['opening_mode', 'post_layout'] as $k) { if (array_key_exists($k, $basic)) { unset($basic[$k]); $changed = true; } } if ($changed) { update_option('aksrt_basic_settings', $basic); } } // 3. 删除全部分类的 aksrt_flow term meta global $wpdb; if ($wpdb instanceof wpdb) { $wpdb->delete($wpdb->termmeta, ['meta_key' => 'aksrt_flow'], ['%s']); } update_option(self::OPT_CMS_FORMAT_MIGRATED, time()); } private static function maybe_migrate_resource_pay_meta(): void { if (get_option(AKSRT_Domain_Model::RESOURCE_PAY_META_MIGRATED)) return; if (!is_admin() && !(defined('DOING_CRON') && DOING_CRON)) return; global $wpdb; $batch_size = 200; $cursor = (int) get_option(self::OPT_RESOURCE_PAY_META_CURSOR, 0); $candidate_keys = [ AKSRT_Domain_Model::PAY_META_KEY, AKSRT_Domain_Model::PAY_TYPE_KEY, AKSRT_Domain_Model::PAY_PRICE_KEY, AKSRT_Domain_Model::RESOURCE_MARKER_KEY, '_aksrt_res_pay_type', '_aksrt_res_price', '_aksrt_res_original_price', '_aksrt_res_vip1_price', '_aksrt_res_vip2_price', '_aksrt_res_version', '_aksrt_res_size', '_aksrt_res_license', '_aksrt_res_compat', '_aksrt_res_demo_url', '_aksrt_res_downloads', '_aksrt_res_require_login', '_aksrt_res_require_captcha', 'download_count', ]; $placeholders = implode(', ', array_fill(0, count($candidate_keys), '%s')); $sql = "SELECT DISTINCT pm.post_id FROM {$wpdb->postmeta} pm INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE p.post_type IN ('post', 'aksrt_resource') AND pm.meta_key IN ({$placeholders}) AND pm.post_id > %d ORDER BY pm.post_id ASC LIMIT %d"; $params = array_merge($candidate_keys, [$cursor, $batch_size]); $ids = $wpdb->get_col($wpdb->prepare($sql, $params)); if (empty($ids)) { delete_option(self::OPT_RESOURCE_PAY_META_CURSOR); update_option(AKSRT_Domain_Model::RESOURCE_PAY_META_MIGRATED, time()); return; } foreach ($ids as $post_id) { self::migrate_resource_pay_meta_post((int) $post_id); } update_option(self::OPT_RESOURCE_PAY_META_CURSOR, max(array_map('intval', $ids))); if (count($ids) < $batch_size) { delete_option(self::OPT_RESOURCE_PAY_META_CURSOR); update_option(AKSRT_Domain_Model::RESOURCE_PAY_META_MIGRATED, time()); } } private static function maybe_migrate_orders_to_repository(): void { if (get_option(AKSRT_Domain_Model::ORDER_MIGRATED_OPTION)) return; if (!class_exists('AKSRT_Order_Repository')) return; AKSRT_Order_Repository::get_instance()->migrate_from_option(); update_option(AKSRT_Domain_Model::ORDER_MIGRATED_OPTION, time()); } /** * §7.0 板块 taxonomy → plate CPT 一次性迁移。 * * 将 aksrt_forum_board taxonomy terms 转为 aksrt_forum_plate CPT posts, * 保留 term meta → post meta 映射、层级关系、版主数据。 * 同时在每个帖子上写入 _aksrt_plate_id 指向新 plate post。 * 旧 taxonomy 数据保留不删(向后兼容)。 */ private static function maybe_migrate_board_taxonomy_to_plate_cpt(): void { if (get_option(self::OPT_PLATE_CPT_MIGRATED)) return; if (!is_admin() && !(defined('DOING_CRON') && DOING_CRON)) return; if (!post_type_exists('aksrt_forum_plate')) return; $terms = get_terms([ 'taxonomy' => 'aksrt_forum_board', 'hide_empty' => false, 'orderby' => 'meta_value_num', 'meta_key' => '_aksrt_sort_order', 'order' => 'ASC', ]); if (is_wp_error($terms) || empty($terms)) { update_option(self::OPT_PLATE_CPT_MIGRATED, time()); return; } $term_to_plate = []; foreach ($terms as $term) { $existing = get_posts([ 'post_type' => 'aksrt_forum_plate', 'meta_key' => '_aksrt_migrated_from_term', 'meta_value' => (string) $term->term_id, 'numberposts' => 1, 'post_status' => 'any', 'fields' => 'ids', ]); if (!empty($existing)) { $term_to_plate[$term->term_id] = (int) $existing[0]; continue; } $plate_id = wp_insert_post([ 'post_type' => 'aksrt_forum_plate', 'post_title' => $term->name, 'post_content' => $term->description ?: '', 'post_excerpt' => wp_trim_words($term->description ?: '', 30, ''), 'post_status' => 'publish', 'post_parent' => 0, 'menu_order' => (int) get_term_meta($term->term_id, '_aksrt_sort_order', true), ], true); if (is_wp_error($plate_id)) { continue; } $term_to_plate[$term->term_id] = $plate_id; update_post_meta($plate_id, '_aksrt_migrated_from_term', $term->term_id); update_post_meta($plate_id, '_aksrt_sort_order', (int) get_term_meta($term->term_id, '_aksrt_sort_order', true)); update_post_meta($plate_id, '_aksrt_icon', (string) get_term_meta($term->term_id, '_aksrt_icon', true)); $moderators = get_term_meta($term->term_id, '_aksrt_moderators', true); if (is_array($moderators) && !empty($moderators)) { update_post_meta($plate_id, '_aksrt_moderators', $moderators); } $roles = get_term_meta($term->term_id, '_aksrt_moderator_roles', true); if (is_array($roles) && !empty($roles)) { update_post_meta($plate_id, '_aksrt_moderator_roles', $roles); } $topic_count = (int) get_term_meta($term->term_id, '_aksrt_topic_count', true); if ($topic_count <= 0) { $topic_count = (int) $term->count; } update_post_meta($plate_id, '_aksrt_posts_count', $topic_count); } // Resolve parent hierarchy foreach ($terms as $term) { if ($term->parent > 0 && isset($term_to_plate[$term->term_id], $term_to_plate[$term->parent])) { wp_update_post([ 'ID' => $term_to_plate[$term->term_id], 'post_parent' => $term_to_plate[$term->parent], ]); } } // Assign _aksrt_plate_id on existing topics global $wpdb; foreach ($term_to_plate as $term_id => $plate_id) { $topic_ids = $wpdb->get_col($wpdb->prepare( "SELECT tr.object_id FROM {$wpdb->term_relationships} tr INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id WHERE tt.term_id = %d AND tt.taxonomy = 'aksrt_forum_board'", $term_id )); foreach ($topic_ids as $topic_id) { update_post_meta((int) $topic_id, '_aksrt_plate_id', $plate_id); } } delete_option('rewrite_rules'); update_option(self::OPT_PLATE_CPT_MIGRATED, time()); } }