You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress多站点中如何正确判断指定站点的自定义文章类型是否激活

解决WordPress多站点跨站判断自定义文章类型是否激活的问题

这个坑我之前踩过!本质原因是:自定义文章类型是在当前站点的init钩子里注册的,但switch_to_blog()只是切换了数据库连接和站点上下文,不会重新跑一遍目标站点的init钩子。这就导致切换站点后,目标站点的自定义post type根本没被注册到当前运行环境里,所以post_type_exists()的判断结果完全跟着初始加载的站点走,自然会出问题。

下面给你几个靠谱的解决办法,按需选就行:

方法1:切换站点后手动调用注册逻辑

如果你的注册代码是全局可访问的(比如在主题functions.php或者插件文件里),可以把注册逻辑封装成独立函数,切换站点后手动调用它,再做判断:

// 先把注册逻辑单独抽出来,方便复用
function register_recipe_post_type() {
    $args = array( 
        'public' => true, 
        'label' => __( 'Recipe', 'textdomain' ), 
        'menu_icon' => 'dashicons-book', 
    ); 
    // 只在站点14注册
    if( get_current_blog_id() === 14 ) { 
        register_post_type( 'recipe', $args ); 
    } 
}

// 原有的init钩子注册保留
add_action( 'init', 'register_recipe_post_type' );

// 封装一个跨站判断的函数
function is_recipe_active_on_blog( $target_blog_id ) {
    $current_id = get_current_blog_id();
    // 当前就是目标站点,直接判断就行
    if ( $current_id === $target_blog_id ) {
        return post_type_exists( 'recipe' );
    }

    // 切换到目标站点
    switch_to_blog( $target_blog_id );
    // 手动触发注册逻辑
    register_recipe_post_type();
    $exists = post_type_exists( 'recipe' );
    // 切回原站点
    restore_current_blog();

    return $exists;
}

// 用的时候直接调用
var_dump(is_recipe_active_on_blog(14)); // 不管当前在哪个站点,结果都准确

这个方法的好处是和你原有的注册逻辑完全对齐,不会出现判断条件不一致的问题;缺点是如果注册逻辑很复杂,手动调用可能会有重复执行的风险,但这里我们已经加了站点ID判断,所以只会在符合条件的站点注册,没问题。

方法2:直接查目标站点的数据库(最靠谱)

WordPress会把已注册的自定义文章类型存在站点的wp_post_types选项里(多站下表前缀是wp_{blog_id}_options),我们直接查这个选项就行,不用走注册流程:

function is_recipe_active_on_blog( $target_blog_id ) {
    $current_id = get_current_blog_id();
    $exists = false;

    if ( $current_id === $target_blog_id ) {
        $post_types = get_option( 'wp_post_types' );
        $exists = isset( $post_types['recipe'] );
    } else {
        // 获取目标站点的数据库表前缀
        $blog_prefix = $GLOBALS['wpdb']->get_blog_prefix( $target_blog_id );
        // 直接查目标站点的options表
        $post_types_data = $GLOBALS['wpdb']->get_var( $GLOBALS['wpdb']->prepare(
            "SELECT option_value FROM {$blog_prefix}options WHERE option_name = %s",
            'wp_post_types'
        ) );
        
        if ( $post_types_data ) {
            // 反序列化选项值
            $post_types = maybe_unserialize( $post_types_data );
            $exists = isset( $post_types['recipe'] );
        }
    }

    return $exists;
}

// 使用示例
var_dump(is_recipe_active_on_blog(14)); // 结果绝对准确

这个方法是我最推荐的——完全不依赖运行时的钩子或注册逻辑,直接从数据库拿最原始的信息,性能也更好,适合需要频繁跨站判断的场景,比如你做hreflang链接的情况。

方法3:清除post type缓存后用内置函数(不太推荐)

如果你想用WordPress原生的post_type_exists,可以切换站点后清除post type的缓存,再判断:

function is_recipe_active_on_blog( $target_blog_id ) {
    $current_id = get_current_blog_id();
    if ( $current_id === $target_blog_id ) {
        return post_type_exists( 'recipe' );
    }

    switch_to_blog( $target_blog_id );
    // 清除post type的缓存
    wp_cache_delete( 'post_types', 'wp' );
    $exists = post_type_exists( 'recipe' );
    restore_current_blog();

    return $exists;
}

不过这个方法有点玄学,有时候缓存清不干净,结果就不准,所以除非你特别想用内置函数,否则还是优先选前两种。

总结

做hreflang链接这种需要准确判断的场景,直接用方法2准没错;如果你的注册逻辑有额外的依赖(比如要检查某个插件是否激活才注册),那方法1更合适,能保证判断逻辑和注册逻辑完全一致。

内容的提问来源于stack exchange,提问作者marks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 19:48:10