Control term order on a per-post basis

I have a taxonomy in which term order matters, but varies from post to post. So I want to be able to set the order that terms are displayed in on a per-post basis:

  • My first post | Tagged: Apples, Oranges, Bananas

  • Some other post | Tagged: Oranges, Bananas, Apples

Since this would vary from post to post, I need something other than the taxonomy-wide term ordering supported by plugins like Custom Taxonomy Sort and Taxonomy Terms Order.

I am looking for advice on how to implement this. Here is an outline of my current thinking:

Per-post term ordering using a custom field

  1. Remove standard taxonomy metabox using remove_meta_box()

  2. Add custom metabox containing term ordering interface, e.g., drag-and-drop (or simple text input next to each term for an integer describing term’s order. (Or perhaps it’s possible to add drag-and-drop to the existing meta_box without having to remove and add a new one?**)

  3. Using javascript, save a comma-separated list of term IDs, in order, in a hidden custom field, _mytermorder_taxonomyname. (Separate custom field for each taxonomy, e.g., _mytermorder_category, __mytermorder_tags, etc.)

  4. Create a custom function my_get_the_terms() that loops through the IDs in the _taxonomyname_termorder custom field. If a post has terms but no _taxonomyname_termorder field (as with old posts), just return get_the_terms().

  5. In relevant theme files, replace instances of get_the_terms() or other native term functions with my_get_the_terms().

Do you have advice, alternatives, warnings, or related snippets? I’d be grateful for any thoughts. Thank you!

Concerns

  • What if the list in the custom field gets out of sync with the actual term list (as it would if terms were added through an interface other than the post edit screen, such as the quick-edit/bulk edit form or Front-End Editor).

Solution: At the beginning of my_get_the_terms(), we can check whether the IDs in the custom field match the terms returned by get_the_terms. If not, default to get_the_terms.

  • New terms wouldn’t be captured on first use, because they don’t yet have an ID. You’d have to save a new term before it would work. (I could live with this, but it is a problem.)

  • The meta box has to list terms in the right order when the post edit page loads.


** For drag-and-drop sorting in the default metabox, I discovered that I can use jQuery UI’s .sortable, already available in the admin; for a non-hierarchical taxonomy, it’s $('#taxonomyname .tagchecklist').sortable().

3 s
3

I’m not sure if I understand exactly what your trying to accomplish but I’ve outlined a way for you to sort the order of terms associated with the current post.

Html for the term order metabox:

 echo '<ul id="the-terms">'
         $terms = get_the_terms( $post->ID, $taxonomy );
            foreach ( $terms as $term ) {
            echo '<li class="item" id="term-'.$term->term_id.'">'. $term->name .'</li>';        
            }
            echo '</ul>';
            echo '<a href="https://wordpress.stackexchange.com/questions/38961/javascript: void(0); return false;" id="save_term_order" class="button-primary">Update Order</a>';

Javascript to make the above list sortable and save the order using ajax.

*Note: requires jQuery UI-Sortable.

jQuery(document).ready(function() {  
// Make the term list sortable
        jQuery("#the-terms").sortable({
            items: '.item',
            placeholder: 'sortable-placeholder',
            tolerance: 'pointer',
            distance: 1,
            forcePlaceholderSize: true,
            helper: 'clone',
            cursor: 'move'
        });
// Save the order using ajax        
   jQuery("#save_term_order").live("click", function() {
        var postID = $("#post_ID").val();
        jQuery.post(ajaxurl, {
        action:'save_term_order', 
        cache: false, 
        post_id: postID,  
        order: jQuery("#the-terms").sortable('toArray').toString(),
        success: ajax_response()
       });
            return false; 
    });   
 });

WordPress ajax function to save the order as a custom field:

add_action ( 'wp_ajax_save_term_order', 'term_order_save' );
function term_order_save () {
    global $wpdb;
    $wpdb->flush ();
    $item_id = $_POST['post_id'];
    $meta_key = '_term_order';

    $order = $_POST[ 'order' ];
    $str = str_replace ( "term-", "", $order );
    $int = str_replace ( "'", "", $str );

    update_post_meta ( $item_id, $meta_key, array ( 'term_order' => $int ) );

    $response="<p>Term order updated</p>";
    echo $response;

    die(1);
}

This will save a list of the term id’s in order sorted as a serialized array:

_term_order => array(
term_order => ‘123,312,110,34,44,27’
)

To show the list of ordered terms on the front end:

$orderd_terms = get_post_meta ( $post->ID, '_term_order', true );
$terms = $ordered_terms[ 'term_order' ];
$term_ids = explode ( ",", $terms );

  for ( $i = 0; $i < count ( $term_ids ); $i ++ ) {

      $term = get_term( $term_ids[$i], $taxonomy, OBJECT)
      echo $term->name;
  }

Leave a Comment