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.
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.
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");
}
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.
When you fetch terms (front or admin), use 'orderby' => 'custom_order'
:
$terms = get_terms([
'taxonomy' => 'condition',
'orderby' => 'custom_order',
'hide_empty' => false,
]);
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 (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);
wp_termmeta
for custom_order
after sorting.get_terms()
uses 'orderby' => 'custom_order'
.
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.