WordPress как на ладони
rgbcode is looking for WordPress developers.

WP_Query: Помогите отсортировать записи :)

имеется запрос:

add_action('pre_get_posts', 'exclude_expired_event');
function exclude_expired_event($query) {
	if ( ! is_admin() && $query->is_main_query() ) {

		$current_date = date('Ymd');

		$meta_query = [
			'relation'  => 'OR',
			'first' => [
				'key'  => 'date',
				'type' => 'DATE',
				'value' => $current_date,
				'compare' => '>=',
			],
			'second'       => [
				'key'     => 'date',
				'value' => '',
				'compare' => '=',
			],
		];

		$query->set('meta_query', $meta_query);
		//$query->set('orderby', 'none');  //для add_filter('posts_results',...
	}
	return $query;
}

тут я оставляю записи только со свежей датой относительно текущей даты (ключ date), а также оставляю записи, у которых дата не указана, то есть value для ключа пустое.

так вот, как отсортировать записи, чтобы сперва отображались по дате, самые ближайшие, то есть: 20230102 (2.01.2023) 20230106 (6.01.2023) 20231003 (3.10.2023) - а после них записи без дат (где value пустое значение).

пробовал добавить данный код:

add_filter('posts_results', 'custom_sort_results');

function custom_sort_results($posts) {
	usort($posts, function($a, $b) {
		$dateA = get_post_meta($a->ID, 'date', true);
		$dateB = get_post_meta($b->ID, 'date', true);

		// Проверка на наличие значения 'date' и сравнение дат
		if (empty($dateA) && empty($dateB)) {
			return 0; // Если оба не имеют дату, оставляем без изменений
		} elseif (empty($dateA)) {
			return 1; // Если $a не имеет дату, перемещаем $b вверх
		} elseif (empty($dateB)) {
			return -1; // Если $b не имеет дату, перемещаем $a вверх
		} else {
			return strtotime($dateA) - strtotime($dateB);
		}
	});

	return $posts;
}

но фильтр применяется на постраничную навигацию, то есть сортировка происходит по новой на каждой странице /page/2/ /page/3/

Заметки к вопросу:
mick год назад

фух, решил задачу.

нужно в массив второго запроса добавить еще relation and

полный код:

add_action('pre_get_posts', 'exclude_expired_event');
function exclude_expired_event($query) {
	if ( ! is_admin() && $query->is_main_query() ) {
		$current_date = date('Ymd');
		$meta_query = [
			'relation'  => 'OR',
			'first' => [
				'key'  => 'date',
				'value' => $current_date,
				'compare' => '>=',
			],
			[
				'relation' => 'AND', //gold :)
				[
					'key'     => 'date',
					'value'   => '',
					'compare' => '=',
				]
			]
		];

		$query->set('meta_query', $meta_query);
		$query->set('orderby', array(
			'meta_value_num' => 'ASC',
		));
	}
	return $query;
}
0
mick
год назад 7
  • 0
    Kama9752

    Странный формат даты у тебя, он как число идет... Поэтому тебе нужно указать тип не DATE, а NUMERIC и добавить сортировку по метаполю

    $query->set('orderby', 'meta_value_num');
    
    // или укажи ключ
    
    $query->set('orderby', 'first');
    
    // возможно надо будет еще поиграться с сортировкой по двум полям
    
    $query->set('orderby', [ 'first' => 'DESC', 'second' => 'ASC' ] );
    mick год назад

    изменил NUMERIC type, и пробовал разные варианты orderby. но все равно получаю сортировку
    без даты - с заполненной датой или
    с датой (но не по возрастающей) - без даты

    mick год назад

    удалось отсортировать по дате (возрастание) и далее без даты таким способом

    //.......
    'first' => [
    	'key'  => 'date',
    	// 'value' => $current_date,
    	// 'compare' => '>=', 
    	'compare' => 'EXISTS', 
    ],
    
    //........
    
    $query->set('orderby', array(
    	'meta_value_num' => 'ASC',
    ));

    но просроченные записи по дате относительно текущей даты также отображаются

    Комментировать
На вопросы могут отвечать только зарегистрированные пользователи. Вход . Регистрация