Сортировка записей по таксономии и мета-значению в WordPress

7 мар. 2014 г., 17:50:18
Просмотры: 13.6K
Голосов: 3

Возможно сортировать записи по meta_value.

Возможно сортировать записи по нескольким значениям.

И благодаря коду ниже можно сортировать по таксономии.

Но как изменить код ниже, чтобы сортировать одновременно по таксономии И meta_value?

Добавлено в functions.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 );

Добавлено в index.php

<?php $args = array(
'post_type' => 'custom_post_type',
'posts_per_page' => -1,
'meta_key' => '_EventStartDate',
'orderby' => 'taxonomy_cat',
'order' => asc
);
$the_query = new WP_Query( $args );

if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query-    >the_post(); ?>

и т.д.

Такой вариант не работает

'orderby' => 'taxonomy_cat meta_value',
0
Все ответы на вопрос 1
0

В вашем коде есть

if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby'] 

что делает ваш код нерабочим при множественных полях сортировки, потому что если вы укажете

'orderby' => 'taxonomy_cat meta_value'

то условие $taxonomy == $wp_query->query['orderby'] никогда не будет истинным.

Кроме того, я считаю, что перебор всех таксономий только для поиска таксономии для сортировки неэффективен и не очень надежен.

Поэтому я немного изменил ваш код: когда вы хотите сортировать по таксономии, аргумент должен выглядеть примерно так:

'orderby' => 'taxonomy.taxonomy_cat'

Благодаря префиксу 'taxonomy.' легко распознать таксономию, и нет необходимости перебирать все таксономии.

После этого WordPress позволяет передавать только один аргумент в параметре 'order', поэтому при передаче нескольких аргументов в 'orderby' результат может быть неожиданным.

Поэтому я изменил ваш код, добавив дополнительный аргумент: 'ordertax'. Конечно, он необязателен, поэтому если вы его не передадите, будет использован аргумент 'order'. Он также игнорируется, если 'orderby' не содержит аргументов таксономии. Если вы используете несколько аргументов 'orderby' без передачи 'ordertax', все аргументы сортируются на основе параметра 'order' (или по умолчанию 'DESC'), поэтому использование

'orderby' => 'taxonomy.taxonomy_cat meta_value',
'order' => 'ASC'

означает "ORDERBY taxonomy_cat ASC, meta_value ASC", а использование

'orderby' => 'taxonomy.taxonomy_cat meta_value',
'ordertax' => 'DESC'
'order' => 'ASC'

означает "ORDERBY taxonomy_cat DESC, meta_value ASC".

Теперь сам код:

function orderby_tax_clauses( $clauses, $wp_query ) {
  $orderby_arg = $wp_query->get('orderby');
  if ( ! empty( $orderby_arg ) && substr_count( $orderby_arg, 'taxonomy.' ) ) {
    global $wpdb;
    $bytax = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC)";
    $array = explode( ' ', $orderby_arg ); 
    if ( ! isset( $array[1] ) ) {
      $array = array( $bytax, "{$wpdb->posts}.post_date" );
      $taxonomy = str_replace( 'taxonomy.', '', $orderby_arg );
    } else {
      foreach ( $array as $i => $t ) {
        if ( substr_count( $t, 'taxonomy.' ) )  {
          $taxonomy = str_replace( 'taxonomy.', '', $t );
          $array[$i] = $bytax;
        } elseif ( $t === 'meta_value' || $t === 'meta_value_num' ) {
          $cast = ( $t === 'meta_value_num' ) ? 'SIGNED' : 'CHAR';
          $array[$i] = "CAST( {$wpdb->postmeta}.meta_value AS {$cast} )";
        } else {
          $array[$i] = "{$wpdb->posts}.{$t}";
        }
      }
    }
    $order = strtoupper( $wp_query->get('order') ) === 'ASC' ? ' ASC' : ' DESC';
    $ot = strtoupper( $wp_query->get('ordertax') );
    $ordertax = $ot === 'DESC' || $ot === 'ASC' ? " $ot" : " $order";
    $clauses['orderby'] = implode(', ',
      array_map( function($a) use ( $ordertax, $order ) {
        return ( strpos($a, 'GROUP_CONCAT') === 0 ) ? $a . $ordertax : $a . $order;
      }, $array )
    );
    $clauses['join'] .= " LEFT OUTER JOIN {$wpdb->term_relationships} ";
    $clauses['join'] .= "ON {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id";
    $clauses['join'] .= " LEFT OUTER JOIN {$wpdb->term_taxonomy} ";
    $clauses['join'] .= "USING (term_taxonomy_id)";
    $clauses['join'] .= " LEFT OUTER JOIN {$wpdb->terms} USING (term_id)";
    $clauses['groupby'] = "object_id";
    $clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
  }
  return $clauses;
}

Используйте его так:

$args = array(
  'post_type'      => 'custom_post_type',
  'posts_per_page' => -1,
  'meta_key'       => '_EventStartDate',
  'orderby'        => 'taxonomy.taxonomy_cat meta_value',
  'ordertax'       => 'ASC',
  'order'          => 'DESC'
);

add_filter( 'posts_clauses', 'orderby_tax_clauses', 10, 2 );
$the_query = new WP_Query( $args );
remove_filter( 'posts_clauses', 'orderby_tax_clauses', 10, 2 );

Обратите внимание, что использование моего кода (как и вашего) с WP_Query, содержащим запрос таксономии, может привести к проблемам... по этой причине важно удалять фильтр после его использования.

7 мар. 2014 г. 23:51:32