Cum să salvezi starea unui editor de layout drag and drop jQuery UI Sortables în interfața site-ului?
Construiesc un editor de layout pentru articole în interfața site-ului folosind jQuery UI Sortable.
Articolele sunt aranjate în cutii de 300px pe 250px peste o imagine de fundal. Articolele sunt create și editate din interfața de administrare WordPress dar vreau să permit administratorului site-ului să ajusteze ordinea cutiilor folosind o interfață drag and drop în frontend.
Am reușit să implementez partea de drag and drop sortable dar am nevoie de o metodă pentru a salva starea (ordinea) cutiilor. Ideal aș vrea să pot salva starea ca o opțiune și să o integrez în query.
Query-ul pentru articole este un simplu WP_Query care preia și date din custom meta boxes pentru a determina layout-ul individual al cutiilor:
$args= array(
'meta_key' => 'c3m_shown_on', // cheia meta
'meta_value'=> 'home' ); // valoarea meta
$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="Imagine 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>
JavaScript-ul este doar instrucțiunea de bază pentru sortable
jQuery(document).ready(function() {
jQuery("#sortable").sortable();
});
Există metode disponibile folosind cookie-uri pentru a salva starea dar trebuie să dezactivez și funcția de drag and drop pentru utilizatorii non-admin așa că am nevoie să salvez în baza de date.
Caut cea mai creativă și utilă metodă și voi acorda o recompensă de 100 de puncte pentru cel mai bun răspuns.
Update:
Am reușit să implementez răspunsul lui somatic cu o mică modificare.
ajaxurl nu returnează valoarea pe paginile non-admin așa că am folosit wp_localize_script( 'functions', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
pentru a defini valoarea și am schimbat linia JavaScript de sub options în:
url: MyAjax.ajaxurl,
Pentru a limita accesul la aranjarea ordinii doar pentru administratori am adăugat o condiție la funcția mea 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' ) ) );
}
}
O să mai fac câteva teste și voi marca această întrebare ca rezolvată și voi acorda recompensa.
Brady are dreptate că cea mai bună metodă de a gestiona salvarea și afișarea ordinii postărilor personalizate este prin utilizarea proprietății menu_order
.
Iată codul jQuery pentru a face lista sortabilă și pentru a transmite datele via AJAX către WordPress:
jQuery(document).ready(function($) {
var itemList = $('#sortable');
itemList.sortable({
update: function(event, ui) {
$('#loading-animation').show(); // Afișează animația de încărcare în timp ce așteptăm
opts = {
url: ajaxurl, // ajaxurl este definit de WordPress și indică spre /wp-admin/admin-ajax.php
type: 'POST',
async: true,
cache: false,
dataType: 'json',
data:{
action: 'item_sort', // Spune WordPress cum să gestioneze această cerere AJAX
order: itemList.sortable('toArray').toString() // Transmite ID-urile elementelor listei în format 1,3,2
},
success: function(response) {
$('#loading-animation').hide(); // Ascunde animația de încărcare
return;
},
error: function(xhr,textStatus,e) { // Poate fi extins pentru a furniza mai multe informații
alert(e);
// alert('A apărut o eroare la salvarea actualizărilor');
$('#loading-animation').hide(); // Ascunde animația de încărcare
return;
}
};
$.ajax(opts);
}
});
});
Iată funcția WordPress care ascultă pentru callback-ul AJAX și efectuează modificările în baza de date:
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');
Cheia pentru afișarea postărilor în ordinea pe care ai salvat-o este adăugarea proprietății menu_order
la argumentele query-ului:
$args= array(
'meta_key' => 'c3m_shown_on',
'meta_value'=> 'home'
'orderby' => 'menu_order',
'order' => 'ASC'
);
$box_query = new WP_Query($args);
Apoi rulează loop-ul și afișează fiecare element... (prima linie este animația de încărcare WordPress - vei dori să o ascunzi inițial prin CSS, iar funcția jQuery o va afișa în timpul procesării)
<img src="<?php bloginfo('url'); ?>/wp-admin/images/loading.gif" id="loading-animation" alt="Animație încărcare" title="Se încarcă..." />
<ul id="sortable">
<li id="{echo post ID here}">{echo title or other name here}</li>
</ul>
Cod inspirat din excelentul tutorial al lui soulsizzle.

Mulțumesc mult pentru asta - m-a ajutat enorm la ce lucram și eu. O problemă pe care am întâmpinat-o a fost că fiecare element din lista sortabilă trebuie să aibă un ID care să corespundă cu ID-ul postării. Acest lucru era prezent în tutorialul lui soulsizzle, dar nu în postarea inițială.

Departe de a fi finalizat, dar ideea este de a trimite o cerere AJAX la efectuarea acțiunii de drag and drop. De asemenea, poți dori să declanșezi cererea AJAX doar după ce apeși pe un buton "salvează" sau similar. Un array care conține ID-urile postărilor și noua ordine ar fi trimis.
Apoi, ar trebui să actualizezi postările în baza de date pe partea de server. În final, adaugă un parametru order
în bucla ta de WP_Query
.
Sper că acest lucru te ajută să începi. Oricine poate continua să lucreze la acest exemplu.

/**
* Încarcă fișierele javascript și 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');
/**
* Actualizează ordinea postărilor prin ajax la declanșarea evenimentului de drag and drop
*/
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');
/**
* Afișează postările sortate
*/
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 );
Fișier 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', // Spune WordPress-ului cum să gestioneze această cerere ajax
order: '4567,4569,4565 ' // Transmite ID-urile elementelor listei în format 1,3,2. Scrie-ți propria metodă js pentru a accesa lista de id-uri din frontend.
},
success: function(data, response) {
console.log(response);
},
error: function(xhr,textStatus,e) {
alert(e);
}
});
}
});
