it-swarm.com.de

Ist es mit wp_query möglich, nach Taxonomie zu bestellen?

Meine Frage ist einfach: Ich verwende WP_Query, um mithilfe von tax_query einige benutzerdefinierte Posts abzurufen, die nach einer Taxonomie gefiltert wurden.

Jetzt ist mein Problem, dass ich nach der Taxonomie ordnen möchte, aber aufgrund der Dokumentation und der Suche im Web kann ich keine Lösung finden.

Mit orderby in WP_Query können Sie nach einer Reihe von Feldern sortieren, auch nach benutzerdefinierten Metafeldern, aber die Taxonomie scheint nicht unterstützt zu werden.

Irgendwelche Hinweise auf die richtige Richtung?

Danke euch allen.

48
yeope

Nein, es ist nicht möglich, nach Taxonomie zu ordnen, da dies unter bestimmten Gesichtspunkten eigentlich keinen Sinn ergibt.

Taxonomien sind Möglichkeiten, Dinge zu gruppieren. Der Sinn einer Taxonomie für Stellen wäre es also, Begriffe in dieser Taxonomie zu haben, die zwischen Stellen geteilt werden. Wenn eine Taxonomie Begriffe hätte, die jeweils nur für einen Beitrag verwendet wurden, würde dies die Taxonomie sinnlos machen. Und wenn die Begriffe so geteilt würden, wie sie sollten, würde eine Bestellung danach nichts besonders Nützliches ergeben.

Was Sie in einer solchen Situation verwenden sollten, ist das Post-Meta. Sie können per Post-Meta bestellen, und es ist für jeden Post einzigartig.

Bearbeiten: Das heißt, Sie können nach Taxonomie ordnen, indem Sie eine benutzerdefinierte SQL-Abfrage mit einem Filter erstellen. Dies ist in einer nicht geänderten WP_Query nicht möglich: http://scribu.net/wordpress/sortable-taxonomy-columns. html

Wenn Sie jedoch auf diese Art zurückgreifen müssen, ist Ihre Datenentwurfsstruktur in erster Linie falsch. "Begriffe" in der Taxonomie sind keine tatsächlichen "Daten". Die Begriffe selbst haben keine inhärente Bedeutung, sie sind nur Bezeichnungen für die bestimmte Gruppierung, die sie beschreiben. Wenn Sie sie als aussagekräftige Daten behandeln, liegt Ihnen ein Konstruktionsfehler zugrunde.

Taxonomien gruppieren Dinge, indem sie ihnen Begriffe zuweisen. Diese Gruppierung ist der springende Punkt bei Taxonomien. Die Begriffe sind nur hübsche Gesichter in der Gruppierung. Wenn Sie aussagekräftige Metadaten haben, die Sie einem Beitrag zuordnen können, sollten Sie stattdessen das Beitrags-Meta verwenden. Und dass Sie können bestellen, weil Post-Meta sowohl Schlüssel als auch Werte zum Speichern von Informationen verwendet. Mit einer Taxonomie speichern Sie wirklich nur Schlüssel, deren Werte die nach diesem Begriff gruppierten Beiträge sind.

Auf lange Sicht sind die Dinge einfacher, wenn Sie den richtigen Ansatz dafür verwenden. Ich sage zwar nicht, dass Sie mit Taxonomie nichts Seltsames anfangen können, aber Sie erschweren sich die Dinge auf lange Sicht, indem Sie sie falsch verwenden.

13
Otto

Die akzeptierte Antwort auf diese Frage ist nicht akzeptabel. Es ist unlogisch anzunehmen, dass eine Bestellung nach Steuern "keinen Sinn ergibt". Die Antwort, die er gab, ergibt keinen Sinn.

Erwägen Sie, einen Menüpfostentyp zu haben. Dann haben Sie eine benutzerdefinierte Steuer von "FoodCategories". Die FoodCategories-Steuer beinhaltet die Begriffe "Frühstück", "Mittagessen" und "Abendessen". Wenn Sie eine Abfrage mit dem Parameter tax_query senden, wird jetzt eine Ergebnismenge mit allen Begriffen angezeigt, die jedoch nach dem Postdatum sortiert sind.

Um die richtige Reihenfolge dieser Einträge im Verhältnis zu ihren Begriffen zu ermitteln und sie dann am Frontend entsprechend anzuzeigen, indem Sie die Beiträge in ihre verschiedenen Kategorien unterteilen, müssen Sie die Ergebnismenge durchlaufen und dann jeden einzelnen Beitrag innerhalb der abfragen Ergebnismenge, um die Begriffe zu finden und mit dem aktuellen Begriff zu vergleichen, in ein Array zu filtern und fortzufahren. Anschließend müssen Sie das neue Array erneut durchlaufen, um es anzuzeigen. Das ist nicht produktiv.

Es wäre schön, wenn WP eine "tax__in" orderby-Option hätte, wie es eine "post__in" -Option tut, aber da dies nicht der Fall ist, müssen Sie entweder den obigen lächerlichen Prozess ausführen; Passen Sie die Abfrage mithilfe der Filter "posts_orderby" und "posts_join" an, um die orderby-Methode anzupassen und den Begriff der Ergebnismenge hinzuzufügen. Oder Sie müssen eine neue Abfrage für jeden Begriff erstellen, nach dem Sie in den HTML-Abschnitten im Verhältnis zu diesen Begriffen filtern.

Am effizientesten wäre es, die Abfragezeichenfolge über Filter zu ändern. Am einfachsten wäre es, drei separate Abfragen durchzuführen. Die API WP sollte die Bestellung nach Steuern oder restriktiven Abfrageparametern verarbeiten. Wenn Sie eine Abfrage basierend auf bestimmten Bedingungen einschränken, besteht eine hohe Wahrscheinlichkeit, dass viele nach denselben Bedingungen bestellen müssen.

43
Aryan Duntley

Ja, aber es ist ziemlich verwickelt ...

Füge zu functions.php in deinem Theme hinzu:

function orderby_tax_clauses( $clauses, $wp_query ) {
    global $wpdb;
    $taxonomies = get_taxonomies();
    foreach ($taxonomies as $taxonomy) {
        if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby'] ) {
            $clauses['join'] .=<<<SQL
LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb->term_relationships}.object_id
LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
SQL;
            $clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
            $clauses['groupby'] = "object_id";
            $clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
            $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ? 'ASC' : 'DESC';
        }
    }
    return $clauses;
}

    add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );

Dies ist frankensteined von einigen gefundenen Sachen und einige Sachen, die ich selbst gemacht habe. Das zu erklären ist ziemlich schwierig, aber das Fazit ist, dass dies läuft. Sie können? Orderby = (Taxonomie-Abfrage var) & order = ASC (oder DESC) setzen und sie wird gleich abheben!

15
Drew Gourley

Ich komme hier zu spät zum Spiel, aber es gibt eine einfachere Möglichkeit, dies mit WordPressy zu tun.

Erstellen Sie Ihre Steuerabfrage wie gewohnt.

$tax_query = array();
$tax_query['relation']="OR";
$tax_query[] = array(
    'taxonomy' => 'product_cat',
    'field'    => 'slug',
    'terms'    => $cat_terms,
);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

Richten Sie Ihre Argumente für query_posts oder WP_Query ein

$args = array(
    'post_type'=>'post',
    'posts_per_page'=>12,
    'paged'=>$paged,
    'tax_query' => $tax_query,
);

Bevor Sie den Aufruf von query_posts/WP_Query ausführen, schließen Sie sich dem orderby-Filter an und überschreiben Sie ihn

add_filter('posts_orderby', 'edit_posts_orderby');
function edit_posts_orderby($orderby_statement) {
    $orderby_statement = " term_taxonomy_id ASC ";
    return $orderby_statement;
}
query_posts($args);
remove_filter('posts_orderby', 'edit_posts_orderby');

vergessen Sie nicht, den Filter danach zu entfernen ...

dies funktioniert b/c die tax_query erstellt die Joins usw. für Sie, Sie müssen nur durch eines der Felder aus dem Join bestellen.

9

Nun, ich möchte meine Erfahrungen mit dem Sortieren benutzerdefinierter Beitragstypen nach Kategorie/Taxonomie offenlegen.

DAS NETZ

  1. Eine Reisebürowebsite, die unter WordPress ausgeführt wird
  2. Hauptinhalt des benutzerdefinierten Post-Typs "ruta"
  3. Taxonomie mit dieser Struktur Reiseart> Kontinent> Land

DER FALL

Auf Seiten mit Archivkategorielisten wollte der Kunde, dass die Beiträge nach sortiert werden

  1. Der Kontinent, geordnet nach der Anzahl der Routen.
  2. Das Land, alphabetisch sortiert.

DIE SCHRITTE

Erstens , ich fange die Anfrage von der unmodifizierten Archivseite ab, die zufällig so war:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
FROM wp_posts 
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) 
WHERE 1=1 
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) )
AND wp_posts.post_type IN ('ruta', 'nav_menu_item') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45 
AND wp_posts.post_status = 'private') 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC LIMIT 0, 20

Zweitens , ich habe den SQL-Code in Sequel Pro für die Datenbank bearbeitet, um meinen Anforderungen zu entsprechen. Ich komme mit diesem heraus (ja, wahrscheinlich kann es verbessert werden: mein Wissen über MySQL ist nicht hervorragend):

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, tt1.parent AS pare,
    (
    SELECT COUNT(*) 
    FROM  wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id =      wp_term_relationships.term_taxonomy_id )
    INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id =  tt1.term_taxonomy_id )
    WHERE 1=1  
    AND tt1.parent = pare
    ) AS Total
FROM  wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id =      wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )
WHERE 1=1  
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) ) 
AND wp_posts.post_type IN ('ruta', 'nav_menu_item') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45 
AND wp_posts.post_status = 'private') 
GROUP BY wp_posts.ID 
ORDER BY
total DESC,
wp_terms.name  

Drittens , ich habe die Abfrage in der Datei functions.php mit drei Filtern verknüpft: posts_fields, posts_join und posts_orderby

Der Code in functions.php:

function xc_query_fields( $fields ) {

   $fields = "wp_posts.ID, wp_posts.post_title, wp_terms.name, tt1.parent AS pare,
    (
    SELECT COUNT(*) 
    FROM  wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
    INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id = tt1.term_taxonomy_id )
    WHERE 1=1  
    AND tt1.parent = pare
    )
    AS Total";
     return $fields;
}


function xc_query_joins( $join ) {
$join .= "INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
   INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
   INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )";
 return $join;
}


function xc_query_orderby( $join ) {
    $join = "total DESC, wp_terms.name ";
    return $join;
 }

Schließlich Ich habe die Filter aus dem pre_get_post-Hook unter bestimmten Bedingungen ausgelöst

function filtra_queries( $query )
{

  if (  is_archive()  && $query->is_main_query() && !is_admin()  ) {

$rutes = array('viajes-privados', 'asia', 'africa', 'oceania', 'america', 'oriente-proximo');

if  ( in_array( $query->get('category_name'), $rutes ) ) 
  {
  add_filter( 'posts_fields', 'xc_query_fields' );
  add_filter( 'posts_join', 'xc_query_joins' );
  add_filter( 'posts_orderby', 'xc_query_orderby' );
}// end if in_array

  }// end if is_archive

}
 add_filter('pre_get_posts', 'filtra_queries');

Hoffe das kann jemandem helfen

2
Xavier Caliz

Ich hatte ein sehr ähnliches Problem: Ich möchte ein benutzerdefiniertes Post-Type-Archiv (Zeitschriftenartikel) nach einer benutzerdefinierten Taxonomie (Ausgaben) bestellen. Ich führe niemals direkte SQL-Abfragen auf meiner Site durch - und normalerweise müssen Sie Ihren Ansatz überdenken, wenn Sie wie diese anderen Antworten sind.

PROBLEME:

1) Mit Wordpress können Sie Taxonomien nicht auf intelligente Weise bestellen.

2) Wordpress erlaubt es orderby einfach nicht, Taxonomien für WP_Query nach dem Typ (wie von Otto dargelegt) zu verwenden.

LÖSUNGEN:

1) Das Sortieren von Taxonomien wird derzeit am besten mit dem Custom Taxonomy Order NE Plugin durchgeführt. Es ermöglicht Ihnen, die Taxonomie über WYSIWYG in wp-admin zu bestellen, was nicht so ist, wie ich es tun würde, aber ich habe nichts Besseres gefunden.

Wenn Sie das Plugin einrichten, erhalten Sie etwas Ähnliches wie hier. Notieren Sie sich die Option Auto-sort Queries of this Taxonomy - setzen Sie diese auf Custom Order as Defined Above; Dadurch erhalten Sie die Bestellung, die Sie benötigen. Bildschirmfoto:

 Custom Taxonomy Order NE display 

2) Mit einer sortierten Taxonomie können Sie jetzt eine Reihe von WP_Query-Aufrufen erstellen, die sich über jeden Begriff erstrecken. Auf diese Weise wird ein Archiv erstellt, das nach Taxonomie geordnet ist. Verwenden Sie get_terms(), um ein Array aller Steuerbedingungen zu erstellen, und führen Sie dann für jede Bedingung eine foreach aus. Dadurch wird für jedes Begriffselement ein WP_Query erstellt, der alle Beiträge für einen bestimmten Begriff zurückgibt. Auf diese Weise wird effektiv ein Archiv erstellt, das nach Taxonomiebegriffen geordnet ist. Code, um dies zu ermöglichen:

  // Get your terms and put them into an array
  $issue_terms = get_terms([
    'taxonomy' => 'issues',
    'hide_empty' => false,
  ]);

  // Run foreach over each term to setup query and display for posts
  foreach ($issue_terms as $issue_term) {
    $the_query = new WP_Query( array(
      'post_type' => 'post',
      'tax_query' => array(
        array(
          'taxonomy' => 'issues',
          'field' => 'slug',
          'terms' => array( $issue_term->slug ),
          'operator' => 'IN'
        )
      )
    ) );

    // Run loop over each query
    while($the_query->have_posts()) :
      $the_query->the_post();

      // YOUR TEMPLATE OUTPUT FOR EACH POST

    endwhile;
  }

Verwandte Lektüre auf dieser Site: Alle Posts in einem benutzerdefinierten Post-Typ anzeigen, gruppiert nach einer benutzerdefinierten Taxonomie

2
staypuftman

Ich bin nicht sicher, warum alle Lösungen hier ziemlich übertrieben sind. OK, es ist ein halbes Jahrzehnt her, aber ich führe gerade den folgenden Code aus und es funktioniert:

   <?php // Default
    $wheels_args = array(
        'post_type' => 'wheels',
        'posts_per_page' => '96',
        'orderby' => 'taxonomy, name', // Just enter 2 parameters here, seprated by comma
        'order'=>'ASC'
    );
    $loop = new WP_Query($wheels_args);
    ?>

Dies sortiert die Taxonomien Ihres CPT zuerst nach ihrer Taxonomie in alphabetischer Reihenfolge und innerhalb dieser Taxonomiegruppen auch nach alphabetischer Reihenfolge.

1
user3135691

Hier ist die Lösung, die ich für dieses spezielle Problem verwendet habe. Diese Lösung ist für extreme Fälle gedacht, in denen es nicht möglich ist, einen pre_get_posts-Filter zu verwenden und die Abfrage eine Paginierung enthält (z. B. WooCommerce):

global $wpdb;

$taxonomies = array('my-tax-1', 'my-tax-2', 'my-tax-3');

$orderby = "'".implode("', '", array_keys($taxonomies))."'";
$id_sql = $GLOBALS['wp_query']->request;

$id_sql = preg_replace('/LIMIT\s+\d+\s?,?\s\d*/', '', $id_sql);
$id_sql = str_replace('SQL_CALC_FOUND_ROWS', '', $id_sql);

$term_sql = "SELECT
  tt.taxonomy AS `taxonomy`,
  t.name AS `term_name`,
  t.slug AS `term_slug`,
  count(*) AS `term_count`
FROM ({$id_sql}) p 
JOIN wp_term_relationships tr
  ON p.ID = tr.object_id
JOIN wp_term_taxonomy tt
  ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms t
  ON tt.term_id = t.term_id
WHERE tt.taxonomy IN ({$orderby})
GROUP BY t.slug
ORDER BY
  FIELD(tt.taxonomy, {$orderby})"; // Add further specific ordering here

$results = $wpdb->get_results($term_sql, ARRAY_A);

Ich habe dies verwendet, um ein Navigationsmenü zu erstellen, das nach Taxonomie, Begriff und Anzahl der Beiträge pro Begriff geordnet ist.

Wenn Sie einfach die Beiträge möchten, ändern Sie die Abfrage in SELECT p.* und GROUP BY p.ID.

1
CodeShaman

Es ist wie eine Abfrage vor der Abfrage, aber es stört nicht, wenn nicht zu viele Beiträge abgefragt werden. Die Idee ist, die Hauptabfrage so zu ändern, dass wir nicht einmal zu Vorlagen gehen und neue Abfragen generieren müssen Schleifen ...

function grouped_by_taxonomy_main_query( $query ) {

    if ( $query->is_home() && $query->is_main_query() ) { // Run only on the homepage

        $post_ids = array();

        $terms = get_terms('my_custom_taxonomy');

        foreach ( $terms as $term ) {
            $post_ids = array_merge( $post_ids, get_posts( array( 
                'posts_per_page' => 4, // as you wish...
                'post_type' => 'my_custom_post_type', // If needed... Default is posts
                'fields' => 'ids', // we only want the ids to use later in 'post__in'
                'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // getting posts in the current term
            );
        }

        $query->query_vars['post_type'] = 'my_custom_post_type'; // Again, if needed... Default is posts
        $query->query_vars['posts_per_page'] = 16; // If needed...
        $query->query_vars['post__in'] = $post_ids; // Filtering with the post ids we've obtained above
        $query->query_vars['orderby'] = 'post__in'; // Here we keep the order we generated in the terms loop
        $query->query_vars['ignore_sticky_posts'] = 1; // If you dont want your sticky posts to change the order

    }
}

// Hook my above function to the pre_get_posts action
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
0
Marcelo Viana