Come salvare lo stato di un editor di layout drag and drop con jQuery UI Sortables lato frontend?

4 mag 2011, 17:12:19
Visualizzazioni: 29.8K
Voti: 21

Sto creando un editor di layout di post lato frontend utilizzando jQuery UI Sortable.

I post sono disposti in box di 300px per 250px su un'immagine di sfondo. I post vengono creati e modificati tramite l'admin di WordPress ma voglio permettere all'amministratore del sito di regolare l'ordine dei box usando un'interfaccia drag and drop sul frontend.

Ho fatto funzionare la parte drag and drop sortable ma ho bisogno di trovare un modo per salvare lo stato (ordine) dei box. Idealmente vorrei poter salvare lo stato come opzione e integrarlo nella query.

La query per i post è una semplice WP_Query che ottiene anche dati da custom meta box per determinare il layout dei singoli box:

$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="Immagine 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>

Il javascript è solo l'istruzione base di sortable predefinita

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

Ci sono metodi disponibili usando i cookie per salvare lo stato ma ho anche bisogno di disabilitare il drag and drop sortable per gli utenti non amministratori quindi ho davvero bisogno di salvare nel database.

Sto cercando il metodo più creativo e utilizzabile e assegnerò una ricompensa di 100 punti alla migliore risposta.

Aggiornamento:

Ho fatto funzionare la risposta di somatic con una piccola modifica.

ajaxurl non restituisce il valore nelle pagine non admin quindi ho usato wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); per definire il valore e ho modificato la riga javascript sotto options in:
url: MyAjax.ajaxurl,

Per limitare l'accesso al riordinamento solo agli amministratori ho aggiunto una condizione alla mia funzione 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' ) ) );
    }
}

Farò un po' più di test e segnerò questa domanda come risolta e assegnerò la ricompensa.

3
Commenti

È possibile utilizzare menu_order sui post? So che si può usare sugli allegati, quindi perché non sui post? Se è possibile, qui potresti memorizzare l'ordine dei post...

Scott Scott
6 mag 2011 19:05:37

Sembra che si possa - 'menu_order' - Ordina per Ordine Pagina. Usato più spesso per le Pagine (campo Ordine nella casella Modifica Attributi Pagina) e per gli allegati (i campi numerici nella finestra di dialogo Inserisci/Carica Galleria Media), ma potrebbe essere usato per qualsiasi tipo di post con valori distinti di 'menu_order' (tutti hanno come default 0).

Scott Scott
6 mag 2011 19:07:57

@Brady Ottima idea sull'uso di menu_order. @somatic l'ha ampliata e ha funzionato. Grazie!

Chris_O Chris_O
8 mag 2011 06:12:15
Tutte le risposte alla domanda 3
3
23

Brady ha ragione nel dire che il modo migliore per gestire il salvataggio e la visualizzazione dell'ordine dei custom post type è utilizzare la proprietà menu_order

Ecco il codice jQuery per rendere la lista ordinabile e passare i dati via ajax a WordPress:

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

    itemList.sortable({
        update: function(event, ui) {
            $('#loading-animation').show(); // Mostra l'animazione di caricamento durante l'attesa

            opts = {
                url: ajaxurl, // ajaxurl è definito da WordPress e punta a /wp-admin/admin-ajax.php
                type: 'POST',
                async: true,
                cache: false,
                dataType: 'json',
                data:{
                    action: 'item_sort', // Indica a WordPress come gestire questa richiesta ajax
                    order: itemList.sortable('toArray').toString() // Passa gli ID degli elementi della lista nel formato 1,3,2
                },
                success: function(response) {
                    $('#loading-animation').hide(); // Nasconde l'animazione di caricamento
                    return; 
                },
                error: function(xhr,textStatus,e) {  // Può essere ampliato per fornire maggiori informazioni
                    alert(e);
                    // alert('Si è verificato un errore durante il salvataggio degli aggiornamenti');
                    $('#loading-animation').hide(); // Nasconde l'animazione di caricamento
                    return; 
                }
            };
            $.ajax(opts);
        }
    }); 
});

Ecco la funzione WordPress che ascolta il callback ajax ed esegue le modifiche sul database:

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 chiave per visualizzare i post nell'ordine salvato è aggiungere la proprietà menu_order agli argomenti della query:

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

$box_query = new WP_Query($args);

Poi esegui il tuo loop e mostra ogni elemento... (la prima riga è l'animazione di caricamento di WordPress - dovrai nasconderla inizialmente via CSS, e poi la funzione jQuery la mostrerà durante l'elaborazione)

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

Codice ispirato dall'eccellente tutorial di soulsizzle.

7 mag 2011 00:26:16
Commenti

Ottima risposta. Proverò a seguirla.

Chris_O Chris_O
7 mag 2011 00:30:42

Grazie mille per questo - mi ha aiutato tantissimo anche su un progetto su cui stavo lavorando. Un problema che ho incontrato è che ogni elemento nella lista ordinabile deve avere un ID che corrisponda all'ID del post. Questo era presente nel tutorial di soulsizzle ma non nel post originale dell'OP.

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

Hai perfettamente ragione, Dalton, sono stato troppo sintetico nel mio esempio. Codice aggiornato.

somatic somatic
29 ago 2011 04:11:06
0

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

Lontano dall'essere completato, ma l'idea è di inviare una richiesta ajax durante il drag and drop. Potresti anche voler attivare la richiesta ajax solo dopo aver cliccato un pulsante "salva" o qualcosa di simile. Verrebbe inviato un array contenente gli ID dei post e il nuovo ordine.

Poi dovresti aggiornare i post nel database lato server. Infine, aggiungi un parametro order al tuo loop WP_Query.

Spero che questo ti dia un inizio. Chiunque può continuare a sperimentare.

4 mag 2011 18:04:34
2
/**
 *  Carica i file javascript e 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');


/**
 *  Aggiorna l'ordine degli articoli via AJAX all'attivazione dell'evento di trascinamento
 */
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');


/**
 *  Visualizza gli articoli ordinati
 */
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 );

File 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 come gestire questa richiesta ajax
                    order: '4567,4569,4565 ' // Passa gli ID degli elementi della lista in formato 1,3,2. Scrivi il tuo metodo js per accedere alla lista degli id dal frontend.
                },
                success: function(data, response) {
                    console.log(response);
                },
                error: function(xhr,textStatus,e) {
                    alert(e);
                }

                });

        }
    });
28 mag 2019 03:05:41
Commenti

Per favore non limitarti a copiare il codice. Ti viene richiesto di aggiungere una spiegazione sul perché pensi che il codice sopra risponda alla domanda.

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

@MayeenulIslam La descrizione è già stata aggiunta all'interno degli snippet di codice come commento.

SkyRar SkyRar
28 mag 2019 23:13:12