I'm having some trouble with a custom thing I'm doing.

I've implented a custom image uploader into a metabox in a custom post type. Now I'm trying to work out a way that will let me reorder the uploaded images. I found that jQuery Sortable would be a convenient way for the user to be able to just drag and drop in which order the images should appear (in the frontend I'm using a jQuery image slider to show the images and the order of the images are decided by the attachment data "menu_order", so therefor I need some sort of functionality that saves the menu_order that I create with the jQuery Sortable.

Now, this is a simplified example of what I have: http://jsfiddle.net/LN4sA/

Together with each attachment I have added hidden input fields with the attachment id and a field that will house the current position of the attachment in the menu order.

The ID of the attachment is easily fetched with basic WP PHP ($attachment->ID). However, I have not yet found an easy way to populate the #att_order with the proper menu_order. So here I'd like some help/input if someone would be so kind.

To save the actual information I'm using ajax to pull the values from the input fields:

add_action('save_post', 'save_attachment_position');
function save_attachment_position(){
    global $post;
    if ($post->post_type == 'work') { ?>
        <script type="text/javascript">
                type: 'post',
                url: ajaxurl,
                data: {
                    action: 'order_attachment',
                    att_ID: jQuery(this).parents('.attachment').find('#att_id').val(),
                    att_order: jQuery(this).parents('.attachment').find('#att_order').val(),
                    _ajax_nonce: jQuery('#ordernonce').val(),
                    post_type: 'attachment'

And then use wp_update_post to update the attachment data:

add_action('wp_ajax_order_attachment', 'order_attachment');
function order_attachment($post) {
    $attachmentdata = array();
    $attachmentdata['ID'] = $_POST['att_ID'];
    $attachmentdata['menu_order'] = $_POST['att_order'];

I'm aware that I need some sort of loop here but I will work that out.

Any ideas?


  • Can you provide an example of the output HTML once the images are output, and again once they've been reordered, or alternatively provide a complete example that can be run(ie. something i can test on my installation). – t31os Jul 23 '11 at 12:50
  • @t31os I think this is everything that you need to be able to run it on your own install: pastebin.com/8yLjdkrq and pastebin.com/23wU7Qe1 Might have missed something though. Think it's easier for your to be able to test yourself (also good for anyone that wanna do something similar) – INT Jul 24 '11 at 18:00
  • @t31os Also please note on line 28 in paste 8yLjdkrq, I've put attachment ID as a placerholder, as I haven't figured out how to get the current menu_order for the attachments. – INT Jul 25 '11 at 12:17
  • Maybe this way is better to go: soulsizzle.com/jquery/… But not quite sure how to use it (since I need the menu order to be saved when you press update/save and not on every drag/drop) – INT Jul 25 '11 at 14:44
  • See the answer i provided, that should address your requirements(hopefully)... ;) – t31os Jul 26 '11 at 13:09

I'm not entirely sure what your intentions are for the code, and unfortunately i didn't find what you provided worked very well, so i rewrote parts of the code supplied to make it into a more workable solution.

This code will work for saving the attachment order in the metabox on save, not via ajax, but realistically there's no reason to save those changes on every sort(is there?).

I refactored the code so you can adjust the post type at the top of the code. I'm not sure what you aiming for with the enqueue call, and pretty sure it can't be called in the way you were doing, nor was it needed on the post editor page anyway(sortable and the necessary scripts are already available/loaded on the editor screen).

Give this a shot and see how you get on.. (note this is a working sample)..

// Not applicable to my testing, but left it in because i'm sure it's appropriate to your usage
add_theme_support( 'post-thumbnails' );
add_image_size( 'editor-thumb', 130, 72, true );

// Quicker to update one line than several, only reason it's defined here
$my_post_type = 'book';

// Add metabox on the proper metabox hook
add_action( 'add_meta_boxes_' . $my_post_type, 'add_image_sortable_box',   2000 );

// Fire jQuery only on the appliable pages
add_action( 'admin_footer-post.php',           'add_sortable_to_elements', 2000 );
add_action( 'admin_footer-post-new.php',       'add_sortable_to_elements', 2000 );

function add_image_sortable_box() {
    global $my_post_type;
    add_meta_box( 'test-image-thing', 'Sortable Attachments Test', 'do_image_metabox_thingy', $my_post_type, 'side', 'default' );

function add_sortable_to_elements() { 
    <script type="text/javascript">
        jQuery(document).ready(function($) {

function do_image_metabox_thingy( $p ) { 

    // No global statement needed here, the hook this function is attached to gives you the post object

    $args = array(
        'order'          => 'asc',
        'orderby'        => 'menu_order',
        'post_type'      => 'attachment',
        'post_parent'    => $p->ID,
        'post_mime_type' => 'image',
        'post_status'    => null,
        'numberposts'    => -1,

    $attachments = get_posts( $args );

    if( $attachments ) :

        // Only need 1 nonce to cover the lot
        wp_nonce_field( 'my_attachment_sort', 'attachment_sort_nonce' );

    <div class="imageuploader">
        <div id="attachmentcontainer">

        foreach( $attachments as $attachment ) :
            $attachmentid = $attachment->ID;
            $editorimage = wp_get_attachment_image_src( $attachment->ID, 'editor-thumb', false, false);

            <div class="attachment" id="test-<?php echo $attachment->ID; ?>">
                <div class="image">
                    <img width="100" height="auto" src="<?php echo $editorimage[0]; ?>" />
                    <input type="hidden" name="att_id[]" id="att_id" value="<?php echo $attachment->ID; ?>" />


        <div style="clear: both;"></div>


// Updates the attachments when saving
add_filter( 'wp_insert_post_data', 'test_meta_save', 1000, 2 );

function test_meta_save( $data, $_post_vars ) {
    global $my_post_type;
    if( $my_post_type != $data['post_type'] || !isset( $_post_vars['attachment_sort_nonce'] ) )
        return $data;

    if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
        return $data;

    if( !wp_verify_nonce( $_post_vars['attachment_sort_nonce'], 'my_attachment_sort' ) )
        return $data;

    global $post_ID;

    if( !current_user_can( 'edit_post', $post_ID ) ) 
        return $data;

    if( isset( $_post_vars['att_id'] ) ) {
        foreach( $_post_vars['att_id'] as $img_index => $img_id ) {
            $a = array(
                'ID' => $img_id,
                'menu_order' => $img_index
            wp_update_post( $a );
    return $data;

Of course make sure to switch the post type value, book is my testing post type.. :)

Any questions, add them to your original question, then drop a comment onto this answer to let me know..

  • NOTE: There's a few bits you might want to change, such as removing the hard-coded image height/width and the ID i attached the attachment div. – t31os Jul 26 '11 at 13:07
  • Amazing! Don't know what else to say. I am very, very thankful that you took time to give such an elaborate answer. Very much appreciated! – INT Aug 1 '11 at 23:11
  • Happy to help.. ;) – t31os Aug 2 '11 at 9:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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