Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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">
            <?php
    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 xxxxx.com" /></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 } ?>               
                </div>
         </article>
     </li>              
    <?php endwhile; ?>
       </ul>
</section>

The javascript is just the basic default sortable instructions

jQuery(document).ready(function() {
    jQuery("#sortable").sortable();
  });

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.

Update:

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.

share|improve this question
1  
Is it possible you could use menu_order on posts? I know you can use them on attachments so why not posts? if its possible this is where you could store the order of the posts... –  Brady May 6 '11 at 16:05
1  
Looks like you can - 'menu_order' - Order by Page Order. Used most often for Pages (Order field in the Edit Page Attributes box) and for attachments (the integer fields in the Insert / Upload Media Gallery dialog), but could be used for any post type with distinct 'menu_order' values (they all default to 0). –  Brady May 6 '11 at 16:07
    
@Brady Great idea on using menu_order. @somatic expanded on it and it worked. Thanks! –  Chris_O May 8 '11 at 3:12
add comment

2 Answers

up vote 16 down vote accepted
+100

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

    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',
                data:{
                    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
                    return; 
                },
                error: function(xhr,textStatus,e) {  // This can be expanded to provide more information
                    alert(e);
                    // alert('There was an error saving the updates');
                    $('#loading-animation').hide(); // Hide the loading animation
                    return; 
                }
            };
            $.ajax(opts);
        }
    }); 
});

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) );
        $counter++;
    }
    die(1);
}
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>
</ul>

Code inspired by soulsizzle's excellent tutorial.

share|improve this answer
    
Excellent answer. I will give it a shot. –  Chris_O May 6 '11 at 21:30
    
Thank you so much for this - totally helped on something I was working on too. One problem I bumped up against was that each item in the sortable list needs to have an ID that matches the post ID. This was in soulsizzle's tutorial but not in the OP's post. –  Dalton Aug 17 '11 at 20:51
    
Absolutely right, Dalton, I was too brief in my example. Code updated. –  somatic Aug 29 '11 at 1:11
add comment

http://jsfiddle.net/TbR69/1/

Far from finished, but the idea is to send an ajax request on drag and drop. You may also want to trigger the ajax request only after clicking a "save" button or something. An array containing post IDs and new order would be sent.

Then you'd have to update the posts in the database on the server end. Finally, add an order parameter to your WP_Query loop.

I hope this gets you started. Anybody feel free to continue fiddling.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.