Question

I defined a custom field named crimedate using standard date format Y-m-d. I defined the filters to make ordering by this date work in the post list of the backend, which works fine.

Now I need the possibility to show posts ordered by anniversary, using only day and month of the crimedate, but I don't know how to do that:

function crimes_columns($columns) {
    $columns['crimedate'] = 'Crime date';
    $columns['crimeanniversary'] = 'Crime anniversary';
    return $columns;
}
add_filter('manage_posts_columns', 'crimes_columns');

function crimes_show_columns($name, $post_id) {
    switch ($name) {
        case 'crimedate':
            // show whole date
            echo get_post_meta($post_id, "crimedate", true);
            break;
        case 'crimeanniversary':
            // show only anniversary in format dd/mm
            $date = get_post_meta($post_id, "crimedate", false);
            echo substr($date,6)."/".substr($date,4,2);
            break;
    }
    return $row_output;
}
add_action('manage_posts_custom_column',  'crimes_show_columns');

add_filter( 'manage_edit-post_sortable_columns', 'crimes_add_custom_column_make_sortable' );
function crimes_add_custom_column_make_sortable( $columns ) {
    $columns['crimedate'] = 'crimedate';
    $columns['crimeanniversary'] = 'Crime anniversary';
    return $columns;
}

add_action( 'pre_get_posts', 'crimes_orderby_meta' );
function crimes_orderby_meta( $query ) {
    if(!is_admin())
        return;
 
    $orderby = $query->get( 'orderby');
 
    if( 'crimedate' == $orderby ) {
        $query->set('meta_key','crimedate');
        $query->set('orderby','meta_value');
    }
    else if( 'crimeanniversary' == $orderby ) {
        // ¿¿¿ what to do here ???
    }
}

Is it possible to sort dates only by day and month ignoring the year in hook pre_get_posts? Or do I have to save days and month in two separte fields to make that work?

Was it helpful?

Solution

No, it's not possible by using pre_get_posts alone. But you don't have to use separate fields for the date.

WP_Query, although doesn't provide a simple query arg that would sort the posts by month and day only, you can use the posts_orderby filter hook to modify the ORDER BY clause (i.e. ORDER BY <the part here>) for sorting the posts.

Working Example

  1. In the pre_get_posts hook, set the meta_key to crimedate:

    // In crimes_orderby_meta():
    
    elseif ( 'crimeanniversary' == $orderby ) {
        $query->set( 'meta_key', 'crimedate' );
    }
    
  2. Then on the posts_orderby hook, you can use the STR_TO_DATE() function in MySQL to sort the posts by the month and day of the meta value:

    Note that I purposely used a static leap year, which means 29/02 (Feb 29th) always comes after 28/02 (Feb 28th), when the sort order is ASC.

    add_filter( 'posts_orderby', 'posts_orderby_crimeanniversary', 10, 2 );
    function posts_orderby_crimeanniversary( $orderby, $query ) {
        if ( is_admin() && 'crimeanniversary' === $query->get( 'orderby' ) ) {
            global $wpdb;
    
            $order = ( 'ASC' === strtoupper( $query->get( 'order' ) ) ) ? 'ASC': 'DESC';
    
            // This means, we still sort by the date, but we "recreate" the date using
            // the year 2020 (or any leap year), and month and day from the meta value.
            $orderby = "STR_TO_DATE( CONCAT( '2020-',
                MONTH( {$wpdb->postmeta}.meta_value ), '-',
                DAY( {$wpdb->postmeta}.meta_value
            ) ), '%Y-%m-%d' ) $order";
        }
    
        return $orderby;
    }
    

I hope that helps, and please correct these issues in your code:

  • In crimes_add_custom_column_make_sortable():

    $columns['crimeanniversary'] = 'crimeanniversary';  // like this
    $columns['crimeanniversary'] = 'Crime anniversary'; // not this
    
  • In crimes_show_columns():

    get_post_meta($post_id, "crimedate", true)  // like this
    get_post_meta($post_id, "crimedate", false) // not this
    

    And just remove that line with $row_output — which is not defined.

  • And don't forget the fourth parameter here:

    add_action('manage_posts_custom_column', 'crimes_show_columns', 10, 2); // like this
    add_action('manage_posts_custom_column', 'crimes_show_columns');        // not this!
    
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top