维护术语和自定义帖子之间严格的一对一关联

时间:2019-08-02 作者:Sean

我正在构建一个库存系统,其中库存项目有自己的页面,但标准WordPresspost 还可以使用这些库存项目标记post类型。据我所知,这意味着我必须实现自定义post类型(inventory) 提供每个项目的页面and 自定义的非层次分类法(inventory_item) 表示post 中的帖子类型和页面inventory 岗位类型。每个自定义贴子类型的贴子将与一个inventory_item 学期

假设以上是实现这种关系的最佳方法,那么这意味着我必须处理各种边缘情况,以确保维护自定义的post-to-term关系。例如:

inventory 帖子被编辑或删除,相应的inventory_item 术语也必须更新/删除inventory_item 条款本身,例如通过term 编辑页面或编辑术语元盒/古腾堡小部件。只有当相应的inventory 创建自定义帖子类型帖子inventory_item 单击链接时将用户带到相应自定义帖子的术语(例如在标记云中)

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

使用许多挂钩来维护分类法和自定义帖子之间的一对一关系是困难的,但并非不可能。由于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 );