plugin development - Custom Taxonomy Ajax ordering in admin like woocommerce product categories

admin2025-05-31  0

This is a functionality to be active in admin panel. and yes I need to fetch the items in front end the same order. Well here is what I have tried so far.

Custom post and taxonomy added in ACF. Hirarcy enabled. Sortable enabled.

add_action('admin_enqueue_scripts', function($hook) {
if ($hook === 'edit-tags.php' && $_GET['taxonomy'] === 'condition') {
    wp_enqueue_script('jquery-ui-sortable');
    wp_enqueue_script('condition-sort', get_stylesheet_directory_uri() . '/js/taxonomy-sort.js', array('jquery', 'jquery-ui-sortable'), false, true);
    wp_localize_script('condition-sort', 'cts', [
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('condition_sort_nonce')
    ]);
} });

    // Add custom column
add_filter('manage_edit-condition_columns', function($columns) {
    $columns['order'] = '';
    return $columns;
});

// Display sort handle
add_filter('manage_condition_custom_column', function($content, $column_name, $term_id) {
    if ($column_name === 'order') {
        return '<span class="handle">≡</span>';
    }
    return $content;
}, 10, 3);

add_action('wp_ajax_save_condition_order', function() {
    check_ajax_referer('condition_sort_nonce', 'nonce');

    if (!current_user_can('manage_categories') || !isset($_POST['order'])) {
        wp_send_json_error();
    }

    $order = $_POST['order'];

    foreach ($order as $index => $term_id) {
        update_term_meta($term_id, 'custom_order', $index);
    }

    wp_send_json_success();
});

add_filter('get_terms_orderby', function($orderby, $args) {
    if (!is_admin() && isset($args['taxonomy']) && $args['taxonomy'] === 'condition') {
        return "CAST((SELECT meta_value FROM wp_termmeta WHERE term_id = t.term_id AND meta_key = 'custom_order') AS UNSIGNED)";
    }
    return $orderby;
}, 10, 2);

My Custom taxonomy name is "condition". Post type is "sea-foods".

Here is the js I use.

jQuery(document).ready(function($) {
    $('tbody').sortable({
        handle: '.handle',
        update: function() {
            let order = [];
            $('tbody tr').each(function() {
                order.push($(this).attr('id').replace('tag-', ''));
            });

            $.post(cts.ajax_url, {
                action: 'save_condition_order',
                order: order,
                nonce: cts.nonce
            }, function(response) {
                if (response.success) {
                    console.log('Order saved');
                } else {
                    alert('Failed to save order');
                }
            });
        }
    });
});

The problem is, the drag and drop working. In the console I am getting the order saved notice. But the order is not actually get saved. May be I am doing something wrong in the updatae meta section or something in the saving the order part.

Any help will be appriciated.

This is a functionality to be active in admin panel. and yes I need to fetch the items in front end the same order. Well here is what I have tried so far.

Custom post and taxonomy added in ACF. Hirarcy enabled. Sortable enabled.

add_action('admin_enqueue_scripts', function($hook) {
if ($hook === 'edit-tags.php' && $_GET['taxonomy'] === 'condition') {
    wp_enqueue_script('jquery-ui-sortable');
    wp_enqueue_script('condition-sort', get_stylesheet_directory_uri() . '/js/taxonomy-sort.js', array('jquery', 'jquery-ui-sortable'), false, true);
    wp_localize_script('condition-sort', 'cts', [
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('condition_sort_nonce')
    ]);
} });

    // Add custom column
add_filter('manage_edit-condition_columns', function($columns) {
    $columns['order'] = '';
    return $columns;
});

// Display sort handle
add_filter('manage_condition_custom_column', function($content, $column_name, $term_id) {
    if ($column_name === 'order') {
        return '<span class="handle">≡</span>';
    }
    return $content;
}, 10, 3);

add_action('wp_ajax_save_condition_order', function() {
    check_ajax_referer('condition_sort_nonce', 'nonce');

    if (!current_user_can('manage_categories') || !isset($_POST['order'])) {
        wp_send_json_error();
    }

    $order = $_POST['order'];

    foreach ($order as $index => $term_id) {
        update_term_meta($term_id, 'custom_order', $index);
    }

    wp_send_json_success();
});

add_filter('get_terms_orderby', function($orderby, $args) {
    if (!is_admin() && isset($args['taxonomy']) && $args['taxonomy'] === 'condition') {
        return "CAST((SELECT meta_value FROM wp_termmeta WHERE term_id = t.term_id AND meta_key = 'custom_order') AS UNSIGNED)";
    }
    return $orderby;
}, 10, 2);

My Custom taxonomy name is "condition". Post type is "sea-foods".

Here is the js I use.

jQuery(document).ready(function($) {
    $('tbody').sortable({
        handle: '.handle',
        update: function() {
            let order = [];
            $('tbody tr').each(function() {
                order.push($(this).attr('id').replace('tag-', ''));
            });

            $.post(cts.ajax_url, {
                action: 'save_condition_order',
                order: order,
                nonce: cts.nonce
            }, function(response) {
                if (response.success) {
                    console.log('Order saved');
                } else {
                    alert('Failed to save order');
                }
            });
        }
    });
});

The problem is, the drag and drop working. In the console I am getting the order saved notice. But the order is not actually get saved. May be I am doing something wrong in the updatae meta section or something in the saving the order part.

Any help will be appriciated.

Share Improve this question asked May 10 at 5:18 BehemothBehemoth 1146 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 1

Your setup is almost correct! The drag-and-drop works, AJAX fires, and PHP receives the order. The main issue is likely with how you save and retrieve the order.

1. Saving the Order

Your code for saving order with update_term_meta($term_id, 'custom_order', $index); is correct.
Tip: Check your wp_termmeta table after sorting to confirm that custom_order is being set.


foreach ($order as $index => $term_id) {
    update_term_meta($term_id, 'custom_order', $index);
    error_log("Set order $index for term $term_id");
}
  

2. Retrieving the Order

Your get_terms_orderby filter is only running on the frontend (!is_admin()). Remove that check so the order applies everywhere, including the admin panel.


add_filter('get_terms_orderby', function($orderby, $args) {
    if (isset($args['taxonomy']) && $args['taxonomy'] === 'condition') {
        global $wpdb;
        return "(SELECT meta_value FROM $wpdb->termmeta WHERE term_id = t.term_id AND meta_key = 'custom_order')+0 ASC";
    }
    return $orderby;
}, 10, 2);
  

The +0 ensures the sorting is numeric.

3. Fetching Terms in Custom Order

When you fetch terms (front or admin), use 'orderby' => 'custom_order':


$terms = get_terms([
    'taxonomy'   => 'condition',
    'orderby'    => 'custom_order',
    'hide_empty' => false,
]);
  

4. Extra Tips

  • Flush object cache if you use one.
  • Add error logging in your PHP handler if needed.

5. Full Working Example

AJAX Handler


add_action('wp_ajax_save_condition_order', function() {
    check_ajax_referer('condition_sort_nonce', 'nonce');
if (!current_user_can('manage_categories') || !isset($_POST['order'])) {
    wp_send_json_error();
}

$order = $_POST['order'];

foreach ($order as $index =&gt; $term_id) {
    update_term_meta($term_id, 'custom_order', $index);
}

wp_send_json_success();

});

Orderby Filter


add_filter('get_terms_orderby', function($orderby, $args) {
    if (isset($args['taxonomy']) && $args['taxonomy'] === 'condition') {
        global $wpdb;
        return "(SELECT meta_value FROM $wpdb->termmeta WHERE term_id = t.term_id AND meta_key = 'custom_order')+0 ASC";
    }
    return $orderby;
}, 10, 2);
  

6. Debug Checklist

  • Check wp_termmeta for custom_order after sorting.
  • Ensure your filter runs in both admin and frontend.
  • Confirm get_terms() uses 'orderby' => 'custom_order'.

7. If Still Not Working

  • Try manually updating a term's meta in the DB and see if the order changes.
  • Check for JavaScript or network errors in your browser console.
  • Make sure your browser cache isn't interfering.

Summary

You are saving the order correctly, but your orderby filter is only running on the frontend. Remove the !is_admin() check, and ensure your admin table is using the custom_order meta for sorting. Also, double-check that the meta is actually being saved in the database.

add_action('admin_enqueue_scripts', function($hook) {
    if ($hook === 'edit-tags.php' && $_GET['taxonomy'] === 'condition') {
        wp_enqueue_script('jquery-ui-sortable');
        wp_enqueue_script('condition-sort', get_stylesheet_directory_uri() . '/js/taxonomy-sort.js', array('jquery', 'jquery-ui-sortable'), false, true);
        wp_localize_script('condition-sort', 'cts', [
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('condition_sort_nonce')
        ]);
    }
});

// Add custom column
add_filter('manage_edit-condition_columns', function($columns) {
    $columns['order'] = '';
    return $columns;
});

// Display sort handle
add_filter('manage_condition_custom_column', function($content, $column_name, $term_id) {
    if ($column_name === 'order') {
        return '<span class="handle" data-id="'.$term_id.'">≡</span>';
    }
    return $content;
}, 10, 3);

add_action('wp_ajax_save_condition_order', function() {
    check_ajax_referer('condition_sort_nonce', 'nonce');

    if (!current_user_can('manage_categories') || !isset($_POST['order'])) {
        wp_send_json_error();
    }

    $order = $_POST['order'];
    //error_log('Received order: ' . print_r($order, true));
    foreach ($order as $index => $term_id) {
        update_term_meta($term_id, 'custom_order', $index);
        //error_log("Set order $index for term $term_id");
    }

    wp_send_json_success();
});

add_filter('get_terms_orderby', function($orderby, $args) {
    
    if (isset($args['taxonomy'][0]) && $args['taxonomy'][0] === 'condition') {
        global $wpdb;
        //return "CAST((SELECT meta_value FROM wp_termmeta WHERE term_id = t.term_id AND meta_key = 'custom_order') AS UNSIGNED)";
        
        return "(SELECT meta_value FROM $wpdb->termmeta WHERE term_id = t.term_id AND meta_key = 'custom_order')";
    }
    
    return $orderby;
}, 10, 2);

The js code:

jQuery(document).ready(function($) {
    $('tbody').sortable({
        handle: '.handle',
        update: function() {
            let order = [];
            $('tbody tr').each(function() {
                let id = $(this).find('.handle').data('id');
                if (id) order.push(id);
            });

            console.log('Sorted order:', order); // Debug

            $.post(cts.ajax_url, {
                action: 'save_condition_order',
                order: order,
                nonce: cts.nonce
            }, function(response) {
                if (response.success) {
                    console.log('Order saved');
                    // Optionally reload: location.reload();
                } else {
                    alert('Failed to save order');
                }
            });
        }
    });
});

Its now working. The "Arizona Web Development" who made me correct. Marking it as an answer. Thanks.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1748632069a313662.html

最新回复(0)