每个自定义分类中仅允许每个术语的一个实例

时间:2016-03-05 作者:Pete

我正在寻找一个函数,该函数将每个术语的创建限制为每个自定义分类法中只有一个实例。每个自定义分类法可能具有相同的术语,但该术语在每个不同的自定义分类法中只能出现一次。我猜对于每个自定义分类法,这都需要一个函数。

1 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

这是一个很有趣的问题。我真的找不到任何容易的事。术语创建由wp_insert_term() 作用如果您查看源代码,就会发现在插入术语之前,我们实际上没有太多可以使用的过滤器或操作。pre_insert_term 是关于术语验证和插入之前发生的唯一筛选器。

默认情况下,在任何层次分类法中,如果术语不在同一层次结构中,则可以有名称重复的术语。没有任何过滤器或操作可以改变此行为,因此我们面临的挑战是停止此行为并确保一个术语只能有一个实例。

非层次分类法,因为只能有顶级术语,不会有这个问题。不能有任何其他同名术语。

然而,上述规则有一个例外,每当我们显式设置一个唯一的slug时,我们可以在同一级别上使用相同名称的术语。然而,我们将跳过这一切,只关注所提供的术语名称

所以我们只剩下pre_insert_term 滤器让我们看看可能的解决方案

add_filter( \'pre_insert_term\', function ( $term, $taxonomy )
{
    /**
     * Start by validating the term. The taxonomy is already validated
     * 
     * If the term is a numeric or int value, we will bail. We will let wp_insert_term
     * handle the process from here on. This is just a very loose check on our side
     */
    if ( is_numeric( $term ) )
        return $term;

    /**
     * $term is a valid non numeric string, so we most probably have a term name
     *
     * We will now basically use the same logic as `wp_insert_term` to validate the $term
     * name.
     */
    $term_name = strtolower( filter_var( $term, FILTER_SANITIZE_STRING ) );

    /**
     * Get all terms which matchings names like $term_name
     *
     * Getting terms by name is not an exact match, but a LIKE comparison, so
     * if you have names like \'Term A\', \'term a\' and \'term A\', they all will match.
     * We will need to do an exact match later on
     */
    $name_matches = get_terms( 
        $taxonomy, 
        [
            \'name\'       => $term_name,
            \'hide_empty\' => false,
            \'fields\'     => \'names\', // Only get term names
        ] 
    );
    // If $name_matches is empty, we do not have duplicates, bail
    if ( !$name_matches )
        return $term;

    // Convert all names into lowercase
    $names_array = array_map( \'strtolower\', $name_matches );
    // Test to see if we have an exact term name match, if so, return WP_Error
    if ( in_array( $term_name, $names_array ) )
        return new WP_Error( 
            \'term_exists\',
            __( \'You cannot have a term with the same name, choose a unique name.\' ),
            $term 
        );

    // OK we have a unique term name, let \'wp_insert_term\' continue the rest of the process
    return $term;   
}, 10, 2 );
我们所做的是获取所有名称与要插入的术语类似的术语,将它们全部转换为小写,然后测试术语名称是否在术语名称数组中。如果是,我们将返回WP_Error 对象以停止整个术语插入过程

显然,您不需要在分类法之间进行任何其他检查,因为您可以在不同的分类法之间使用相同名称的术语。