WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Получаем несколько соседних записей одним запросом

В WP есть функции, которые получают по одной соседней записи get_previous_post() и get_next_post(). Но они могут получить только один пост. А что делать, когда нужно получить сразу несколько соседних (граничащих, крайних) записей, которые расположены рядом с текущей (вокруг - до и после неё).

1
2
3
4 - текущий пост
5
6
7

Задачу можно решить двумя запросами WP_Query, но мы сделаем это одним запросом!

/**
 * Получает соседние (по дате) записи.
 *
 * @param array $args {
 *     Массив аргументов:
 *
 *     @type int         $limit        По сколько соседних записей нужно получить.
 *     @type bool        $in_same_term Получать записи только из тех же терминов в кторых находится текущая запись.
 *     @type string      $taxonomy     Название таксы. Когда $in_same_term = true, нужно знать с какой таксой работать.
 *     @type int/WP_Post $post         Пост от которого идет отсчет. По умолчанию: текущий.
 *     @type string      $order        Порядок сортировки. При DESC - элемент 'prev' будет содержать новые записи, а 'next' старые. При ASC наоборот...
 *     @type bool        $cache_result Нужно ли кэшировать результат в объектный кэш?
 * }
 *
 * @return array Массив вида array( 'prev'=>array(посты), 'next'=>array(посты) ) или array() если не удалось получить записи или в запросе есть ошибка.
 *
 * @ver 1.0
 */
function get_post_adjacents( $args = array() ) {
	global $wpdb;

	$args = (object) array_merge( array(
		'limit'        => 3,
		'in_same_term' => false,
		'taxonomy'     => 'category',
		'post'         => $GLOBALS['post'],
		'order'        => 'DESC',
		'cache_result' => false,
	), $args );

	$post = is_numeric($args->post) ? get_post($args->post) : $args->post;

	// in_same_term
	$join = $where = '';
	if ( $args->in_same_term ) {
		$join .= " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
		$where .= $wpdb->prepare( "AND tt.taxonomy = %s", $args->taxonomy );

		if ( ! is_object_in_taxonomy( $post->post_type, $args->taxonomy ) )
			return array();

		$term_array = wp_get_object_terms( $post->ID, $args->taxonomy, ['fields'=>'ids'] );

		// Remove any exclusions from the term array to include.
		//$term_array = array_diff( $term_array, (array) $excluded_terms );

		if ( ! $term_array || is_wp_error( $term_array ) )
			return array();

		$term_array = array_map( 'intval', $term_array );

		$where .= " AND tt.term_id IN (" . implode( ',', $term_array ) . ")";
	}

	$query = "
	(
		SELECT p.* FROM $wpdb->posts p $join
		WHERE
			p.post_date   > '". esc_sql($post->post_date). "' AND
			p.post_type   = '". esc_sql($post->post_type). "' AND
			p.post_status = 'publish' $where
		ORDER BY p.post_date ASC
		LIMIT ". intval($args->limit) ."
	)
	UNION
	( SELECT * FROM $wpdb->posts WHERE ID = $post->ID )
	UNION
	(
		SELECT p.* FROM $wpdb->posts p $join
		WHERE
			p.post_date   < '". esc_sql($post->post_date) ."' AND
			p.post_type   = '". esc_sql($post->post_type) ."' AND
			p.post_status = 'publish' $where
		ORDER BY p.post_date DESC
		LIMIT ". intval($args->limit) ."
	)
	ORDER by post_date ".( $args->order === 'DESC' ? 'DESC' : 'ASC' )."
	";

	// пробуем получить кэш...
	if( $args->cache_result ){
		$query_key = 'post_adjacents_' . md5( $query );
		$result = wp_cache_get( $query_key, 'counts' );
		if( false === $result )
			$result = $wpdb->get_results( $query, OBJECT_K );

		// кэшируем запрос...
		if( ! $result )
			$result = array();
		wp_cache_set( $query_key, $result, 'counts' );
	}
	else
		$result = $wpdb->get_results( $query, OBJECT_K );

	// соберем prev/next массивы
	if( $result ){

		$adjacents = array( 'prev'=>[], 'next'=>[] );
		$indx = 'prev';
		foreach( $result as $pst ){
			//unset($pst->post_content); // для дебага

			// текущий пост
			if( $pst->ID == $post->ID ){
				$indx = 'next';
				continue;
			}

			$adjacents[ $indx ][ $pst->ID ] = get_post( $pst ); // создадим объекты WP_Post
		}

	}

	// дебаг
	//$posts_tits = wp_list_pluck( $result, 'post_title' );
	//die( print_r(  $posts_tits  ) );

	return $adjacents;
}

Пример использования

$adjacents = get_post_adjacents( [
	'post' => 10253
] );

print_r( $adjacents );

Получим:

Array(
	[prev] => Array
		(
			[10415] => WP_Post Object
					[ID] => 10415
					[post_author] => 141
					[post_date] => 2018-07-14 17:23:56
					[post_date_gmt] => 2018-07-14 12:23:56
					[post_title] => Contact Form 7 — показ полей по условию
					...

			[10339] => WP_Post Object
					[ID] => 10339
					[post_author] => 141
					[post_date] => 2018-06-19 00:40:03
					[post_date_gmt] => 2018-06-18 19:40:03
					[post_title] => Хуки на странице редактирования записи
					...

			[10276] => WP_Post Object
					[ID] => 10276
					[post_author] => 141
					[post_date] => 2018-06-14 23:35:17
					[post_date_gmt] => 2018-06-14 18:35:17
					[post_title] => Smart Custom Fields - простой плагин метаполей
					...

		)

	[next] => Array
		(
			[10040] => WP_Post Object
					[ID] => 10040
					[post_author] => 1
					[post_date] => 2018-05-21 21:35:48
					[post_date_gmt] => 2018-05-21 16:35:48
					[post_title] => Webcraftic Clearfy: оптимизация, ускорение и защита WordPress
					...

			[10097] => WP_Post Object
					[ID] => 10097
					[post_author] => 1
					[post_date] => 2018-05-21 13:13:21
					[post_date_gmt] => 2018-05-21 08:13:21
					[post_title] => Рейтинг лучших мессенджеров 2018
					...

			[10084] => WP_Post Object
					[ID] => 10084
					[post_author] => 1
					[post_date] => 2018-05-17 13:53:47
					[post_date_gmt] => 2018-05-17 08:53:47
					[post_title] => Как работают уведомления (пинги, трэкбэки) в WordPress
					...
		)
)

В результате, как мы видим, у нас появилась возможность получить несколько предыдущих и несколько следующих постов.

3 комментария
    Войти