Interogare pentru sortarea unei liste după meta key întâi (dacă există) și afișarea postărilor rămase fără meta key ordonate după titlu
Lucrez la un șablon pentru o pagină de taxonomie personalizată unde dorim ca elementele conectate la termen să fie sortate după o dată de publicare (câmp de dată personalizat) - și dacă există mai multe elemente în aceeași zi (formatate ca YYYY-MM-DD) să fie apoi sortate după titlu, iar în final să sorteze după titlu dacă câmpul personalizat nu a fost completat (elementele mai vechi).
Așadar, am încercat în sute de moduri diferite cu WP_Query și returnează majoritatea rezultatelor așa cum doresc - dar în acest caz returnează doar elementele care au meta_key-ul publication_date. Toate celelalte elemente sunt ignorate și nu sunt afișate. Am încercat o meta_query folosind o relație "or" și am comparat publication_date ca EXISTS și NOT EXISTS, dar asta mi-a returnat 0 rezultate.
De asemenea, site-ul rulează încă versiunea 3.5.2 și nu doresc să facă upgrade.
Iată cea mai recentă interogare care îmi aduce postările care au câmpul personalizat publication_date afișat în ordinea corectă:
$term = get_queried_object(); // găsește termenul paginii de taxonomie pe care ne aflăm
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
array(
'taxonomy' => 'resource_types',
'field' => 'slug',
'terms' => $term->name,
)),
'meta_key' => 'publication_date',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'paged' => $paged,
'posts_per_page' => '10',
));
Am încercat și să folosesc wpdb și să rulez o interogare SQL, dar chiar nu sunt sigur cum să realizez ceea ce vreau făcând asta. Dacă cineva m-ar putea ajuta ar fi minunat!
Mulțumesc anticipat.

Mulțumesc tuturor pentru ajutor!
În final, interogarea de mai jos mi-a oferit rezultatele dorite - anume să afișez și să ordonez postările după un câmp personalizat "publication_date" mai întâi - sortând după dată, iar dacă există mai multe cu aceeași dată (de exemplu, 4 marcate cu iunie 2013), să le ordonez acestea după titlu. Apoi, după ce parcurge toate postările care au completat câmpul Publication Date, va parcurge din nou postările rămase, ordonate alfabetic după titlu.
Această soluție obține setul de rezultate într-o singură interogare și păstrează paginarea:
$term = get_queried_object();
the_post();
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
array(
'taxonomy' => 'resource_types',
'field' => 'slug',
'terms' => $term->name,
)),
'meta_query' => array(
'relation' => 'OR',
array( //verifică dacă data a fost completată
'key' => 'publication_date',
'compare' => '=',
'value' => date('Y-m-d')
),
array( //dacă nu există dată adăugată, afișează și aceste postări
'key' => 'publication_date',
'value' => date('Y-m-d'),
'compare' => 'NOT EXISTS'
)
),
'meta_key' => 'publication_date',
'orderby' => 'meta_value title',
'order' => 'ASC',
'paged' => $paged,
'posts_per_page' => '10',
));

Fain. Niciodată nu m-am gândit să rulez două meta_query
pe aceeași cheie!

Pentru mine (folosind WordPress 4.1.1), dacă setez meta_key
automat nu-l include chiar și cu NOT EXISTS
. Chiar sper că fac ceva greșit.

@RyanTaylor la fel și la mine - meta_key nu trebuie setat în interogare pentru ca asta să funcționeze, dar se pare că ordonează corect după valoarea meta chiar și când cheia meta nu este setată.

Conform comentariilor de mai sus, pentru WP 4.1+ eliminați sau comentați 'meta_key' => 'publication_date',
.

La câțiva ani mai târziu, codul postat de CSSGirl nu a funcționat pentru mine deoarece existau unele articole care nu aveau cheia meta sau cheia meta era goală, așa că iată ce a trebuit să fac pentru a avea toate articolele ordonate după dată și pentru a afișa mai întâi cele cu o valoare a cheii meta:
$args = array(
'post_type' => $type,
'post_status' => 'publish',
'nopaging' => TRUE,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => $meta_key,
'compare' => 'NOT EXISTS',
),
array(
'relation' => 'OR',
array(
'key' => $meta_key,
'value' => 'on',
),
array(
'key' => $meta_key,
'value' => 'on',
'compare' => '!=',
),
),
),
'orderby' => array( 'meta_value' => 'DESC', 'date' => 'DESC' ),
);

Cred că ar trebui să folosești două bucle separate. Poți captura toate articolele găsite în prima buclă și apoi să le excludi ușor din a doua buclă:
$found_posts = array();
while($loop->have_posts()): $loop->the_post();
// conținutul buclei
$found_posts[] = get_the_id();
endwhile;
wp_reset_query();
$args = array(
// alți parametri
'post__not_in' => $found_posts,
);
Apoi poți rula a doua buclă.

a funcționat - dar a stricat paginarea - ai vreo idee cum să rezolvăm asta? Iată cum arată acum: echo paginate_links( array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?page=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $publication_query->max_num_pages,
'prev_text' => __('Previous |'),
'next_text' => __('| Next'),
) );

Există vreun motiv pentru care nu ai putea impune ca cheia meta publication_date să existe pentru fiecare articol, chiar și cu o valoare goală?
Deci în acțiunea ta save_post
ai adăuga/actualiza cheia meta indiferent dacă valoarea din $_POST
este goală sau nu.
Ar trebui să rulezi un script de actualizare pentru a parcurge articolele mai vechi și a adăuga cheia cu o valoare goală, de exemplu:
add_action( 'admin_init', 'update_old_posts' );
function update_old_posts() {
if ( ! isset( $_GET[ 'update_old_posts' ] ) )
return;
foreach( get_posts() as $post ) {
if ( false === get_post_meta( $post->ID, 'publication_date', true ) ) {
update_post_meta( $post->ID, 'publication_date', '' );
echo "Actualizat {$post->post_title} <br />";
}
}
die;
}
Rulează-l accesând http://example.com/wp-admin/?update_old_posts
Apoi poți folosi aceeași interogare pe care o ai. Poate dorești să adaugi un filtru suplimentar pentru a putea ordona după diferite coloane în direcții diferite, ar avea sens să sortezi după dată în ordine descrescătoare și după titlu în ordine crescătoare.
add_filter( 'posts_orderby', 'multicolumn_orderby', 10, 2 );
function multicolumn_orderby( $orderby, $query ) {
global $wpdb;
// verifică dacă este interogarea corectă
if ( $query->get( 'meta_key' ) == 'publication_date' ) {
$orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
}
return $orderby;
}

Am creat o clauză WHERE personalizată. Am testat-o folosind $wp_query->request
chiar înainte de bucla mea principală, nu cunosc foarte bine SQL, dar acest lucru a funcționat.
add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
if(!$query->is_main_query())
return;
//Suprascrie argumentele interogării
$query->set('meta_query', array(
array(
'key' => 'TRENDING',
//'value' => 'asdfasdf',//poate fi necesară o valoare pentru versiunile mai vechi de WordPress
'compare' => 'NOT EXISTS',
)
));
$query->set('orderby', 'meta_value_num date');
$query->set('order', 'DESC');
}
add_filter('posts_where', 'add_trending_where');
function add_trending_where($where = ''){
global $wpdb, $wp_query;
if(!$wp_query->is_main_query())//Nu sunt sigur dacă funcționează cu adevărat. Ar trebui să fie OK
return $where;
$where .= " OR ( $wpdb->postmeta.meta_key = 'TRENDING' )";
// Nu rula acest cod de două ori
remove_filter('posts_where', 'add_trending_where');
return $where;
}
Alternativ, ai putea seta compare
la 'EXISTS'
și să schimbi linia din add_trending_where în $where .= " OR ($wpdb->postmeta.post_id IS NULL)";
. Atunci ar trebui să modifici valoarea cheii doar într-un singur loc. Din nou, folosește $wp_query->request
și experimentează dacă vrei să înțelegi mai bine sau să ajustezi acest lucru.
EDIT: Tocmai am observat că acest lucru nu funcționează dacă meta_key
este setat în interogare. Ai putea folosi $query->set('meta_key', NULL);
dacă este necesar.
EDIT 2: Am reușit să fac acest lucru să funcționeze cu metoda de mai sus. Din nu știu ce motiv, nu a funcționat la început (poate meta_key era setat... nu știu).
add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
// Renunță dacă nu este interogarea principală "ascunsă", spre deosebire de un apel 'new WP_Query()'
if(!$query->is_main_query())
return;
// Setează meta_query pentru a obține share-uri pentru orderby și, de asemenea, conținut nepartajat.
$query->set('meta_query', array(
'relation' => 'OR',
array(
'key' => 'TRENDING',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'TRENDING',
'compare' => 'EXISTS',
)
));
//$query->set('meta_key', NULL);
$query->set('orderby', array('meta_value_num' => 'DESC', 'date' => 'DESC'));
}
