使用wp_Query是否可以按分类法进行排序?

时间:2011-04-08 作者:yeope

我的问题很简单,我用WP_Query 要检索某些自定义类型的帖子,请使用tax_query.

现在我的问题是我想orderby 这个taxonomy, 但从文档和网络搜索中,我找不到解决方案。

这个orderby 在里面WP_Query 允许您按一组字段甚至自定义元字段排序,但它似乎不支持分类法。

有没有指向正确方向的指针?

谢谢大家。

11 个回复
最合适的回答,由SO网友:Otto 整理而成

不,不可能按分类法排序,因为从某种类型的角度来看,这实际上没有多大意义。

分类法是将事物分组的方法。因此,在帖子上使用分类法的目的实际上是在该分类法中包含在帖子之间共享的术语。如果一个分类法的术语只在每个帖子上使用,那么这将使分类法变得毫无意义。如果这些术语按其应有的方式共享,那么按其排序将不会产生任何特别有用的结果。

在这种情况下,您应该使用post meta。您可以按post meta排序,这对于每个帖子都是唯一的。

编辑:也就是说,您可以通过使用过滤器进行自定义SQL查询来按分类法排序,但无法从未修改的WP\\U查询中进行排序:http://scribu.net/wordpress/sortable-taxonomy-columns.html

然而,如果你不得不做这类事情,那么你的数据设计结构首先是错误的。分类法中的“术语”不是实际的“数据”。这些术语本身没有固有的含义,它们只是它们所描述的特定分组的标签。如果将它们视为有意义的数据,那么就存在潜在的设计缺陷。

分类法通过为事物分配术语来对它们进行分组。这种分组是分类法的全部要点,术语只是分组上的漂亮面孔。如果您有有有意义的元数据要分配给帖子,那么您应该改为使用帖子元数据。您可以排序,因为post meta同时使用键和值来存储信息。使用分类法,实际上只存储键,键的值是按该术语分组的帖子。

从长远来看,如果你使用正确的方法,事情会变得更容易。虽然我并不是说你不能对分类法做一些奇怪的事情,但从长远来看,你只是在错误地使用它,让事情变得更加困难。

SO网友:Aryan Duntley

这个问题的公认答案是不可接受的。认为按税收排序“没有意义”是不合逻辑的。他给出的答案没有道理。

考虑使用菜单栏类型。然后你有一个“食品类别”的海关税。食品分类税有“早餐”、“午餐”和“晚餐”三个术语。如果您使用tax\\u query参数提交查询,那么您现在就有了一个包含所有术语的结果集,但它们是按发布日期排序的。

为了从中获得与术语相关的正确顺序,然后通过将帖子分为不同的类别在前端进行适当显示,您必须遍历结果集,然后查询结果集中的每个帖子,以找到其术语并与当前术语进行比较,过滤成一个数组并继续整个过程。然后,您必须再次循环新数组以进行显示。这是没有成效的。

如果WP有一个“tax\\uu in”orderby选项,就像它有一个“post\\uu in”选项一样,那就太好了,但既然没有,你要么就必须执行上述荒谬的过程;通过“posts\\u orderby”过滤器和“posts\\u join”过滤器自定义查询,以分别调整orderby方法和将术语添加到结果集中;或者,您必须在与这些术语相关的html部分中对要筛选的每个术语进行新的查询。

最有效的方法是通过过滤器更改查询字符串。最简单的方法是进行三个单独的查询。WP API应处理按税务排序或任何限制性查询参数。如果您基于某些条件限制查询,则很有可能许多人需要根据这些条件进行排序。

SO网友:Drew Gourley

是的,但这很复杂。。。

添加到函数。主题中的php:

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 );
这是弗兰肯斯坦从一些发现的东西和一些我自己做的东西。解释起来很难,但你可能会说,底线是跑步?orderby=(分类查询变量)(&;订单=ASC(或DESC),她将立即起飞!

SO网友:Francis Yaconiello

我来晚了,但有一种更简单的方式。

像平常一样构建税务查询

$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;
设置query\\u post或WP\\u query的参数
$args = array(
    \'post_type\'=>\'post\',
    \'posts_per_page\'=>12,
    \'paged\'=>$paged,
    \'tax_query\' => $tax_query,
);
在进行query\\u posts/WP\\u查询调用之前,挂接orderby过滤器并覆盖它
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\');
之后不要忘记移除过滤器。。。

这适用于b/c。tax\\u查询为您创建联接等,您只需按联接中的一个字段排序。

SO网友:user3135691

我不知道为什么这里的所有解决方案都是过度的。好吧,这是五年前的事了,但我现在只运行以下代码,它可以正常工作:

   <?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);
    ?>
这将首先按字母顺序对CPT的分类法进行排序,并在这些分类法组中按字母顺序对als进行排序。

SO网友:Xavier Caliz

好吧,我想展示一下我在按类别/分类法对自定义帖子类型进行排序方面的经验。

THE WEB

<一个在WordPress上运行的旅行社网站,主要内容是关于名为“ruta”的自定义帖子类型的分类法,该结构类型为旅行>大陆>国家

THE CASE

在归档类别列表页面中,客户希望帖子按

大陆,按每条路线的数量排序

THE STEPS

First, 我从未修改的归档页查询中捕获到请求,该查询碰巧是这样的:

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
Second, 我在Sequel Pro中根据数据库编辑了sql代码,以符合我的需要。我得出这样的结论(是的,也许可以改进:我在MySQL方面的知识并不出众):

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  
Third, 我将查询挂接到函数上。带有三个过滤器的php文件:posts\\u字段、posts\\u join和posts\\u orderby

函数中的代码。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;
 }
Finally 根据某些条件,我从pre\\u get\\u post挂钩触发了过滤器

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\');
希望这能帮助别人

SO网友:serraosays

我遇到了一个与之非常相似的问题:我想按自定义分类法(问题)订购自定义的帖子类型存档(杂志文章)。我从不在我的网站上直接进行SQL查询,通常如果你喜欢这些其他答案,你需要重新考虑你的方法。

问题:

1) Wordpress不允许您以任何智能方式对分类法进行排序。

2) Wordpress不允许orderby 在post类型WP\\U查询上使用分类法(如Otto所述)。

解决方案:

1) 排序分类法最好由Custom Taxonomy Order NE 目前的插件。它允许您在中通过所见即所得对分类法进行排序wp-admin 我不会这么做,但我没有找到更好的。

当你安装插件时,你会得到一些类似于我在这里所做的事情。记下选项Auto-sort Queries of this Taxonomy - 将此设置为Custom Order as Defined Above; 这将为您提供所需的订单。屏幕截图:

Custom Taxonomy Order NE display

2) 有了分类法,现在可以创建一系列贯穿每个术语的WP\\U查询调用,从而有效地创建按分类法排序的存档。使用get_terms() 要创建所有税务术语的数组,请运行foreach 每个学期。这将创建WP_Query 对于将返回给定术语的所有帖子的每个术语项,有效地创建了按分类术语排序的存档。实现此操作的代码:

  // 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;
  }
本网站相关阅读:Display all posts in a custom post type, grouped by a custom taxonomy

SO网友:CodeShaman

这是我用来解决这个特殊问题的解决方案。此解决方案适用于无法同时使用pre_get_posts 筛选并在查询上存在现有分页(即: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);
我用它创建了一个nav菜单,按分类法、术语和每个术语的帖子数排序。

如果您只是想要帖子,请将查询更改为SELECT p.*GROUP BY p.ID

SO网友:honk31

我喜欢手动对术语进行排序,所以我使用插件来进行排序。我是pre_get_posts 过滤器,所以我采用了Drew Gourley的正确工作示例,并使其能够工作。所以这是一种特殊情况,但我无论如何都会发布这篇文章,以防它对某人有所帮助。以下代码进入函数。php或自定义插件。

首先让我们从过滤器开始。我们订购定制贴子类型music 按习惯分类法style

function so14306_pre_get_posts($query)
{
    if (is_admin()) :
        return;
    endif;

    if ($query->is_main_query()) :
        if (is_post_type_archive(\'music\')) :
            $query->set(\'orderby\', \'style\');

        endif;
    endif;
}

add_action(\'pre_get_posts\', \'so14306_pre_get_posts\');
然后我们调用post\\u子句过滤器:

function so14306_posts_clauses($clauses, $wp_query)
{
    global $wpdb;

    if (isset($wp_query->query_vars[\'orderby\']) && $wp_query->query_vars[\'orderby\'] === \'style\') {
        $orderby = $wp_query->query_vars[\'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 = \'{$orderby}\' OR taxonomy IS NULL)";
        $clauses[\'groupby\'] = "object_id";
        $clauses[\'orderby\'] = "GROUP_CONCAT({$wpdb->terms}.term_order ORDER BY {$wpdb->terms}.term_order ASC) ASC";
        $clauses[\'orderby\'] .= ", {$wpdb->posts}.post_name ASC";
    }

    return $clauses;
}

add_filter(\'posts_clauses\', \'so14306_posts_clauses\', 10, 2);
现在,您只需使用以下插件对分类法进行排序:Simple Custom Post Order. 这plugin is mandatory 对于此解决方案,因为它添加了列term_order 到数据库!

这一行:$clauses[\'orderby\'] .= ", {$wpdb->posts}.post_name ASC" 按标题对帖子进行排序,因此上述解决方案的完整排序是:分类术语=>帖子标题。

SO网友:JohnG

一种相当简单的方法是添加一个函数,该函数表示:

发布帖子时

  • 将其另存为您帖子的自定义元值,然后在循环中按该元值对帖子排序。

    因此:

    // 1
    add_action( \'publish_post\', \'save_and_add_meta\' );
    
    function save_and_add_meta($post_id){
    
            //Temporarily remove the action to avoid an infinite loop
            remove_action( \'publish_post\', \'save_and_add_meta\' );
    
            // 2            
            $category_slug = get_the_terms($post_id, \'your_taxonomys_name\')[0]->slug;
    
            //3
            add_post_meta($post_id, \'cat_slug\', $category_slug);
    
            //Add the action back in.
            add_action( \'publish_post\', \'save_and_add_meta\' );
    }
    
    然后在WP查询中将以下内容添加到$args中:

    \'meta_key\' => \'cat_slug\',
    \'orderby\' => \'meta_value\',
    \'order\' => \'DESC\',
    
    如果你能找到一种方法来限制用户在每篇文章中只分配一个类别,或者如果你的类别是互斥的,那么这种方法是有效的。但是,如果他们指定了多个类别,那么其中一个类别中就不会有该职位。

  • SO网友:Marcelo Viana

    这就像是在查询之前进行查询,但如果我们没有查询太多的帖子,就不会麻烦了。。。其想法是修改主查询,这样我们甚至不需要转到模板并生成新的查询和循环。。。

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

    结束

    相关推荐

    Saving Taxonomy Terms

    我有一个有趣的问题,希望有人能尽快回答。我已经创建了自己的metabox,它基于“我的metabox代码”(下面的列表)正确地显示了我创建的“event\\u types”分类中所有术语的下拉列表。我遇到的问题是,当从下拉列表中选择不同的术语并更新帖子时,能够保存/更新与帖子相关的术语。在对各种代码位进行修补之后,我发现通过手动将term\\u ID number[用逗号分隔]输入数组区域,我得到了我想要的结果。例如,如果在保存帖子时,函数将调用此代码wp_set_post_terms( $post_id