只有当WP在保存时获取其term\\u ID时,才能添加层次分类法中的术语(请查看category的默认元盒如何工作以获得想法),因为在层次分类法中,如果这些术语位于层次树的不同分支中,则可以有多个相同的术语名称。
对于非层次术语,这是不可能的。正如所指出的here, 当从非层次分类法添加术语时,它们的ID由term\\u exists()通过术语名称检索,这显然只能在您具有唯一术语名称的情况下才能工作。所以我不认为kingkool68的答案适用于更复杂的分类情况。
因此,我通过结合使用标记样式的UI和层次分类metabox的“内部工作”来完成这项工作。我是以班纳特的例子为基础的。这里我的自定义分类法是“coverage”,它可以添加到帖子、附件和页面中。
PHP
//remove default metabox
add_action(\'admin_menu\', function() {
remove_meta_box(\'coveragesdiv\', [\'post\', \'attachment\', \'page\'], \'normal\');
});
//add our custom meta box
add_action(\'add_meta_boxes\', function() {
add_meta_box(
\'tagsdiv-coverages\',
__(\'Coverage\', \'textdomain\'),
\'coveragesMetaboxShow\',
[\'post\', \'attachment\', \'page\'],
\'side\'
);
});
//enqueue js for custom autosuggest/remove terms
add_action(\'admin_enqueue_scripts\', function() {
$screen = get_current_screen();
if ($screen->base == \'post\' && (in_array($screen->post_type, [\'post\', \'headlines\', \'attachment\', \'page\']))) {
wp_enqueue_script(\'coveragesMetaBoxJS\', plugin_dir_url(__FILE__) . \'../js/admin/coveragesMetaBox.js\', [\'jquery\', \'jquery-ui-autocomplete\']);
wp_localize_script(\'coveragesMetaBoxJS\', \'coveragesMetaBoxAjax\', [\'url\' => admin_url(\'admin-ajax.php\'), \'nonce\' => wp_create_nonce(\'coveragesMetaBoxNonce\')]);
}
});
//show metabox
function coveragesMetaboxShow() {
global $post;
$tax_name = \'coverages\';
$taxonomy = get_taxonomy($tax_name);
$bCanAssignTerms = current_user_can($taxonomy->cap->assign_terms);
$aryTerms = get_the_terms($post->ID, $tax_name);
?>
<style type="text/css">
.tagchecklist.coverages { margin-bottom:0; }
.tagchecklist.coverages.disabled { margin-left:0; }
.tagchecklist.coverages input { display:none; }
</style>
<div class="tagsdiv" id="<?php echo $tax_name; ?>">
<?php if ($bCanAssignTerms) { ?>
<label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $tax_name; ?></label>
<p>
<input type="text" id="new-tag-<?php echo $tax_name; ?>" class="newtag form-input-tip" autocomplete="off" value="" style="width:100%; float:none;">
</p>
<!-- needed so WP deletes all term relations on save if all terms where removed from UI -->
<input type="hidden" name="tax_input[<?php echo $tax_name; ?>][]" value="0">
<?php } ?>
<ul class="tagchecklist <?php echo $tax_name; if (!$bCanAssignTerms) { echo \' disabled\'; } ?>" role="list">
<?php
foreach($aryTerms AS $term) {
echo \'<li id="tax\'.$term->term_id.\'"><input value="\'.$term->term_id.\'" name="tax_input[\'.$tax_name.\'][]" type="checkbox" checked>\';
if ($bCanAssignTerms) {
echo \'<button type="button" class="ntdelbutton"><span class="remove-tag-icon" aria-hidden="true"></span></button>\';
}
else {
echo \'•\';
}
echo \' \'.$term->name.\'</li>\';
}
?>
</ul>
</div>
<?php
}
//custom autosuggest search; based on WP core https://developer.wordpress.org/reference/functions/wp_ajax_ajax_tag_search/
//no suitable hooks/filters there :(
add_action(\'wp_ajax_coveragesTagSearch\', function() {
if (isset($_GET[\'nonce\']) && wp_verify_nonce($_GET[\'nonce\'], \'coveragesMetaBoxNonce\')) {
if ( ! isset( $_GET[\'tax\'] ) ) {
wp_die( 0 );
}
$taxonomy = sanitize_key( $_GET[\'tax\'] );
$tax = get_taxonomy( $taxonomy );
if ( ! current_user_can( $tax->cap->assign_terms ) ) {
wp_die( -1 );
}
$s = wp_unslash( $_GET[\'term\'] );
$comma = _x( \',\', \'tag delimiter\' );
if ( \',\' !== $comma )
$s = str_replace( $comma, \',\', $s );
if ( false !== strpos( $s, \',\' ) ) {
$s = explode( \',\', $s );
$s = $s[count( $s ) - 1];
}
$s = trim( $s );
$term_search_min_chars = 2;
if ( ( $term_search_min_chars == 0 ) || ( strlen( $s ) < $term_search_min_chars ) ){
wp_die();
}
$results = get_terms( $taxonomy, array( \'name__like\' => $s, \'fields\' => \'id=>name\', \'hide_empty\' => false, \'number\' => 20 ) );
//change result format from associative array to array of objects; needed in jQuery.autocomplete\'s select event to get the term_id
$aryResults = [];
foreach ($results AS $term_id=>$term_name) {
$objTerm = new stdClass;
$objTerm->id = $term_id;
$objTerm->value = $term_name;
$aryResults[] = $objTerm;
}
echo json_encode($aryResults, JSON_NUMERIC_CHECK);
}
wp_die();
});
JS
jQuery(function() {
//remove term from UI
jQuery(\'.tagchecklist.coverages .ntdelbutton\').on(\'click\', function() {
jQuery(this).parent().remove();
});
//custom term autocomplete
jQuery(\'#new-tag-coverages\').autocomplete({
minLength:2,
source:coveragesMetaBoxAjax.url + \'?action=coveragesTagSearch&tax=coverages&nonce=\' + coveragesMetaBoxAjax.nonce,
select:function(event, ui) {
jQuery(\'.tagchecklist.coverages\').append(\'<li id="tax\' + ui.item.id + \'"><input value="\' + ui.item.id + \'" name="tax_input[coverages][]" type="checkbox" checked><button type="button" class="ntdelbutton"><span class="remove-tag-icon" aria-hidden="true"></span></button> \' + ui.item.value + \'</li>\');
//when selecting a term with the mouse from the autosuggest list, the close-event is triggered *after* the target value is set :(
window.setTimeout(function() { jQuery(event.target).val(\'\'); }, 100);
},
close:function(event, ui) {
jQuery(event.srcElement).val(\'\');
}
});
});