web-dev-qa-db-fra.com

Utiliser l'interface de balise pour la taxonomie hiérarchique?

Les taxonomies faites sur commande sont grandes. J'ai enregistré plusieurs nouvelles taxonomies et écrit à un importateur pour importer notre taxonomie hiérarchique dans WordPress à la XML. Le problème est qu’une taxonomie contient environ 1 100 termes et que parcourir une liste de contrôle de 1 100 éléments constitue un châtiment cruel et inhabituel.

Existe-t-il un moyen d'avoir une taxonomie hiérarchique mais d'utiliser plutôt l'interface Tag (champ de recherche avec complétion automatique)?

Update:ce code de la réponse de Bainternet y parvient en grande partie (ajoute une interface de balise pour la taxonomie spécifiée, avec le nuage de balises "le plus utilisé" autocomplete et correctement rempli), mais les termes ne sont pas sauvegardés sur poste sauver. Si la publication comportait des conditions antérieures, elles seront supprimées lors de la sauvegarde. Je cherche donc toujours une réponse. (Ce même code enregistre très bien les termes si la taxonomie est enregistrée avec hierarchichalset à false, mais le but de la question est d'utiliser l'interface de balise sur une taxonomie hiérarchique.)

//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 } 
}

La question initiale est empruntée à la publication sur le forum Wordpress ici .

3
supertrue

Voici comment je l'ai fait. Ajoutez simplement une condition qui vérifie si la page en cours de chargement est une page d’administrateur ou non. S'il s'agit d'une page d'administration, définissez hiérarchique sur false, sinon définissez hierarchical sur true. Ainsi:

$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);

Cela devrait vous donner une idée. L'inconvénient est que vous ne pouvez pas ajouter de relations parent aux termes à l'aide de l'interface d'administration. Vous pourriez obtenir plus de précisions dans la condition is_admin(), par exemple en cherchant à savoir si la demande contient post-new.php ou post.php

1
kingkool68

Le seul moyen que j'ai trouvé est de supprimer la metabox par défaut et de créer la vôtre, voici le code que j'ai utilisé:

//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 } 
}

Pour ce qui est des économies, vous n'avez pas à vous en soucier, WordPress le fait pour vous.

Mise à jour , je viens de le tester avec des catégories et cela fonctionne bien:

enter image description here

1
Bainternet

Les termes d'une taxonomie hiérarchique ne peuvent être ajoutés que si WP obtient leurs term_ids lors de leur enregistrement (observez comment la métabox par défaut de la catégorie fonctionne pour obtenir l'idée), car dans une taxonomie hiérarchique, il peut exister plusieurs noms de terme si ces termes sont dans différentes branches de l’arborescence.

Avec des termes non hiérarchiques, cela n'est pas possible. Comme il a été souligné ici , lors de l'ajout de termes issus d'une taxonomie non hiérarchique, leurs identifiants sont récupérés par term_exists () via les noms de termes, qui ne peuvent évidemment fonctionner que si vous avez des noms de termes uniques. Donc, je ne pense pas que la réponse de kingkool68 fonctionne dans des situations taxonomiques plus complexes.

J'ai donc réalisé ce travail en utilisant une combinaison de l'interface utilisateur de style balise et du "fonctionnement interne" d'une métabox de taxonomie hiérarchique. J'ai basé cela sur l'exemple de Bainternet. Ma taxonomie personnalisée ici est celle des "couvertures", qui peuvent être ajoutées à des publications, des pièces jointes et des pages.

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('');
        }
    });
});
0
Tobias Hartlehnert

Je pense que nous pouvons ajouter une entrée cachée qui récupère le term_id du tag sélectionné via jQuery (AJAX) et l'enregistrer en tant que terme du message en utilisant la fonction wp_set_object_terms.

J'ai posté une autre question relative à ce problème: WP la balise native suggère metabox. Comment traite-t-il l'id de balise?

0
Adige72

Je trouve la solution, commentutiliser l'interface de balise sur une taxonomie hiérarchique.

Pour le premier, nous devons créer la fonction is_edit_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' ) );
}

* code pris de ici .

Vous pouvez maintenant utiliser le code produit par kingkool68 :

$args = array(
    //...
    'hierarchical' => true,
    //...
);
if( is_edit_page() ) {
    $args['hierarchical'] = false;
}

Il enregistre la structure hiérarchique, mais affiche les taxonomies sur la page d'édition comme des balises (séparées par des virgules).

0
Bogdan