¿Cómo guardar el estado de un editor de diseño frontend con drag and drop usando jQuery UI Sortables?

4 may 2011, 17:12:19
Vistas: 29.8K
Votos: 21

Estoy construyendo un editor de diseño de entradas para el frontend usando jQuery UI Sortable.

Las entradas están dispuestas en cajas de 300px por 250px sobre una imagen de fondo. Las entradas se crean y editan usando el panel de WordPress pero quiero permitir que el administrador del sitio ajuste el orden de las cajas usando una interfaz de arrastrar y soltar en el frontend.

Ya tengo funcionando la parte de arrastrar y soltar, pero necesito encontrar una manera de guardar el estado (orden) de las cajas. Idealmente me gustaría poder guardar el estado como una opción e incorporarlo en la consulta.

La consulta para las entradas es un simple WP_Query que también obtiene datos de metaboxes personalizados para determinar el diseño individual de cada caja:

$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);
    
    // Si hay un enlace externo, usarlo, sino usar el enlace de la entrada
    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="Imagen 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>

El javascript es simplemente las instrucciones básicas por defecto de sortable

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

Hay métodos disponibles usando cookies para guardar el estado pero también necesito deshabilitar el arrastrar y soltar para usuarios no administradores, así que realmente necesito guardar en la base de datos.

Estoy buscando el método más creativo y usable y otorgaré una recompensa de 100 puntos a la mejor respuesta.

Actualización:

Conseguí que la respuesta de somatic funcionara con un pequeño cambio.

ajaxurl no devuelve el valor en páginas no administrativas, así que usé wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); para definir el valor y cambié la línea de javascript bajo options a:
url: MyAjax.ajaxurl,

Para limitar el acceso a ordenar solo a administradores, agregué una condicional a mi función wp_enqueue_script:

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

Voy a hacer algunas pruebas más y marcar esta pregunta como resuelta y otorgar la recompensa.

3
Comentarios

¿Es posible usar menu_order en publicaciones? Sé que se puede usar en adjuntos, así que ¿por qué no en publicaciones? Si es posible, aquí es donde podrías almacenar el orden de las publicaciones...

Scott Scott
6 may 2011 19:05:37

Parece que se puede - 'menu_order' - Ordenar por Orden de Página. Se usa más frecuentemente para Páginas (campo Orden en el cuadro Editar Atributos de Página) y para adjuntos (los campos enteros en el diálogo Insertar/Subir Galería Multimedia), pero podría usarse para cualquier tipo de publicación con valores distintos de 'menu_order' (todos tienen 0 por defecto).

Scott Scott
6 may 2011 19:07:57

@Brady Gran idea sobre usar menu_order. @somatic lo amplió y funcionó. ¡Gracias!

Chris_O Chris_O
8 may 2011 06:12:15
Todas las respuestas a la pregunta 3
3
23

Brady tiene razón en que la mejor manera de manejar el guardado y visualización del orden de tipos de contenido personalizados es usando la propiedad menu_order.

Aquí está el jQuery para hacer la lista ordenable y pasar los datos via ajax a WordPress:

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

    itemList.sortable({
        update: function(event, ui) {
            $('#loading-animation').show(); // Mostrar el gif de carga animado mientras se espera

            opts = {
                url: ajaxurl, // ajaxurl es definido por WordPress y apunta a /wp-admin/admin-ajax.php
                type: 'POST',
                async: true,
                cache: false,
                dataType: 'json',
                data:{
                    action: 'item_sort', // Indicar a WordPress cómo manejar esta petición ajax
                    order: itemList.sortable('toArray').toString() // Pasar IDs de los elementos de la lista en formato 1,3,2
                },
                success: function(response) {
                    $('#loading-animation').hide(); // Ocultar la animación de carga
                    return; 
                },
                error: function(xhr,textStatus,e) {  // Esto puede expandirse para proveer más información
                    alert(e);
                    // alert('Hubo un error al guardar los cambios');
                    $('#loading-animation').hide(); // Ocultar la animación de carga
                    return; 
                }
            };
            $.ajax(opts);
        }
    }); 
});

Aquí está la función de WordPress que escucha el callback ajax y realiza los cambios en la base de datos:

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

La clave para mostrar las publicaciones en el orden que has guardado es añadir la propiedad menu_order a los argumentos de la consulta:

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

$box_query = new WP_Query($args);

Luego ejecuta tu loop y muestra cada elemento... (la primera línea es la animación de carga principal de WP - querrás ocultarla inicialmente via css, y luego la función jQuery la mostrará durante el procesamiento)

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

Código inspirado en el excelente tutorial de soulsizzle.

7 may 2011 00:26:16
Comentarios

Excelente respuesta. Le daré una oportunidad.

Chris_O Chris_O
7 may 2011 00:30:42

Muchas gracias por esto - me ayudó totalmente con algo en lo que estaba trabajando también. Un problema con el que me encontré fue que cada elemento en la lista ordenable necesita tener un ID que coincida con el ID de la publicación. Esto estaba en el tutorial de soulsizzle pero no en la publicación original.

Dalton Rooney Dalton Rooney
17 ago 2011 23:51:31

Absolutamente correcto, Dalton, fui demasiado breve en mi ejemplo. Código actualizado.

somatic somatic
29 ago 2011 04:11:06
0

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

Lejos de estar terminado, pero la idea es enviar una solicitud AJAX al arrastrar y soltar. También podrías querer activar la solicitud AJAX solo después de hacer clic en un botón "guardar" o algo similar. Se enviaría un arreglo que contenga los IDs de las entradas y el nuevo orden.

Luego tendrías que actualizar las entradas en la base de datos en el servidor. Finalmente, añade un parámetro order a tu bucle WP_Query.

Espero que esto te ayude a empezar. Cualquiera puede sentirse libre de continuar modificando el código.

4 may 2011 18:04:34
2
/**
 *  Cargar archivos javascript y css
 */
function uc_enqueue_my_assets() {
    wp_enqueue_script( 'jquery-ui-sortable');
    wp_register_script( 'order', plugins_url( '/js/order.js', __FILE__ ), array( 'jquery' ) );
    wp_enqueue_script( 'order' );
}

function uc_is_user_logged_in()
{
    if ( is_user_logged_in()) {
        add_action( 'wp_enqueue_scripts', 'uc_enqueue_my_assets' );
        add_action( 'admin_enqueue_scripts', 'uc_enqueue_my_assets' );
    }
}
add_action('init', 'uc_is_user_logged_in');


/**
 *  Actualizar el orden de las publicaciones mediante ajax al activar el evento de arrastrar y soltar
 */
function uc_sort_post_items() {

    $order = wp_parse_id_list(explode(',', $_POST['order']));
    write_log($order);

    global $wpdb;
    $list = join(', ', $order);
    $wpdb->query('SELECT @i:=0');
    $wpdb->query(
        "UPDATE wp_posts SET menu_order = ( @i:= @i+1 )
        WHERE ID IN ( $list ) ORDER BY FIELD( ID, $list );"
    );

    wp_die();
}
add_action('wp_ajax_uc_sort_post_items', 'uc_sort_post_items');
add_action('wp_ajax_nopriv_uc_sort_post_items', 'uc_sort_post_items');


/**
 *  Mostrar publicaciones ordenadas
 */
function uc_pre_get_posts( $wp_query ) {
    write_log(basename($_SERVER['PHP_SELF']));
    $wp_query->set('orderby', 'menu_order');
    $wp_query->set('order', 'ASC');
}
add_action( 'pre_get_posts', 'uc_pre_get_posts', 1 );

Archivo Javascript order.js

$('#the-list').sortable({
        update: function(event, ui) {

            $.ajax({

                url: '/wp-admin/admin-ajax.php',
                type: 'post',
                dataType: 'json',
                data:{
                    action: 'uc_sort_post_items', // Indica a WordPress cómo manejar esta solicitud ajax
                    order: '4567,4569,4565 ' // Pasa los IDs de los elementos de la lista en formato 1,3,2. Escribe tu propio método js para acceder a la lista de IDs desde el frontend.
                },
                success: function(data, response) {
                    console.log(response);
                },
                error: function(xhr,textStatus,e) {
                    alert(e);
                }

                });

        }
    });
28 may 2019 03:05:41
Comentarios

Por favor, no solo copies el código. Se te solicita que agregues alguna explicación sobre por qué crees que el código anterior responde a la pregunta.

Mayeenul Islam Mayeenul Islam
28 may 2019 08:50:20

@MayeenulIslam La descripción ya ha sido agregada dentro de los fragmentos de código como líneas de comentario.

SkyRar SkyRar
28 may 2019 23:13:12