Post Type Reorder - Simple Drag and Drop Ordering for WordPress

PHOTO EMBED

Wed Sep 25 2024 00:20:34 GMT+0000 (Coordinated Universal Time)

Saved by @Y@sir #posttype reorder #drag-and-dropreordering #quicklyreorganize content #re-order

<?php
// Add Re-Order submenu to each post type
function add_reorder_submenu() {
    $post_types = get_post_types(array('show_ui' => true), 'objects');
    foreach ($post_types as $post_type) {
        // Skip the attachment post type
        if ($post_type->name === 'attachment') {
            continue;
        }
        $parent_slug = ($post_type->name === 'post') ? 'edit.php' : 'edit.php?post_type=' . $post_type->name;
        add_submenu_page(
            $parent_slug,
            'Re-Order ' . $post_type->label,
            'Re-Order',
            'edit_posts',
            $post_type->name . '-reorder',
            'display_reorder_page'
        );
    }
}
add_action('admin_menu', 'add_reorder_submenu');

// Display the reorder page
function display_reorder_page() {
    if (!current_user_can('edit_posts')) {
        wp_die(__('You do not have sufficient permissions to access this page.'));
    }

    $current_screen = get_current_screen();
    $post_type = $current_screen->post_type;
    if (empty($post_type)) {
        $post_type = sanitize_text_field($_GET['post_type'] ?? 'post');
    }
    $post_type_object = get_post_type_object($post_type);

    if (!$post_type_object || $post_type === 'attachment') {
        wp_die(__('Invalid post type.'));
    }

    $query_args = array(
        'post_type' => $post_type,
        'post_status' => array('publish', 'draft', 'pending', 'future', 'private'),
        'posts_per_page' => -1,
        'orderby' => 'menu_order',
        'order' => 'ASC',
        'suppress_filters' => true,
    );
    $posts = get_posts($query_args);

    $total_items = count($posts);

    ?>
    <div class="wrap">
        <h1><?php echo esc_html(sprintf('Re-Order %s', $post_type_object->labels->name)); ?></h1>
        
        <div id="message" class="updated notice is-dismissible" style="display:none;"><p></p></div>
        
        <p><?php esc_html_e('Drag and drop items to reorder them. Click "Update Order" to save changes.'); ?></p>
        <button id="update-order" class="button button-primary"><?php esc_html_e('Update Order'); ?></button>
        <button id="reset-order" class="button"><?php esc_html_e('Reset Order'); ?></button>
        
        <p class="item-count"><?php esc_html_e('Total items:'); ?> <span id="total-items"><?php echo esc_html($total_items); ?></span></p>
        
 <ul id="sortable-list" class="widefat striped">
        <?php foreach ($posts as $post) : 
            $title = $post->post_title;
            $status = get_post_status($post->ID);
            $status_class = ($status !== 'publish') ? sprintf(' post-status-%s', sanitize_html_class($status)) : '';
        ?>
            <li class="ui-state-default<?php echo esc_attr($status_class); ?>" data-id="<?php echo esc_attr($post->ID); ?>">
                <span class="dashicons dashicons-menu"></span>
                <?php echo esc_html($title); ?>
                <span class="post-status">(<?php echo esc_html($status); ?>)</span>
            </li>
        <?php endforeach; ?>
        </ul>

        <p class="reorder-footer">
            <?php
            echo wp_kses(
                sprintf(
                    'Created by <a href="%s" target="_blank">Yasir Shabbir</a>',
                    'https://yasirshabbir.com'
                ),
                array(
                    'a' => array(
                        'href' => array(),
                        'target' => array()
                    )
                )
            );
            ?>
        </p>
    </div>

    <style>
        #sortable-list { list-style-type: none; margin: 20px 0; padding: 0; }
        #sortable-list li { 
            padding: 10px 15px !important; 
            background: #fff; 
            border: 1px solid #ddd; 
            margin-bottom: 5px; 
            cursor: move; 
            font-size: 14px !important;
            line-height: 1.4;
        }
        #sortable-list li:hover { background: #f9f9f9; }
        #sortable-list .dashicons { 
            color: #bbb; 
            margin-right: 10px;
            font-size: 20px;
            line-height: 1;
        }
        .ui-sortable-helper { 
            background: #f9f9f9 !important; 
            box-shadow: 0 2px 5px rgba(0,0,0,0.15); 
        }
        #update-order, #reset-order { display: inline-block; margin-right: 10px; margin-bottom: 20px; }
        .updating { opacity: 0.5; pointer-events: none; }
        .post-status { font-size: 0.8em; color: #666; margin-left: 5px; }
        .post-status-draft { opacity: 0.7; }
        .post-status-pending { background-color: #fef7f1; }
        .post-status-future { background-color: #f1fef7; }
        .post-status-private { background-color: #fef1f1; }
        .item-count { margin-top: 10px; font-weight: bold; }
        
             .reorder-footer {
            margin-top: 20px;
            text-align: center;
            font-style: italic;
            color: #666;
        }
    </style>

    <script>
    jQuery(document).ready(function($) {
        $("#sortable-list").sortable({
            handle: ".dashicons-menu"
        });

        function updateOrder(action, buttonId) {
            var $button = $("#" + buttonId);
            var $list = $("#sortable-list");
            var order = $list.sortable("toArray", {attribute: "data-id"});
            
            $button.addClass("updating").text(action === "update_post_order" ? "<?php esc_html_e('Updating...'); ?>" : "<?php esc_html_e('Resetting...'); ?>");
            $list.addClass("updating");
            
            $.ajax({
                url: ajaxurl,
                type: "POST",
                data: {
                    action: action,
                    order: order,
                    post_type: <?php echo wp_json_encode($post_type); ?>,
                    security: <?php echo wp_json_encode(wp_create_nonce('post_order_nonce')); ?>
                },
                success: function(response) {
                    if (response.success) {
                        $("#message").html("<p>" + response.data + "</p>").show();
                        if (action === "reset_post_order") {
                            location.reload();
                        }
                    } else {
                        $("#message").html("<p><?php esc_html_e('Error:'); ?> " + response.data + "</p>").show();
                    }
                },
                error: function() {
                    $("#message").html("<p><?php esc_html_e('An error occurred.'); ?></p>").show();
                },
                complete: function() {
                    $button.removeClass("updating").text(action === "update_post_order" ? "<?php esc_html_e('Update Order'); ?>" : "<?php esc_html_e('Reset Order'); ?>");
                    $list.removeClass("updating");
                }
            });
        }

        function updateItemCount() {
            var count = $("#sortable-list li").length;
            $("#total-items").text(count);
        }

        $("#update-order").click(function() {
            updateOrder("update_post_order", "update-order");
        });

        $("#reset-order").click(function() {
            if (confirm("<?php esc_html_e('Are you sure you want to reset the order? This cannot be undone.'); ?>")) {
                updateOrder("reset_post_order", "reset-order");
                setTimeout(updateItemCount, 500);
            }
        });

        updateItemCount();

        $("#sortable-list").on("DOMSubtreeModified", function() {
            updateItemCount();
        });
    });
    </script>
    <?php
}

// AJAX handler to update post order
function update_post_order() {
    check_ajax_referer('post_order_nonce', 'security');
    
    $order = $_POST['order'];
    $post_type = $_POST['post_type'];
    
    if ($post_type === 'attachment') {
        wp_send_json_error('Reordering media items is not supported.');
        return;
    }
    
    foreach ($order as $menu_order => $post_id) {
        wp_update_post(array(
            'ID' => intval($post_id),
            'menu_order' => intval($menu_order)
        ));
    }
    
    wp_send_json_success('Order updated successfully');
}
add_action('wp_ajax_update_post_order', 'update_post_order');

// AJAX handler to reset post order
function reset_post_order() {
    check_ajax_referer('post_order_nonce', 'security');
    
    $post_type = $_POST['post_type'];
    
    if ($post_type === 'attachment') {
        wp_send_json_error('Reordering media items is not supported.');
        return;
    }
    
    $posts = get_posts(array(
        'post_type' => $post_type,
        'posts_per_page' => -1,
        'post_status' => 'any',
    ));
    
    foreach ($posts as $post) {
        wp_update_post(array(
            'ID' => $post->ID,
            'menu_order' => 0
        ));
    }
    
    wp_send_json_success('Order reset successfully');
}
add_action('wp_ajax_reset_post_order', 'reset_post_order');

// Update post order when posts are created or trashed
function set_default_post_order($post_id, $post, $update) {
    if (!$update && $post->post_type !== 'attachment') {
        $post_type = get_post_type($post_id);
        $last_post = get_posts(array(
            'post_type' => $post_type,
            'posts_per_page' => 1,
            'orderby' => 'menu_order',
            'order' => 'DESC'
        ));
        $new_menu_order = (!empty($last_post)) ? $last_post[0]->menu_order + 1 : 0;
        wp_update_post(array(
            'ID' => $post_id,
            'menu_order' => $new_menu_order
        ));
    }
}
add_action('wp_insert_post', 'set_default_post_order', 10, 3);
content_copyCOPY

Post Type Reorder is a lightweight WordPress plugin that enables easy drag-and-drop reordering of posts, pages, and custom post types. With an intuitive user interface, it allows administrators to quickly reorganize content without modifying dates or other post attributes. The plugin adds a "Re-Order" submenu to each supported post type, providing a dedicated page for reordering entries. It supports various post statuses, offers instant visual feedback, and includes options to update or reset the order. Developed with WordPress best practices in mind, this plugin is designed to be efficient, secure, and compatible with most themes and plugins. Post Type Reorder simplifies content management, making it an essential tool for WordPress sites that require custom ordering of posts or pages.