WP has functions that receive one adjacent

entry get_previous_post() and get_next_post() each. But they can only get one post. And what to do when you need to get several adjacent (bordering, extreme) records that are located next to the current one (around - before and after it).

1
2
3
4 - current post
5 6 7

The task can be solved with two requests WP_Query, but we will do it with one request!

/**
 * Gets adjacent (by date) entries.
 *
 * @param array $args {
 * Array of arguments:
 *
 * @type int $limit How many adjacent records to get.
 * @type bool $in_same_term Get records only from the same terms as the current record.
 * @type string $taxonomy The name of the tax. When $in_same_term = true, you need to know which rate to work with.
 * @type int/WP_Post $post Post from which to count. Default: current.
 * @type string $order Sort order. With DESC, the 'prev' element will contain the new entries, and the 'next' element will contain the old ones. With ASC it's the other way around...
 * @type bool $cache_result Should the result be cached in the object cache?
 *}
 *
 * @return array An array of the form array( 'prev'=>array(posts), 'next'=>array(posts) ) or array() if the records could not be retrieved or there was an error in the request.
 *
 *@ver1.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' )."
";

// try to get the cache...
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 );

// cache request...
if( ! $result )
$result = array();
wp_cache_set( $query_key, $result, 'counts' );
}
else
$result = $wpdb->get_results( $query, OBJECT_K );

// collect prev/next arrays
if( $result ){

$adjacents = array( 'prev'=>[], 'next'=>[] );
$indx = 'prev';
foreach( $result as $pst ){
//unset($pst->post_content); // for debug

// current post
if( $pst->ID == $post->ID ){
$indx = 'next';
continue;
}

$adjacents[ $indx ][ $pst->ID ] = get_post( $pst ); // create WP_Post objects
}

}

// debug
//$posts_tits = wp_list_pluck( $result, 'post_title' );
//die( print_r( $posts_tits ) );

return $adjacents;
}

Example of use

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

print_r( $adjacents );

Get:

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 - show fields by condition
...

[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] => Hooks on the post edit page
...

[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 - simple meta fields plugin
...

)

[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: Optimizing, Speeding Up and Protecting 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] => Rating of the best instant messengers 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] => How notifications (pings, trackbacks) work in WordPress
...
)
)