使用许多挂钩来维护分类法和自定义帖子之间的一对一关系是困难的,但并非不可能。由于WordPress旨在允许许多帖子标记许多术语,因此需要使用各种挂钩来防止在没有自定义帖子的情况下创建术语,反之亦然。
下面的代码显示了完整的系统,包括自定义帖子类型和分类的注册。它具有钩子,用于在自定义帖子类型中创建新帖子时触发相应分类术语的创建,以及在编辑或删除它们时进行处理。它还禁用术语编辑器和各种用户权限,以阻止用户直接编辑分类术语。它还覆盖前端的术语链接,不再指向带有术语标记的帖子上的术语存档页面,而是链接到相应的自定义单个帖子。最后,它删除了普通(非自定义)帖子在保存时在自定义分类法中标记的任何无效术语,因为WordPress允许用户通过编辑器创建新术语,这是我们不希望看到的。
在我的插件中可以看到工作环境中的代码示例,Academic Labbook Plugin.
// Register the custom post type.
function wpse_344265_register_post_type() {
$args = array(
\'labels\' => $labels,
\'description\' => __( \'My custom post type.\', \'my-text-domain\' ),
\'public\' => true,
\'hierarchical\' => false,
\'show_in_rest\' => true,
);
register_post_type( \'my-custom-post-type\', $args );
}
add_action( \'init\', \'wpse_344265_register_post_type\' );
// Create corresponding custom taxonomy terms whenever posts are created.
function wpse_344265_associate_custom_post_with_term( $post_id, $post ) {
if ( \'my-custom-post-type\' !== $post->post_type ) {
return;
}
if ( defined( \'DOING_AUTOSAVE\' ) && DOING_AUTOSAVE ) {
// Don\'t create term for autosaves.
return;
}
if ( \'publish\' !== $post->post_status ) {
// Don\'t create a term unless the post is being published.
return;
}
// Add or update the associated term.
wpse_344265_update_custom_taxonomy_term( $post );
}
add_action( \'save_post\', \'wpse_344265_associate_custom_post_with_term\', 10, 2 );
// Delete corresponding custom taxonomy terms whenever posts are deleted.
function wpse_344265_delete_associated_custom_post_term( $post_id ) {
$post = get_post( $post_id );
if ( is_null( $post ) ) {
// Invalid post.
return;
}
if ( \'my-custom-post-type\' !== $post->post_type ) {
return;
}
$term = wpse_344265_get_custom_term( $post );
if ( ! $term ) {
// No term to delete.
return;
}
wp_delete_term( $term->term_id, \'my-custom-taxonomy\' );
clean_term_cache( array( $term->term_id ), \'my-custom-taxonomy\' );
}
add_action( \'deleted_post\', \'wpse_344265_delete_associated_custom_post_term\' );
function wpse_344265_update_custom_taxonomy_term( $post ) {
$post = get_post( $post );
if ( is_null( $post ) ) {
// Invalid post.
return;
}
// Get custom term, if present.
$term = wpse_344265_get_custom_term( $post );
// Temporarily disable the filter that blocks creation of terms.
remove_filter( \'pre_insert_term\', \'wpse_344265_disallow_insert_term\', 10, 2 );
if ( ! $term ) {
// Term doesn\'t yet exist.
$args = array(
\'slug\' => wpse_344265_get_custom_taxonomy_term_slug( $post ),
);
wp_insert_term( $post->post_title, \'my-custom-taxonomy\', $args );
} else {
// Update term.
$args = array(
\'name\' => $post->post_title,
\'slug\' => wpse_344265_get_custom_taxonomy_term_slug( $post ),
);
wp_update_term( $term->term_id, \'my-custom-taxonomy\', $args );
}
// Re-enable the filter.
add_filter( \'pre_insert_term\', wpse_344265_disallow_insert_term, 10, 2 );
}
function wpse_344265_get_custom_term( $post ) {
$post = get_post( $post );
if ( is_null( $post ) ) {
// Invalid post.
return;
}
$slug = wpse_344265_get_custom_taxonomy_term_slug( $post );
return get_term_by( \'slug\', $slug, \'my-custom-taxonomy\' );
}
function wpse_344265_get_custom_taxonomy_term_slug( $post ) {
$post = get_post( $post );
if ( is_null( $post ) ) {
// Invalid post.
return;
}
// Use the custom post\'s ID since this doesn\'t change even if e.g. its slug does.
return $post->ID;
}
function wpse_344265_register_taxonomy() {
$args = array(
\'hierarchical\' => false,
\'labels\' => array(
\'name\' => __( \'My custom taxonomy\', \'my-text-domain\' ),
),
\'capabilities\' => array(
\'manage_terms\' => \'do_not_allow\',
\'edit_terms\' => \'do_not_allow\',
\'delete_terms\' => \'do_not_allow\',
\'assign_terms\' => \'edit_posts\', // Needed to allow assignment in block editor.
),
\'public\' => true,
\'show_in_menu\' => false, // Hides the term edit page.
\'show_in_rest\' => true, // Needed for block editor support.
\'show_admin_column\' => true, // Show associated terms in admin edit screen.
);
$supported_post_types = array(
\'post\',
);
register_taxonomy( \'my-custom-taxonomy\', $supported_post_types, $args );
}
add_action( \'init\', \'wpse_344265_register_taxonomy\' );
// Override default term links to point towards the term custom post instead of term
// archive.
function wpse_344265_override_term_link( $link, $term, $taxonomy ) {
if ( \'my-custom-taxonomy\' !== $taxonomy ) {
return $link;
}
$my_custom_post = wpse_344265_get_post_from_custom_term( $term );
if ( is_null( $my_custom_post ) ) {
return $link;
}
return get_permalink( $my_custom_post );
}
add_filter( \'term_link\', \'wpse_344265_override_term_link\', 10, 3 );
function wpse_344265_get_post_from_custom_term( $term ) {
// The term\'s slug is the post ID.
return get_post( $term->slug );
}
// Disallow creation of new terms directly.
function wpse_344265_disallow_insert_term( $term, $taxonomy ) {
if ( \'my-custom-taxonomy\' !== $taxonomy ) {
return $term;
}
// Return an error in all circumstances.
return new WP_Error(
\'wpse_344265_disallow_insert_term\',
__( \'Your role does not have permission to add terms to this taxonomy\', \'my-text-domain\' )
);
}
add_filter( \'pre_insert_term\', \'wpse_344265_disallow_insert_term\', 10, 2 );
// Delete any invalid custom taxonomy items when post terms are set.
function wpse_344265_reject_invalid_terms( $object_id, $tt_id, $taxonomy ) {
if ( \'my-custom-taxonomy\' !== $taxonomy ) {
return;
}
$term = get_term_by( \'term_taxonomy_id\', $tt_id, \'my-custom-taxonomy\' );
if ( ! $term ) {
// Nothing to do here.
return;
}
// Check term is valid.
$custom_post = wpse_344265_get_post_from_custom_term( $term );
if ( ! $custom_post ) {
// This is not a valid custom taxonomy term - delete it.
wp_delete_term( $term->term_id, \'my-custom-taxonomy\' );
}
}
add_action( \'added_term_relationship\', \'wpse_344265_reject_invalid_terms\', 10, 3 );