Wie speichere ich den Status eines Front-End-Layout-Editors für jQuery UI Sortables per Drag & Drop?

20

Ich erstelle einen Front-End-Post-Layout-Editor mit jQuery UI Sortable .

Die Beiträge sind in 300 x 250 Pixel großen Feldern über einem Hintergrundbild angeordnet. Die Posts werden mit dem WordPress-Administrator erstellt und bearbeitet, aber ich möchte dem Site-Administrator erlauben, die Reihenfolge der Boxen über eine Drag & Drop-Oberfläche am Frontend anzupassen.

Ich habe das sortierbare Drag & Drop-Teil zum Laufen gebracht, muss aber einen Weg finden, um den Zustand (die Reihenfolge) der Boxen zu speichern. Idealerweise möchte ich den Zustand als Option speichern und in die Abfrage einbauen können.

Die Abfrage für die Posts ist eine einfache WP_Query, die auch Daten aus benutzerdefinierten Meta-Boxen abruft, um das Layout der einzelnen Boxen zu bestimmen:

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

Das Javascript ist nur die standardmäßige sortierbare Anleitung

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

Es gibt Methoden, die Cookies verwenden , um den Status zu speichern, aber ich muss auch das sortierbare Ziehen und Ablegen für Benutzer ohne Administratorrechte deaktivieren, damit ich wirklich in der Datenbank speichern muss.

Ich bin auf der Suche nach der kreativsten und nützlichsten Methode und werde die beste Antwort mit 100 Punkten belohnen.

Aktualisieren:

Ich habe Somatics Antwort mit einer kleinen Änderung erhalten.

ajaxurl gibt den Wert nicht auf Nicht-Admin-Seiten zurück, daher habe ich wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );den Wert definiert und die Javascript-Zeile unter den Optionen folgendermaßen geändert:
url: MyAjax.ajaxurl,

Um den Zugriff auf die Anordnung der Bestellung nur auf Administratoren zu beschränken, habe ich meiner Funktion wp_enqueue_script eine Bedingung hinzugefügt:

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

Ich werde ein wenig mehr testen und diese Frage als gelöst markieren und das Kopfgeld vergeben.

Chris_O
quelle
1
Könnten Sie menu_order für Posts verwenden? Ich weiß, dass Sie sie für Anhänge verwenden können. Warum also keine Posts? wenn es möglich ist, können Sie hier die Reihenfolge der Posts speichern ...
Brady
1
Sieht so aus, als könnten Sie - 'menu_order' - Reihenfolge nach Seitenreihenfolge festlegen. Wird am häufigsten für Seiten (Feld "Reihenfolge" im Feld "Seitenattribute bearbeiten") und für Anhänge (Ganzzahlfelder im Dialogfeld "Mediengalerie einfügen / hochladen") verwendet, kann jedoch für jeden Beitragstyp mit unterschiedlichen "menu_order" -Werten verwendet werden (alle Standardwerte) zu 0).
Brady
@ Brady Tolle Idee für die Verwendung von menu_order. @somatic erweitert darauf und es hat funktioniert. Vielen Dank!
Chris_O

Antworten:

21

Brady hat Recht, dass das Speichern und Anzeigen von benutzerdefinierten Post-Type-Aufträgen am besten über die menu_orderEigenschaft erfolgt

Hier ist die Abfrage, um die Liste sortierbar zu machen und die Daten über Ajax an WordPress zu übergeben:

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

Hier ist die WordPress-Funktion, die auf den Ajax-Rückruf wartet und die Änderungen an der Datenbank vornimmt:

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

Der Schlüssel zum Anzeigen der Beiträge in der von Ihnen gespeicherten Reihenfolge ist das Hinzufügen der menu_orderEigenschaft zu den Abfrageargs:

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

$box_query = new WP_Query($args);

Führen Sie dann Ihre Schleife aus und geben Sie jedes Element aus ... (Die erste Zeile ist die Kernanimation zum Laden von WP - Sie möchten sie zunächst über CSS ausblenden, und dann wird die Funktion jquery während der Verarbeitung angezeigt.)

<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 inspiriert durch das hervorragende Tutorial von soulsizzle .

somatisch
quelle
Hervorragende Antwort. Ich werde es versuchen.
Chris_O
Vielen Dank dafür - total geholfen an etwas, an dem ich auch gearbeitet habe. Ein Problem, auf das ich gestoßen bin, war, dass jedes Element in der sortierbaren Liste eine ID haben muss, die mit der Post-ID übereinstimmt. Dies war im Tutorial von soulsizzle, aber nicht im Beitrag des OP.
Dalton
Absolut richtig, Dalton, ich war in meinem Beispiel zu kurz. Code aktualisiert.
Somatic
4

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

Noch lange nicht fertig, aber die Idee ist, eine Ajax-Anfrage per Drag & Drop zu senden. Möglicherweise möchten Sie die Ajax-Anforderung auch erst auslösen, nachdem Sie auf die Schaltfläche "Speichern" oder eine andere Option geklickt haben. Ein Array mit Post-IDs und neuer Bestellung wird gesendet.

Dann müssten Sie die Posts in der Datenbank auf der Serverseite aktualisieren. Fügen Sie schließlich einen orderParameter zu Ihrer WP_QuerySchleife hinzu.

Ich hoffe, Sie haben damit angefangen. Jeder fühlt sich frei, weiter zu fummeln.

Geert
quelle
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 );

Javascript-Datei 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
quelle
Bitte nicht einfach den Code ausgeben. Sie werden gebeten, eine Erklärung hinzuzufügen, warum der obige Code Ihrer Meinung nach die Frage beantworten wird.
Mayeenul Islam
@MayeenulIslam Die Beschreibung wurde bereits in Code-Ausschnitten als Kommentarzeile hinzugefügt.
SkyRar