parse_query() orderby date ignoring year
-
Hi,
I would like to do the following except I want to ignore the year. In other words, I want to order by month and then by day since it will eventually result in displaying a list to wish a happy birthday to people during a certain period.
$args = array( 'post_type' => array( 'player'), 'numberposts' => -1, 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'ASC', );I saw some possibilities with meta queries but I have no idea what to set as a meta_key and how to deal with that. I was also wondering if there was no easier possibility than using meta queries.
If I was not clear enough, here is the order I would like :
– Bob, 22/11/1960
– John, 30/11/1957
– Tim, 01/12/1959while my current code gives :
– John, 30/11/1957
– Tim, 01/12/1959
– Bob, 22/11/1960Thanks for your help !
-
Surely your posts are not dated with the person’s birthday. The code you give is referring to the date of the post, not a birthday, but since it is a custom post type, it might be using the post date as the birthday.
To have the database order it for you, the date has to be broken into separate fields, from its standardYYYYMMDDformat. You can do this with MySQL functions in the query, added in thepre_get_postsfilter. Or change how the date is stored for that custom post type, so the month can be accessed separately, easily.Yes my posts are dated with the person’s birthday. About your suggestion, I don’t see how to break the date before calling
get_posts($args). My only thought would have been to usedate_querybut I can’t break the date with that…The orderby options of WP_Query are somewhat limited. You need the order by clause in SQL to be something like
ORDER BY MONTH( post_date ). It’s not possible to do this through the “pre_get_posts” action AFAIK, but you may do so through the “posts_orderby” filter.I can’t see what you mean by doing something like
ORDER BY MONTH( post_date )… However, I found a way to address my problem here and adapted it. It still does not work but I’d like to know if it’s in the right direction.add_filter( 'posts_orderby', 'birthday_sort', 10, 2 ); function birthday_sort( $orderby, $query ) { if ( ! is_admin() && 'post_date' === $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; } add_action( 'pre_get_posts', 'birthday_orderby_meta' ); function birthday_orderby_meta( $query ) { $orderby = $query->get( 'orderby'); if( 'post_date' == $orderby ) { $query->set('meta_key','post_date'); $query->set('orderby','meta_value'); } }Well, that is building an order by criteria from meta data. You just want the month number of the post date as criteria, right?
$orderby = 'MONTH( post_date ) ASC';Don’t also set order criteria in pre_get_posts. It doesn’t do anything if you override with posts_orderby. Unless you want all posts sorted this way, you need to distinguish applicable queries from non-applicable queries. The criteria set in pre_get_posts is not being properly coordinated with the criteria in posts_orderby in any case.
Alright I removed
pre_get_posts. However, I don’t only want the month number as criteria since I want them to be ordered by anniversary. If I have someone who’s anniversary is on 12/03 and another one on 14/03, I want to be sure that the 14/03 appears after the 12/03, which would be random by only looking at the month number.However, I tried your solution as well as an adaptation of it with
DAYinstead ofMONTHbut the order remains unchanged whenget_posts( $args )is called afterwards.add_filter( 'posts_orderby', 'birthday_sort', 10, 2 ); function birthday_sort( $orderby, $args ) { if ( ! is_admin() && 'post_date' === $args->get( 'orderby' ) ) { global $wpdb; $order = ( 'ASC' === strtoupper( $args->get( 'order' ) ) ) ? 'ASC': 'DESC'; $orderby = 'DAY( post_date ) ASC'; } return $orderby; }The
'post_date' === $args->get( 'orderby' )condition is likely failing, so your order by directive is passed over. The usual value for that query var is just “date”, or “” if the default is assumed. It depends on what $args are passed to get_posts().Your callback could return something like
MONTH( post_date ), DAY( post_date ) ASC. It’s probably better to include the table name as well (wp_posts.post_date) , but as long as it’s the same table as in the FROM clause it’s not needed.I verified and it correctly enters in the condition. When I
echothe value of$orderbybefore thereturninbirthday_sort(), it contains what is expected. But these birthdays are displayed in a widget and while debugging, I noticed that it was entering the function (and so executingadd_filter()) in the widget following the “Birthdays” one (myechowere displayed in the following widget)… I don’t know if it can help getting the solutionFWIW, “post_date” isn’t a valid orderby arg in WP_Query. It’s just “date”. It may not matter since we’re changing the order by clause anyway.
You need to move your add_filter() call to where it would execute earlier. A plugin’s main file or theme’s functions.php for example. Be sure it’s only altering widget queries and not other queries (unless you want all posts so ordered).
The problem is that the associated query is created just before the call to
add_filter()in my code. So if I move myadd_filter()in the caller for example, there’s no query to pass imo…I tried another way with a closure (to ensure that the query was the one I wanted) but it was not more successful…
The entire point is to add filters before the query is made. The state of a WP_Query object is immaterial. Adding a filter is just adding functions to a list for later use. When the query’s get_post() method is eventually called, that list of functions are retrieved and executed.
Ok I understand, that was absolutely not how I was seeing it. Thanks for it.
Therefore I tried to add my filter before. I did a
debug_print_backtrace()to see the callers until the query creation and tried to add my filter but unfortunately, no one worked (I did the tries in the calling function of two of the plugin files as well as inclass-wp-widget.phpandwidgets.php)Place your code where it’ll execute for all requests, functions.php or a main plugin file. Instead of checking the “orderby” query var as a condition, maybe try checking if the “post_type” query var is “player”. It should correctly order the page you want ordered that way. If it is applied too broadly, find an additional check that will distinguish between wanted and unwanted ordering.
Just did it (at the end of
functions.phponly because I don’t find a suitable main plugin file). Still the same issue with the function which is well entered and returned but after the players having been displayed in the wrong default order…It had worked for me on my site, but I altered the conditional to fit my situation. Try removing the conditional as a test. The ordering should be applied to all post queries. If that is confirmed then the issue is within your conditional statement.
If you’re still not sure, post the latest version of your code so I can give it a test.
The topic ‘parse_query() orderby date ignoring year’ is closed to new replies.