是否按子类别/术语对主查询进行排序?

时间:2015-07-27 作者:Luca Reghellin

我有一篇“下载”的自定义帖子,上面有他的自定义分类法。分类法有两个主要术语。其中一个有4个子项。我目前正在使用wp模板系统将父术语的标准wpquery获取到taxonomy-taxonomyname-termname.php 页直到这里,一切都很好。

现在我想做的是显示父术语下的所有帖子,不分页(这不是问题)。但我想显示它们按子项拆分/分组(在4个子项组中的每个子项组上方都有子项名称)。

通常,我会执行自定义查询。但由于这次我试图利用默认的wp查询系统,所以我只想使用循环。有没有办法按子术语对职位进行分组?

3 个回复
最合适的回答,由SO网友:Luca Reghellin 整理而成

好的,谢谢大家的回答。无论如何,我需要更多的灵活性,所以我最终没有使用wp模板自动糖。。。

因此,这个答案与我最初的问题没有严格的联系,但我认为它也可以帮助人们。

我构建了一个自定义函数,从特定的自定义分类法和可选的父术语中检索一组自定义帖子。如果父项通过,则返回的帖子将属于直接父项术语子项。代码如下:

// $post_type: string
    // $taxonomy: string
    // $parent_term: string (slug) || int (term_id)
    // retrieves posts of a specific post_type and taxonomy, sorted by term
    function get_taxonomy_posts($post_type, $taxonomy, $parent_term = \'\'){

        if(!$post_type || !$taxonomy) return false;

        global $wpdb;

        //if $parent_term is defined and is not an integer then should be a slug, so let\'s get its id
        if(!empty($parent_term) && !is_int($parent_term)){
            $parent_data = get_term_by(\'slug\',$parent_term,$taxonomy);
            $parent_term = $parent_data->term_id;
        }

        $term_ids = get_terms($taxonomy, array( \'parent\' => $parent_term, \'fields\' => \'ids\' ));
        if(is_wp_error($term_ids)) return false;

        $term_ids_str = implode(\',\',$term_ids);

      // NOTE: terms.term_order gets added to tables by this plugin:
      // http://wordpress.org/plugins/taxonomy-terms-order/
      $query = $wpdb->prepare(
        "select p.ID, p.post_title, p.post_content, p.post_excerpt, t.term_id, t.term_order, t.name as term_name, t.slug as term_slug, tt.count
        from " . $wpdb->prefix . "posts p
        inner join " . $wpdb->prefix . "term_relationships rel on p.ID = rel.object_id
        inner join " . $wpdb->prefix . "term_taxonomy tt on tt.term_taxonomy_id = rel.term_taxonomy_id
        inner join " . $wpdb->prefix . "terms t on tt.term_id = t.term_id
        where p.post_type = %s and p.post_status = %s and t.term_id in (" . $term_ids_str . ")
        order by t.term_order, p.menu_order"
        ,$post_type
        ,"publish"
      );

      $records = $wpdb->get_results($query);
      $posts_array = array();

      foreach($records as $record){
        $term_name = $record->term_name;
        if(!key_exists($term_name, $posts_array)) $posts_array[$term_name] = array();
        $posts_array[$term_name][] = $record;
      }

      return $posts_array;

    }//end get taxonomy_posts 
它将为您提供一个数组,其中键是术语名称,值是属于该术语的帖子数组(或者更准确地说,帖子的帖子数据)。它可以很容易地修改为将例如键作为term\\u id而不是term\\u name。返回的单个post数据如下所示:

    object(stdClass)#2308 (9) {
      ["ID"]=>
      string(3) "269"
      ["post_title"]=>
      string(26) "title"
      ["post_content"]=>
      string(0) "content"
      ["post_excerpt"]=>
      string(0) "excerpt"
      ["term_id"]=>
      string(3) "803"
      ["term_order"]=>
      string(1) "2"
      ["term_name"]=>
      string(27) "term name"
      ["term_slug"]=>
      string(26) "term-slug"
      ["count"]=>
      string(1) "3"
    }
旁注1:目前,我正在使用分类术语排序插件,因此在查询中,我按照custom term\\u order字段对术语进行排序。同样,如果您不使用插件,只需根据您的喜好更改检索到的字段和order by子句。

旁注2:代替分类法taxonomyname termname。php,现在我基本上使用一个虚拟页面并应用一个自定义模板(我的意思是/* Template Name: [name] */): 这不是强制性的,但我这样做是为了让wp的主查询只执行一个简单的1 post查询,而不是一种重复的术语查询。

希望有帮助!

SO网友:Pieter Goosen

如果有人想用更好、更正确、更有效的方法来完成事情,那就太棒了。实现你所需要的并不困难。

工作流程:使用usort() 创建自定义排序顺序

使用the_posts 在执行循环之前,筛选以排序并返回已排序的帖子数组

在这个循环中,你所需要做的就是比较之前的帖子和当前的帖子,并采取行动

代码:

让我们看看代码:

首先,使用usort()the_posts 筛选器:(至少需要PHP 5.4+。如果您至少没有PHP 5.4,那么您肯定会遇到安全问题。还要注意,所有代码都未经测试,可能存在错误)

add_filter( \'the_posts\', function ( $posts, $q )
{
    if ( $q->is_main_query() // Target the main query only
         && $q->is_tax() // Change to target only specific term or taxonomy
    ) {
        /**
         * We will now sort the $posts array before the loop executes. We will use usort()
         *
         * There is a bug in usort causing the following error:
         * usort(): Array was modified by the user comparison function
         * @see https://bugs.php.net/bug.php?id=50688
         * This bug has yet to be fixed, when, no one knows. The only workaround is to suppress the error reporting
         * by using the @ sign before usort
         */
        @usort( $posts, function ( $a, $b )
        {
            /**
             * Get the respective terms from the posts 
             * We will use the first term\'s name
             */
            $array_a = get_the_terms( $a->ID, \'TAXONOMY_NAME_HERE\' )[0]->name;
            $array_b = get_the_terms( $b->ID, \'TAXONOMY_NAME_HERE\' )[0]->name;

            // Sort by term name, if they are the same, sort by post date
            if (  $array_a != $array_b ) {
                return strcasecmp( $array_a, $array_b ); // Sort terms alphabetically, ascending
                // return strcasecmp( $array_b, $array_a ); // Sort terms alphabetically, descending
            } else {
                return $a < $b; // Sort by date if terms are the same. Change < to > if the post date order is incorrect
            }
        }
    }
}, 10, 2 );
这应该负责排序。正如我所说的,只需确保日期排序在条款范围内正确即可。如果没有,只需更改<>

现在,我们可以在循环中显示术语名称。根据需要进行调整和修改

if ( have_posts() ) {
    // Define variable to hold previous post term name
    $term_string = \'\';
    while ( have_posts() ) {
    the_post();
        global $post;
        // Get the post terms. Use the first term\'s name
        $term_name = get_the_terms( $post->ID, \'TAXONOMY_NAME_HERE\' )[0]->name;
        // Display the taxonomy name if previous and current post term name don\'t match
        if ( $term_string != $term_name )
            echo \'<h2>\' . $term_name . \'</h2>\'; // Add styling and tags to suite your needs

        // Update the $term_string variable
        $term_string = $term_name;

        // REST OF YOUR LOOP

    }
}

SO网友:Mike

如果我正确理解了这个问题,您希望生成如下内容:

第1分项

职位2

[…]

分项2第1栏

职位2

[…]

也许有一种比我要告诉你的更有效的方法,但我会尝试这样的方法:

首先创建一个数组来保存已排序的帖子

$sortedPosts = array();
接下来,为每个子项创建一个数组
foreach ($subTerms as $subTerm) {
    $sortedPosts[$subTerm] = array();
}
循环浏览查询中的帖子,并根据指定的术语对其进行排序
if (have_posts()) {
    while (have_posts()) {
        the_post();
        $postTerms = get_terms(\'taxonomyName\', array(\'fields\' => \'name\'));

        if (is_array($postTerms)) {
            foreach ($subTerms as $subTerm) {
                if (in_array($subTerm, $postTerms)) {
                    global $post;

                    $sortedPosts[$subTerm][] = $post;
                    /* This grabs the array stored at $sortedPosts[$subTerm]
                       and then inserts the current post at the end of it. */
                }
            }
        }
    }
}
对所有帖子进行排序后,在排序后的数组中循环以打印显示
foreach ($subTerms as $subTerm) {
    $myPosts = $sortedPosts[$subTerm];

    echo \'<h1>\' . $subTerm . \'</h1>\';

    foreach ($myPosts as $currentPost) {
        global $post;
        $post = $currentPost;

        // Enter post display stuff here
    }

    echo \'<hr>\'
}

结束

相关推荐

List Terms by category

我有一个自定义分类法叫做portfolio-type. 这个terms = post_type 是portfolio 类别为portfolio-type我正在尝试获取与当前帖子相同类别的相关帖子<?php global $post; $terms = get_the_terms( $post_id, \'portfolio-type\' ); $terms = $terms[0]->cat_ID; $myposts = get_posts(array(\'num