Opened 9 years ago
Last modified 3 years ago
#29319 reviewing enhancement
filter dayswithposts in widget calendar
Reported by: |
|
Owned by: |
|
---|---|---|---|
Milestone: | Future Release | Priority: | normal |
Severity: | normal | Version: | 3.0 |
Component: | Widgets | Keywords: | needs-unit-tests has-patch needs-refresh |
Focuses: | Cc: |
Description
Hello
here is Konrad, WPML developer. We are fighting now with bug related WordPress calendar widget: it always displays all posts, and we want to filter its results regarding to language of post.
Steps to reproduce:
- install WPML
- publish some post in En language July 1st
- translate this post July 2nd to Polish language
- activate calendar widget
Result: calendar will show that there are posts in July 1st and 2nd.
Expected result: when user displays English posts, calendar should display only July 1st. When user switches to Polish language, calndar should display only July 2nd.
We want to fix this in WPML but we need filter inside of get_calendar() function.
Wordpress gets days with posts by this query inside of get_calendar():
$dayswithposts = $wpdb->get_results("SELECT DISTINCT DAYOFMONTH(post_date) FROM $wpdb->posts WHERE post_date >= '{$thisyear}-{$thismonth}-01 00:00:00' AND post_type = 'post' AND post_status = 'publish' AND post_date <= '{$thisyear}-{$thismonth}-{$last_day} 23:59:59'", ARRAY_N);
The result should be able to filter, then WPML will hook here.
I am attaching proposed diff file.
(I see that we can hook into get_calendar filter but this variable has full html output of calendar. This will unefficient to parse this HTML)
Attachments (3)
Change History (35)
#1
@
9 years ago
- Type changed from feature request to enhancement
The filter needs to be documented as per the documentation standards.
As a workaround, you can use the 'query' filter to change that query.
#2
@
9 years ago
Hi Konrad,
I am struggeling with a similar issue in one of my plugins (WP Access Areas).
I would propose to filter the WHERE and JOIN clause similar to getarchives_where
in function wp_get_archives()
. I'll submit a patch instantly.
#5
@
9 years ago
- Keywords needs-patch added
I was about to commit this, then realized: this can use date_query
if we offer a more robust way to select fields as aliases.
If we keep it in WP_Query, the args can be filtered, instead of having to filter SQL fragments.
#6
@
9 years ago
- Milestone changed from 4.1 to Awaiting Review
- Version changed from 4.0 to 3.0
I'm not a fan of introducing a bunch of SQL query filters for the calendar. I'd rather look into switching this over to a date query as wonderboymusic suggested.
#7
@
9 years ago
I just submitted a patch where get_calendar makes use of get_posts rather than custom built SQL. Works fine with my plugin out of the box (@kkarpieszuk and hopefully with WPML as well).
#11
@
7 years ago
regarding https://core.trac.wordpress.org/ticket/40059
Hi
Thanks for the heads up on this. But that ticket is already open for more then 3 years. Is there any progress on this?
Looking forward to your reply on that.
#12
follow-up:
↓ 13
@
7 years ago
Hi, sorry. Notification about this ticket didn't hit my mail inbox.
I see @podpirate prepared working patch. Could this be commtied?
#13
in reply to:
↑ 12
@
7 years ago
Replying to kkarpieszuk:
Hi, sorry. Notification about this ticket didn't hit my mail inbox.
I see @podpirate prepared working patch. Could this be commtied?
Yes the @podpirate solution works fine. I unregistered the default wordpress calendar widget and added my own calling that function with his adjustments. It works just fine and is picking up any pre_get_post action.
It is unbelievable that the wordpress core team did not fix this issue for such a long time. But i see many other issues reported and acknowledged which also do not get fixed for even a longer period of time. I wonder what is withholding them for fixing this.
#14
@
7 years ago
- Keywords has-patch added; needs-patch removed
- Milestone changed from Awaiting Review to 4.8
#15
@
7 years ago
There is one flaw in @podpirate fix code fix. When there are no posts found the calendar does not show al all.
This code should be changed to have at least show the calendar with todays date
<?php if ( ! $gotsome ) { //$cache[ $key ] = ''; //wp_cache_set( 'theme_get_calendar', $cache, 'theme_calendar' ); //return; }
It is the same with the default wp calendar as it comes out of the box.
This ticket was mentioned in Slack in #core by jeffpaul. View the logs.
7 years ago
This ticket was mentioned in Slack in #core by jeffpaul. View the logs.
7 years ago
#19
@
7 years ago
- Milestone changed from 4.8 to 4.8.1
Punting to 4.8.1 per bug scrub earlier this week.
This ticket was mentioned in Slack in #core by jeffpaul. View the logs.
6 years ago
This ticket was mentioned in Slack in #core by jeffpaul. View the logs.
6 years ago
#24
@
4 years ago
Hi
Since in wp.5.4 the calendar widget is made html 5.1 compatible can this also get resolved please?
Thank you
#25
@
4 years ago
- Milestone changed from Future Release to 5.5
Thanks for the heads up @BackuPs !
This should have been worked on during 5.4 alpha development cycle, but I'm milestoning this for 5.5.
It will need some work (patch refresh) to actually land in 5.5, so a new patch with unit tests would be welcome!
#26
@
4 years ago
Here is the worked out solution using get_posts
<?php function get_calendar( $initial = true, $echo = true ) { global $wpdb, $m, $monthnum, $year, $wp_locale, $posts; $key = md5( $m . $monthnum . $year ); $cache = wp_cache_get( 'get_calendar', 'calendar' ); if ( $cache && is_array( $cache ) && isset( $cache[ $key ] ) ) { /** This filter is documented in wp-includes/general-template.php */ $output = apply_filters( 'get_calendar', $cache[ $key ] ); if ( $echo ) { echo $output; return; } return $output; } if ( ! is_array( $cache ) ) { $cache = array(); } // Quick check. If we have no posts at all, abort! if ( ! $posts ) { $gotsome = (bool) get_posts(array( 'fields'=> 'ids', 'suppress_filters'=> false, 'posts_per_page'=> 1, )); if ( ! $gotsome ) { $nothing_found=__( 'No Calendar Posts Found !'); // Make $nothing_found empty to still show the calendar even if there are no posts $nothing_found = apply_filters( 'get_calendar_nothing_found', $nothing_found ); if (!empty($nothing_found)) { $cache[ $key ] = $nothing_found; wp_cache_set( 'get_calendar', $cache, 'calendar' ); if ( $echo ) { echo $nothing_found; return; } else return $nothing_found; } } } if ( isset( $_GET['w'] ) ) { $w = (int) $_GET['w']; } // week_begins = 0 stands for Sunday. $week_begins = (int) get_option( 'start_of_week' ); $ts = current_time( 'timestamp' ); // Let's figure out when we are. if ( ! empty( $monthnum ) && ! empty( $year ) ) { $thismonth = zeroise( intval( $monthnum ), 2 ); $thisyear = (int) $year; } elseif ( ! empty( $w ) ) { // We need to get the month from MySQL. $thisyear = (int) substr( $m, 0, 4 ); //it seems MySQL's weeks disagree with PHP's. $d = ( ( $w - 1 ) * 7 ) + 6; $thismonth = $wpdb->get_var("SELECT DATE_FORMAT((DATE_ADD('{$thisyear}0101', INTERVAL $d DAY) ), '%m')"); } elseif ( ! empty( $m ) ) { $thisyear = (int) substr( $m, 0, 4 ); if ( strlen( $m ) < 6 ) { $thismonth = '01'; } else { $thismonth = zeroise( (int) substr( $m, 4, 2 ), 2 ); } } else { $thisyear = current_time( 'Y' ); $thismonth = current_time( 'm' ); } $unixmonth = mktime( 0, 0 , 0, $thismonth, 1, $thisyear ); $last_day = gmdate( 't', $unixmonth ); $previous_sheet_posts = get_posts( array( 'post_type' => 'post', 'post_status' => 'publish', 'orderby' => 'date', 'order' => 'DESC', 'posts_per_page' => 1, 'suppress_filters' => false, 'date_query'=> array( 'before' => array( 'month' =>$thismonth, 'year'=>$thisyear, ), ), ) ); $next_sheet_posts = get_posts( array( 'post_type' => 'post', 'post_status' => 'publish', 'orderby' => 'date', 'order' => 'ASC', 'posts_per_page' => 1, 'suppress_filters' => false, 'date_query'=> array( 'after' => array( 'month' =>$thismonth, 'year'=>$thisyear, ), ), ) ); /* translators: Calendar caption: 1: month name, 2: 4-digit year */ $calendar_caption = _x('%1$s %2$s', 'calendar caption',''); $calendar_output = '<table id="wp-calendar"> <caption class="calendar-caption">' . sprintf( $calendar_caption, $wp_locale->get_month( $thismonth ), gmdate( 'Y', $unixmonth ) ) . '</caption> <thead class="calendar-head"> <tr class="calendar-days">'; $myweek = array(); for ( $wdcount = 0; $wdcount <= 6; $wdcount++ ) { $myweek[] = $wp_locale->get_weekday( ( $wdcount + $week_begins ) % 7 ); } foreach ( $myweek as $wd ) { $day_name = $initial ? $wp_locale->get_weekday_initial( $wd ) : $wp_locale->get_weekday_abbrev( $wd ); $wd = esc_attr( $wd ); $calendar_output .= "\n\t\t<th class=\"calendar-day\" scope=\"col\" title=\"$wd\">$day_name</th>"; } $calendar_output .= ' </tr> </thead> <tbody class="calendar-body"> <tr>'; $posts_of_month_titles = array(); $posts_of_month = get_posts( array( 'post_type' => 'post', 'post_status' => 'publish', 'orderby' => 'date', 'order' => 'ASC', 'posts_per_page' => -1, 'suppress_filters' => false, 'date_query'=> array( 'month' =>$thismonth, 'year'=>$thisyear, ), ) ); if ( (bool) $posts_of_month ) { foreach ( $posts_of_month as $post ) { $post_date = date_parse($post->post_date); $post_day = $post_date['day']; /** This filter is documented in wp-includes/post-template.php */ $post_title = esc_attr( apply_filters( 'the_title', $post->post_title, $post->ID ) ); if ( ! isset( $posts_of_month_titles[ $post_day ] ) ) $posts_of_month_titles[ $post_day ] = array(); $posts_of_month_titles[ $post_day ][] = $post_title; } } // See how much we should pad in the beginning. $pad = calendar_week_mod( gmdate( 'w', $unixmonth ) - $week_begins ); if ( 0 != $pad ) { $calendar_output .= "\n\t\t".'<td colspan="'. esc_attr( $pad ) .'" class="pad"> </td>'; } $newrow = false; $daysinmonth = (int) gmdate( 't', $unixmonth ); for ( $day = 1; $day <= $daysinmonth; ++$day ) { if ( isset($newrow) && $newrow ) { $calendar_output .= "\n\t</tr>\n\t<tr>\n\t\t"; } $newrow = false; if ( current_time( 'j' ) == $day && current_time( 'm' ) == $thismonth && current_time( 'Y' ) == $thisyear ) { if ( array_key_exists( $day , $posts_of_month_titles ) ) { $calendar_output .= '<td id="today" class="day-has-post">'; } else $calendar_output .= '<td id="today" class="calendar-is-today">'; } else { if ( array_key_exists( $day , $posts_of_month_titles ) ) { $calendar_output .= '<td class="day-has-post">'; } else $calendar_output .= '<td>'; } if ( array_key_exists( $day , $posts_of_month_titles ) ) { // any posts today? $date_format = gmdate( _x( 'F j, Y', 'daily archives date format','' ), strtotime( "{$thisyear}-{$thismonth}-{$day}" ) ); /* translators: Post calendar label. %s: Date */ $label = sprintf( __( 'Posts published on %s','' ), $date_format); $calendar_output .= sprintf( '<a href="%s" aria-label="%s">%s</a>', get_day_link( $thisyear, $thismonth, $day ), esc_attr( $label ), $day ); } else { $calendar_output .= $day; } $calendar_output .= '</td>'; if ( 6 == calendar_week_mod( gmdate( 'w', mktime(0, 0 , 0, $thismonth, $day, $thisyear ) ) - $week_begins ) ) { $newrow = true; } } $pad = 7 - calendar_week_mod( gmdate( 'w', mktime( 0, 0 , 0, $thismonth, $day, $thisyear ) ) - $week_begins ); if ( 0 != $pad && 7 != $pad ) { $calendar_output .= "\n\t\t".'<td class="pad" colspan="'. esc_attr( $pad ) .'"> </td>'; } $calendar_output .= "\n\t</tr>\n\t</tbody>"; $calendar_output .= "\n\t</table>"; $calendar_output .= '<nav aria-label="' . __( 'Previous and next months' ) . '" class="calendar-footer">'; if ( (bool) $previous_sheet_posts ) { $previous = (object) date_parse( $previous_sheet_posts[0]->post_date ); $calendar_output .= "\n\t\t" . '<span id="prev" class="calendar-prev-next-wrap"><a href="' . get_month_link( $previous->year, $previous->month ) . '" class="calendar-prev-next"> « ' . $wp_locale->get_month_abbrev( $wp_locale->get_month( $previous->month ) ) . '</a></span>'; } else { $calendar_output .= "\n\t\t" . '<span id="prev calendar-prev-nex-wrapt"> </span>'; } $calendar_output .= "\n\t\t" . '<span class="pad"> </span>'; if ( (bool) $next_sheet_posts ) { $next = (object) date_parse( $next_sheet_posts[0]->post_date ); $calendar_output .= "\n\t\t" . '<span id="next" class="calendar-prev-next-wrap"><a href="' . get_month_link( $next->year, $next->month ) . '" class="calendar-prev-next">' . $wp_locale->get_month_abbrev( $wp_locale->get_month( $next->month ) ) . ' » </a></span>'; } else { $calendar_output .= "\n\t\t" . '<span id="next" class="pad calendar-prev-next-wrap"> </span>'; } $calendar_output .= ' </nav>'; $cache[ $key ] = $calendar_output; wp_cache_set( 'get_calendar', $cache, 'calendar' ); if ( $echo ) { /** * Filters the HTML calendar output. * * @since 3.0.0 * * @param string $calendar_output HTML output of the calendar. */ echo apply_filters( 'get_calendar', $calendar_output ); return; } /** This filter is documented in wp-includes/general-template.php */ return apply_filters( 'get_calendar', $calendar_output ); }
proposed diff file