0

I have a big amount of images in WP, that are not attach to any post. They are grouped in custom taxonomies (ignored in code below). The images get uploaded to WP in random order and the post_date is set to the time the image was taken. Therefor the IDs and the post_date are not in the same order.

I need the ID for the next/prev image in time to browse throw time.

For this reasons and more I thought using the date_query of WP_Query would make sense. I wrote this code:

function get_relative_attachment_id( $this_post_ID, $prev = true ) {

// Set the return var, so it can be overwritten
$attachment_id = null;

// WP_Query arguments
$args = array(
    'post_type'      => 'attachment',
    'post_status'    => 'any',
    'posts_per_page' => '1',
    'orderby'        => 'date',
    'relation'       => 'AND',
    'post__not_in'   => array( $this_post_ID ),
);

if ( $prev ) {
    $args['date_query'] = array(
        array(
            'year'    => intval( get_the_date( 'Y', $this_post_ID ) ),
            'compare' => '<=',
        ),
        array(
            'monthnum' => intval( get_the_date( 'n', $this_post_ID ) ),
            'compare'  => '<=',
        ),
        array(
            'day'     => intval( get_the_date( 'j', $this_post_ID ) ),
            'compare' => '<=',
        ),
        array(
            'hour'    => intval( get_the_date( ' G', $this_post_ID ) ),
            'compare' => '<=',
        ),
        array(
            'minute'  => intval( get_the_date( 'i', $this_post_ID ) ),
            'compare' => '<=',
        ),
        array(
            'second'  => intval( get_the_date( 's', $this_post_ID ) ),
            'compare' => '<=',
        ),
    );
} else {
    $args['order'] = 'ASC';
    $args['date_query'] = array(
        array(
            'year'    => intval( get_the_date( 'Y', $this_post_ID ) ),
            'compare' => '>=',
        ),
        array(
            'monthnum' => intval( get_the_date( 'n', $this_post_ID ) ),
            'compare'  => '>=',
        ),
        array(
            'day'     => intval( get_the_date( 'j', $this_post_ID ) ),
            'compare' => '>=',
        ),
        array(
            'hour'    => intval( get_the_date( ' G', $this_post_ID ) ),
            'compare' => '>=',
        ),
        array(
            'minute'  => intval( get_the_date( 'i', $this_post_ID ) ),
            'compare' => '>=',
        ),
        array(
            'second'  => intval( get_the_date( 's', $this_post_ID ) ),
            'compare' => '>=',
        ),
    );

}

// The Query
$query_next_attachment = new WP_Query( $args );

// The Loop
if ( $query_next_attachment->have_posts() ) {
    while ( $query_next_attachment->have_posts() ) {
        $query_next_attachment->the_post();

        // Put the new attachment id into return var
        $attachment_id = get_the_ID();
    }
} else {
    // make the return var null
    $attachment_id = null;
}

// Restore original Post Data
wp_reset_postdata();

return $attachment_id;
}

When the images are uploaded in chronological order the returns are fine within one day. But when I hit the beginning of the day it starts to skip whole days. Example (* get returned):

[...]
2015-03-11 04:58 *
2015-03-11 03:58 *
2015-03-11 02:58 *
2015-03-11 01:58 *
2015-03-11 00:58 *
----
2015-03-10 23:58
[...]
2015-03-10 01:58
2015-03-10 00:58 *
----
2015-03-09 23:58 
[...]
2015-03-09 01:58
2015-03-09 00:58 *
----
2015-03-08 23:58
[...]

A similar behavior into the other direction.
If the order of date and ID is out of sync the return is even more chaos. I would like to fix the "regular" order first.

Is there a mistake in the date_query? Did I miss to set a parameter?

  • OK, first of all, why are you using multiple calls to the get_the_date() function, when you can just use a single with the whole format? – 2ndkauboy Mar 27 '15 at 18:46
  • 1
    And where do you need it? In a link? Than you might just want to use the get_(previous|next)_post() functions using a hook against pre_get_posts. – 2ndkauboy Mar 27 '15 at 18:49
  • @2ndkauboy no need to filter against pre_get_posts. get_adjacent_post uses the global $post variable. See my answer. – Jan Beck Mar 28 '15 at 0:17
  • @2ndkauboy I use the function to reply to Ajax calls and inside the template. How to add the date in one parameter into the date query? – Drivingralle Mar 30 '15 at 8:54
1

Based on the answer by @jan-becker I build this snippet. This works for me:

/*
 * Get the next/prev image id inside c-tax: my_snapshot_position_ctax
 */
function my_return_relative_attachment_id( $this_post_ID, $prev = true ) {
    global $post;

    // overwrite global $post variable
    $post = get_post( $this_post_ID );

    // filter sql query to work with attachment
    add_filter( 'get_next_post_where', 'my_filter_next_prev_post_where_query', 10, 3 );
    add_filter( 'get_previous_post_where', 'my_filter_next_prev_post_where_query', 10, 3 );

    // Get the new post object
    $adjacent_post = get_adjacent_post( true, array(), $prev, 'my_snapshot_position_ctax' );

    // reset global $post variable
    wp_reset_postdata();

    // remove sql query filter
    remove_filter( 'get_next_post_where', 'my_filter_next_prev_post_where_query', 10 );
    remove_filter( 'get_previous_post_where', 'my_filter_next_prev_post_where_query', 10 );

    // check if returned value is a post
    if ( ! is_object( $adjacent_post ) ) {
        // not a post, return an empty string
        return '';
    }

    // return the post id
    return $adjacent_post->ID;
}

/*
 * Filter to modify sql query because attachments have different post status value
 */
function my_filter_next_prev_post_where_query( $sql_query, $in_same_term, $excluded_terms ) {

    // replace 'publish' with 'inherit' because we work with attachments
    $sql_query = str_replace( 'publish', 'inherit', $sql_query );

    // return the modified query string
    return $sql_query;
}

Maybe moving the filter into the function above makes less code. But this is more readable to me.

0

The get_adjacent_post function already does what you are asking for. Its only downside is that it uses the global $post variable to determine the current post. You would need to overwrite it in a wrapper function like so:

<?php
function get_adjacent_post_by_id( $post_id,  $in_same_term = false, $excluded_terms = '', $previous = true, $taxonomy = 'category' ) {
    global $post;

    $post = get_post( $post_id ); // overwrite global $post variable
    $adjacent_post = get_adjacent_post( $in_same_term, $excluded_terms, $previous, $taxonomy );

    wp_reset_postdata(); // reset global $post variable

    return $adjacent_post;

}

// get previous post of post with ID 1337: 
$previous_post = get_adjacent_post_by_id( 1337 );

// get next post of post with ID 1337: 
$next_post = get_adjacent_post_by_id( 1337, false, '', false );
?>

I kept all the original arguments of the get_adjacent_post function. You may remove or reorder them for how you need them.

0

Try this out

<?php
/**
 * Get next/preview post by post_date
 * 
 * @param int|WP_Post   $post
 * @param boolean   $next_post
 * @return WP_Post|WP_Error
 */
function get_next_prev_post_by_date( $post, $next_post = true ) 
{
    global $wpdb;

    // get current post data
    if ( !is_a( $post, 'WP_Post' ) )
        $post = get_post( $post );

    // build select SQL query
    $query = "SELECT * FROM {$wpdb->posts}";
    $query .= " WHERE post_date ". ( $next_post ? '>' : '<' ) ." %s";
    $query .= " AND ID NOT IN (%d)";
    $query .= " ORDER BY post_date DESC LIMIT 1";

    // run query
    $target_post_row = $wpdb->get_row( $wpdb->prepare( $query, $post->ID, $post->post_date ) );

    // return post object if found
    if ( $target_post_row )
        return new WP_Post( $target_post_row );

    // return error if no match found
    return new WP_Error( 'no_match_found', __( 'No matched post found' ) );
}
  • I prefer to make use of core functions over writing a sql query on my own. Core makes good use of caching and so on. – Drivingralle Mar 30 '15 at 10:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.