Comment enregistrer l'état d'un éditeur de mise en page frontal jQuery UI Sortables par glisser-déposer?

20

Je construis un éditeur de mise en page de publication à l'aide de jQuery UI Sortable .

Les messages sont disposés dans des boîtes de 300 x 250 pixels sur une image d'arrière-plan. Les messages sont créés et modifiés à l'aide de l'administrateur WordPress mais je veux permettre à l'administrateur des sites d'ajuster l'ordre des boîtes à l'aide d'une interface glisser-déposer sur le front-end.

J'ai la partie triable par glisser-déposer qui fonctionne, mais je dois trouver un moyen de sauvegarder l'état (l'ordre) des boîtes. Idéalement, j'aimerais pouvoir enregistrer l'état en tant qu'option et l'intégrer dans la requête.

La requête pour les publications est une simple WP_Query qui obtient également des données à partir de métadonnées personnalisées pour déterminer la disposition de la boîte individuelle .:

$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>

Le javascript n'est que les instructions de tri par défaut de base

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

Il existe des méthodes disponibles à l'aide de cookies pour enregistrer l'état, mais je dois également désactiver le glisser-déposer triable pour les utilisateurs non administrateurs, j'ai donc vraiment besoin d'enregistrer dans la base de données.

Je recherche la méthode la plus créative et la plus utilisable et attribuerai une prime de 100 points à la meilleure réponse.

Mise à jour:

J'ai obtenu la réponse de somatic avec un changement mineur.

ajaxurl ne renvoie pas la valeur sur les pages non admin, j'ai donc utilisé wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );pour définir la valeur et changé la ligne javascript sous options en:
url: MyAjax.ajaxurl,

Pour limiter l'accès à l'organisation de la commande aux seuls administrateurs, j'ai ajouté une condition à ma fonction 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' ) ) );
    }
}

Je vais faire un peu plus de tests et marquer cette question comme résolue et attribuer la prime.

Chris_O
la source
1
Est-il possible que vous puissiez utiliser menu_order sur les publications? Je sais que vous pouvez les utiliser sur des pièces jointes, alors pourquoi pas des publications? si c'est possible, c'est là que vous pouvez stocker l'ordre des messages ...
Brady
1
On dirait que vous pouvez - 'menu_order' - Order by Page Order. Utilisé le plus souvent pour les pages (champ Ordre dans la zone Modifier les attributs de page) et pour les pièces jointes (les champs entiers dans la boîte de dialogue Insérer / télécharger la galerie multimédia), mais peut être utilisé pour tout type de publication avec des valeurs 'menu_order' distinctes (elles sont toutes par défaut à 0).
Brady
@Brady Excellente idée sur l'utilisation de menu_order. @somatic l'a développé et cela a fonctionné. Merci!
Chris_O

Réponses:

21

Brady a raison de dire que la meilleure façon de gérer l'enregistrement et l'affichage des commandes de type de message personnalisé est d'utiliser la menu_orderpropriété

Voici le jquery pour rendre la liste triable et pour passer les données via ajax à 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);
        }
    }); 
});

Voici la fonction wordpress qui écoute le rappel ajax et effectue les modifications sur la base de données:

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 clé pour afficher les publications dans l'ordre que vous avez enregistré consiste à ajouter la menu_orderpropriété aux arguments de requête:

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

$box_query = new WP_Query($args);

Ensuite, exécutez votre boucle et sortez chaque élément ... (la première ligne est l'animation de chargement du noyau wp - vous voudrez la masquer initialement via css, puis la fonction jquery s'affichera lors du traitement)

<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 inspiré de l' excellent tutoriel de soulsizzle .

somatique
la source
Excellente réponse. Je vais vous donner un coup de feu.
Chris_O
Merci beaucoup pour cela - totalement aidé sur quelque chose sur lequel je travaillais aussi. Un problème que j'ai rencontré est que chaque élément de la liste triable doit avoir un ID qui correspond à l'ID du message. C'était dans le tutoriel de soulsizzle mais pas dans le post du PO.
Dalton
Absolument raison, Dalton, j'étais trop bref dans mon exemple. Code mis à jour.
somatique
4

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

Loin d'être terminé, mais l'idée est d'envoyer une requête ajax par glisser-déposer. Vous pouvez également vouloir déclencher la demande ajax uniquement après avoir cliqué sur un bouton "enregistrer" ou quelque chose. Un tableau contenant des identifiants de poste et une nouvelle commande serait envoyé.

Ensuite, vous devez mettre à jour les publications dans la base de données côté serveur. Enfin, ajoutez un orderparamètre à votreWP_Query boucle.

J'espère que cela vous aidera à démarrer. Quiconque se sent libre de continuer à jouer.

Geert
la source
0
/**
 *  Enqueue javascript and css files
 */
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');


/**
 *  Update order of posts by ajax on trigger of drag and drop event
 */
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');



/**
 *  Display sorted posts
 */
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 );

Fichier 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', // Tell WordPress how to handle this ajax request
                    order: '4567,4569,4565 ' // Passes ID's of list items in  1,3,2 format. Write your own js method to access the list of id from frontend.
                },
                success: function(data, response) {
                    console.log(response);
                },
                error: function(xhr,textStatus,e) {
                    alert(e);
                }

                });

        }
    });
SkyRar
la source
Veuillez ne pas simplement vider le code. Vous êtes prié d'ajouter quelques explications, pourquoi le code ci-dessus répondra à la question.
Mayeenul Islam
@MayeenulIslam La description a déjà été ajoutée à l'intérieur des extraits de code en tant que ligne de commentaire.
SkyRar