用标签关联不同文章类型,并支持 ACF 人工覆盖

用标签关联不同文章类型,并支持 ACF 人工覆盖

产品、案例、新闻和应用可以通过共享标签建立自动关联;对少数特殊内容,再用 ACF Relationship 字段人工指定。这里的关键是先定义优先级,而不是把两个条件混在一个难以理解的查询里。

ACF Relationship 字段

让自定义文章类型支持标签

内置 post_tag 默认用于文章。可在注册文章类型时声明,或显式关联:

<?php
add_action(
    'init',
    function (): void {
        register_taxonomy_for_object_type(
            'post_tag',
            'application'
        );

        register_taxonomy_for_object_type(
            'post_tag',
            'case_study'
        );
    }
);

注册顺序要确保文章类型和 taxonomy 已经存在。更复杂的跨内容关联也可以单独注册一个站点专用 taxonomy,避免把普通博客标签和产品关系混在一起。

读取人工指定内容

建议把 ACF Relationship 字段 related_applications 设置为返回文章 ID。ID 比完整 WP_Post 数组更轻,也更容易与自动结果合并。

<?php
$current_id = get_the_ID();
$manual_ids = get_field(
    'related_applications',
    $current_id,
    false
);

$manual_ids = array_values(
    array_unique(
        array_filter(
            array_map( 'absint', (array) $manual_ids )
        )
    )
);

$limit = 5;
$ids   = array();

if ( $manual_ids ) {
    $ids = get_posts(
        array(
            'post_type'      => 'application',
            'post_status'    => 'publish',
            'post__in'       => $manual_ids,
            'orderby'        => 'post__in',
            'posts_per_page' => $limit,
            'fields'         => 'ids',
        )
    );
}

这里采用“人工指定优先,标签结果补足”的策略,而不是人工字段非空就完全放弃自动推荐。

查询同标签内容

<?php
$tag_ids = wp_get_post_terms(
    $current_id,
    'post_tag',
    array( 'fields' => 'ids' )
);

if ( is_wp_error( $tag_ids ) ) {
    $tag_ids = array();
}

if ( count( $ids ) < $limit && $tag_ids ) {
    $automatic = new WP_Query(
        array(
            'post_type'              => 'application',
            'post_status'            => 'publish',
            'posts_per_page'         => $limit - count( $ids ),
            'no_found_rows'          => true,
            'ignore_sticky_posts'    => true,
            'post__not_in'           => array_merge(
                array( $current_id ),
                $ids
            ),
            'tag__in'                => $tag_ids,
        )
    );

    $ids = array_merge(
        $ids,
        wp_list_pluck(
            $automatic->posts,
            'ID'
        )
    );
}

若使用自定义 taxonomy,把 tag__in 换成明确的 tax_query。不要把 slug 字符串直接拼进 SQL。

按最终顺序渲染

<?php
if ( $ids ) {
    $related = new WP_Query(
        array(
            'post_type'      => 'application',
            'post_status'    => 'publish',
            'post__in'       => $ids,
            'orderby'        => 'post__in',
            'posts_per_page' => count( $ids ),
            'no_found_rows'  => true,
        )
    );

    if ( $related->have_posts() ) {
        echo '<section aria-labelledby="related-title">';
        echo '<h2 id="related-title">相关应用</h2>';

        while ( $related->have_posts() ) {
            $related->the_post();
            get_template_part(
                'template-parts/content',
                'application-card'
            );
        }

        echo '</section>';
    }

    wp_reset_postdata();
}

模板片段中的链接、标题和图片应分别使用 esc_url()esc_html()wp_get_attachment_image()。不要直接信任 ACF 返回的任意 URL 或数组下标。

需要提前约定

  • 多个标签是“命中任意一个”还是“必须全部命中”。
  • 自动结果按日期、人工排序还是相关度排序。
  • 人工指定内容下线后如何补位。
  • 不同语言内容能否互相关联。
  • 是否允许关联回当前文章,或形成循环推荐。
  • 结果是否缓存,以及更新标签时如何失效。

ACF 参考:Relationship 字段。WordPress 参考:register_taxonomy_for_object_type()

最后更新于

ihopeful Blog 由博主亲笔撰写,重要信息可放心引用。