How to save the state of a drag and drop jQuery UI Sortables front end layout editor?

I am building a front end post layout editor using jQuery UI Sortable.

The posts are laid out in 300px by 250px boxes over a background image. The posts are created and edited using the WordPress admin but I want to allow the sites administrator to adjust the order of the boxes using a drag and drop interface on the front end.

I’ve got the drag and drop sortable part working but need to come up with a way to save the state (order) of the boxes. Ideally I would like to be able to save the state as an option and build it into the query.

The query for the posts is a simple WP_Query that also gets data from custom meta boxes to determine the individual box layout.:

$args= array(
      'meta_key' => 'c3m_shown_on',
       'meta_value'=> 'home' );
    $box_query = new WP_Query($args);  ?>
        <ul id="sortable">
    while ($box_query->have_posts()) : $box_query->the_post(); global $post; global $prefix;           
    $box_size = c3m_get_field($prefix.'box_size', FALSE);
    $box_image = c3m_get_field($prefix.'post_box_image', FALSE);
    $overlay_class = c3m_get_field($prefix.'overlay_class', FALSE);
    if ( c3m_get_field($prefix.'external_link', FALSE) ) {
    $post_link = c3m_get_field($prefix.'external_link', FALSE);
    } else
            { $post_link = post_permalink(); 
    } ?>     
     <li class="<?php echo $box_size;?>  ui-state-default">
        <article <?php post_class() ?> id="post-<?php the_ID(); ?>">
            <?php echo  '<a href="'.$post_link.'" ><img src="'.esc_url($box_image).'" alt="Image via" /></a>'; ?>
                <div class="post-box <?php echo $overlay_class;?>">
                <?php if ( c3m_get_field( $prefix.'text_display', FALSE) ) { ?>     
                <h2><a href="<?php echo $post_link?>"><?php the_title();?></a></h2> 
                <p><?php echo substr($post->post_excerpt, 0, 90) . '...'; ?></p>            
                <?php } ?>               
    <?php endwhile; ?>

The javascript is just the basic default sortable instructions

jQuery(document).ready(function() {

There are methods available using cookies to save the state but I also need to disable the sortable drag and drop for non admin users so I really need to save to the database.

I’m looking for the most creative and usable method and will award a 100 point bounty to the best answer.


I got somatic’s answer working with one minor change.

ajaxurl doesn’t return the value on non admin pages so I used wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); to define the value and changed the javascript line under options to:
url: MyAjax.ajaxurl,

To limit access to arranging the order to only admins I added a conditional to my wp_enqueue_script function:

    function c3m_load_scripts() { 
    if ( current_user_can( 'edit_posts' ) ) {
        wp_enqueue_script( 'jquery-ui' );
        wp_enqueue_script( 'functions', get_bloginfo( 'stylesheet_directory' ) . '/_/js/functions.js', array( 'jquery', 'jquery-ui' ), false);
        wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );

I’m going to do a little more testing and mark this question as solved and award the bounty.


Brady is correct that the best way to handle saving and displaying of custom post type orders is by using the menu_order property

Here’s the jquery to make the list sortable and to pass the data via ajax to wordpress:

jQuery(document).ready(function($) {        
    var itemList = $('#sortable');

        update: function(event, ui) {
            $('#loading-animation').show(); // Show the animate loading gif while waiting

            opts = {
                url: ajaxurl, // ajaxurl is defined by WordPress and points to /wp-admin/admin-ajax.php
                type: 'POST',
                async: true,
                cache: false,
                dataType: 'json',
                    action: 'item_sort', // Tell WordPress how to handle this ajax request
                    order: itemList.sortable('toArray').toString() // Passes ID's of list items in  1,3,2 format
                success: function(response) {
                    $('#loading-animation').hide(); // Hide the loading animation
                error: function(xhr,textStatus,e) {  // This can be expanded to provide more information
                    // alert('There was an error saving the updates');
                    $('#loading-animation').hide(); // Hide the loading animation

Here’s the wordpress function that listens for the ajax callback and performs the changes on the DB:

function my_save_item_order() {
    global $wpdb;

    $order = explode(',', $_POST['order']);
    $counter = 0;
    foreach ($order as $item_id) {
        $wpdb->update($wpdb->posts, array( 'menu_order' => $counter ), array( 'ID' => $item_id) );
add_action('wp_ajax_item_sort', 'my_save_item_order');
add_action('wp_ajax_nopriv_item_sort', 'my_save_item_order');

The key to displaying the posts in the order you have saved is to add the menu_order property to the query args:

$args= array(
    'meta_key' => 'c3m_shown_on',
    'meta_value'=> 'home'
    'orderby' => 'menu_order',
    'order' => 'ASC'

$box_query = new WP_Query($args);

Then run your loop and output each item… (first line is the core wp loading animation – you’ll want to hide it initially via css, and then the jquery function will display when processing)

<img src="<?php bloginfo("url'); ?>/wp-admin/images/loading.gif" id="loading-animation" />
<ul id="sortable">
    <li id="{echo post ID here}">{echo title or other name here}</li>

Code inspired by soulsizzle’s excellent tutorial.

Leave a Comment