是否使用标记接口进行分层分类?

时间:2011-08-16 作者:supertrue

自定义分类法很棒。我注册了一系列新的分类法,并编写了一个导入程序,将我们的层次分类法导入到WordPress的XML中。问题是,一个分类法有大约1100个术语,浏览1100件事情的清单是残酷而不寻常的惩罚。

除了使用标记界面(具有自动完成功能的搜索框)之外,是否有其他方法可以使用层次分类法?

Update: Bainternet答案中的这段代码大部分都是这样的(为指定的分类法添加了标记接口,具有可工作的自动完成和正确填充的“最常用”标记云),但术语不会在保存后保存。如果帖子之前有条款,保存时会删除。所以我仍然在寻找答案。(如果分类法注册在hierarchichal设置为false,但问题的关键是在层次分类法上使用标记接口。)

//remove default metabox
//change TAXONOMY_NAME to your taxonomy name
add_action( \'admin_menu\' , \'remove_post_custom_fields\' );
function remove_post_custom_fields() {
    remove_meta_box( \'issuediv\' , \'post\' , \'normal\' ); 
}



//add our custom meta box
add_action( \'add_meta_boxes\', \'my_add_custom_box\' );

 function my_add_custom_box() {
    add_meta_box( 
//      \'myplugin_sectionid\',
        \'tagsdiv-issue\',
        __( \'New and Improved Issue Tags\', \'textdomain\' ),
        \'tags_like_custom_tax\',
        \'post\' 
    );
 }

 //call back function to display the metabox
 //change TAXONOMY_NAME to your taxonomy name 
 function tags_like_custom_tax(){
     $tax_name = \'issue\';
     global $post;
     $taxonomy = get_taxonomy($tax_name);
     $disabled = !current_user_can($taxonomy->cap->assign_terms) ? \'disabled="disabled"\' : \'\';
     ?>
     <div class="tagsdiv" id="<?php echo $tax_name; ?>">
        <div class="jaxtag">
            <div class="nojs-tags hide-if-js">
                <p><?php echo $taxonomy->labels->add_or_remove_items; ?></p>
                <textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php echo $disabled; ?>><?php echo get_terms_to_edit( $post->ID, $tax_name ); // textarea_escaped by esc_attr() ?></textarea>
            </div>
            <?php if ( current_user_can($taxonomy->cap->assign_terms) ) { ?>
            <div class="ajaxtag hide-if-no-js">
                <label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $taxonomy->labels->name; ?></label>
                <div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div>
                <p><input type="text" id="new-tag-<?php echo $tax_name; ?>" name="newtag[<?php echo $tax_name; ?>]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
                <input type="button" class="button tagadd" value="<?php esc_attr_e(\'Add\'); ?>" tabindex="3" /></p>
            </div>
            <p class="howto"><?php echo esc_attr( $taxonomy->labels->separate_items_with_commas ); ?></p>
            <?php } ?>
        </div>
        <div class="tagchecklist"></div>
    </div>
          <?php if ( current_user_can($taxonomy->cap->assign_terms) ) { ?>
            <p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php echo $taxonomy->labels->choose_from_most_used; ?></a></p>
          <?php } 
}
原始问题来自Wordpress论坛帖子here.

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

我是这样做的。只需添加一个条件,检查正在加载的页面是否为管理页面。如果是管理页面,请将Hierarchy设置为false,否则将Hierarchy设置为true。像这样:

$args = array( 
    \'hierarchical\' => true,
    \'labels\' => $labels,
    \'show_ui\' => true,
    \'query_var\' => true,
    \'rewrite\' => array( 
          \'slug\' => \'genre\'
    ), 
 )

if( is_admin() ) {
    $args[\'hierarchical\'] = false;
}

register_taxonomy(\'genre\', array(\'book\'), $args);
这应该给你一个想法。这样做的缺点是,您无法使用管理界面将父关系添加到术语中。您可以在is_admin() 有条件的,例如查看请求是否包含post-new.phppost.php

SO网友:Bainternet

我找到的唯一方法是删除默认元盒并创建自己的元盒,下面是我使用的代码:

//remove default metabox
//change TAXONOMY_NAME to your taxonomy name
add_action( \'admin_menu\' , \'remove_post_custom_fields\' );
function remove_post_custom_fields() {
    remove_meta_box( \'TAXONOMY_NAMEdiv\' , \'post\' , \'normal\' ); 
}



//add our custom meta box
add_action( \'add_meta_boxes\', \'my_add_custom_box\' );

 function my_add_custom_box() {
    add_meta_box( 
        \'myplugin_sectionid\',
        __( \'My Taxonomy Section Title\', \'textdomain\' ),
        \'tags_like_custom_tax\',
        \'post\' 
    );
 }

 //call back function to display the metabox
 //change TAXONOMY_NAME to your taxonomy name 
 function tags_like_custom_tax(){
     $tax_name = \'TAXONOMY_NAME\';
     global $post;
     $taxonomy = get_taxonomy($tax_name);
     $disabled = !current_user_can($taxonomy->cap->assign_terms) ? \'disabled="disabled"\' : \'\';
     ?>
     <div class="tagsdiv" id="<?php echo $tax_name; ?>">
        <div class="jaxtag">
            <div class="nojs-tags hide-if-js">
                <p><?php echo $taxonomy->labels->add_or_remove_items; ?></p>
                <textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php echo $disabled; ?>><?php echo get_terms_to_edit( $post->ID, $tax_name ); // textarea_escaped by esc_attr() ?></textarea>
            </div>
            <?php if ( current_user_can($taxonomy->cap->assign_terms) ) { ?>
            <div class="ajaxtag hide-if-no-js">
                <label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $box[\'title\']; ?></label>
                <div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div>
                <p><input type="text" id="new-tag-<?php echo $tax_name; ?>" name="newtag[<?php echo $tax_name; ?>]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
                <input type="button" class="button tagadd" value="<?php esc_attr_e(\'Add\'); ?>" tabindex="3" /></p>
            </div>
            <p class="howto"><?php echo esc_attr( $taxonomy->labels->separate_items_with_commas ); ?></p>
            <?php } ?>
        </div>
        <div class="tagchecklist"></div>
    </div>
          <?php if ( current_user_can($taxonomy->cap->assign_terms) ) { ?>
            <p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php echo $taxonomy->labels->choose_from_most_used; ?></a></p>
          <?php } 
}
至于储蓄,你不必担心,WordPress会帮你做到这一点。

Update, 我刚刚用类别对其进行了测试,效果很好:

enter image description here

SO网友:Tobias Hartlehnert

只有当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 \'&bull;\';
                }
                echo \'&nbsp;\'.$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>&nbsp;\' + 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(\'\');
        }
    });
});

SO网友:Adige72

我想我们可以添加一个隐藏的输入来检索所选标记的term_id 通过jQuery(AJAX)并使用函数将其保存为帖子的术语wp_set_object_terms.

我发布了另一个与此问题相关的问题:WP native tag suggest metabox. How does it process tag id?

SO网友:Bogdan

我找到了解决方案,如何use the tag interface on a hierarchical taxonomy.

首先,我们需要创建is\\u edit\\u page()函数:

/**
 * is_edit_page 
 * function to check if the current page is a post edit page
 * 
 * @author Ohad Raz <[email protected]>
 * 
 * @param  string  $new_edit what page to check for accepts new - new post page ,edit - edit post page, null for either
 * @return boolean
 */
function is_edit_page($new_edit = null){
    global $pagenow;
    //make sure we are on the backend
    if (!is_admin()) return false;


    if($new_edit == "edit")
        return in_array( $pagenow, array( \'post.php\',  ) );
    elseif($new_edit == "new") //check for new post page
        return in_array( $pagenow, array( \'post-new.php\' ) );
    else //check for either new or edit
        return in_array( $pagenow, array( \'post.php\', \'post-new.php\' ) );
}
*代码取自here.

现在,您可以使用kingkool68:

$args = array(
    //...
    \'hierarchical\' => true,
    //...
);
if( is_edit_page() ) {
    $args[\'hierarchical\'] = false;
}
它保存层次结构,但在编辑页面上显示分类,如标记(逗号分隔)。

结束

相关推荐

Posts vs Pages and categories

我正在为图书馆的收藏/档案室创建一个基本上静态的网站。由于我希望大多数内容只创建一次,并随着时间的推移慢慢添加或修改,而不是常规的帖子,所以我的第一个倾向是将所有内容都变成一个页面。另一方面,我有两个或三个类别的页面/帖子,我非常希望能够生成这些页面/帖子的列表,除了使用类别和帖子,我想不出一个好的方法来做到这一点。我知道有一个插件允许您使用类别标记页面,但我这样做时get\\u帖子并不总是有效。我有需要多个类别并相互重叠的内容,这一事实是否比这一内容基本上应该是静态的更重要?我有一个由专门针对特定主题的