Adding Custom Post Types To get_calendar() And The Calendar Widget

By default or design, the WordPress function `get_calendar()`[^1] does not handle post types other than `post`. I’ve updated it as the standalone function `ucc_get_calendar()` to allow it to accept a `$post_types` array; the included filter function `ucc_get_calendar_filter()` will allow for seamless integration via `functions.php` without requiring additional editing of Theme templates. (Note that the filter will also apply to the Calendar Widget’s output.)

[php]
/* ucc_get_calendar() :: Extends get_calendar() by including custom post types.
* Derived from get_calendar() code in /wp-includes/general-template.php.
*/

function ucc_get_calendar( $post_types = ” , $initial = true , $echo = true ) {
global $wpdb, $m, $monthnum, $year, $wp_locale, $posts;

if ( empty( $post_types ) || !is_array( $post_types ) ) {
$args = array(
‘public’ => true ,
‘_builtin’ => false
);
$output = ‘names’;
$operator = ‘and’;

$post_types = get_post_types( $args , $output , $operator );
$post_types = array_merge( $post_types , array( ‘post’ ) );
} else {
/* Trust but verify. */
$my_post_types = array();
foreach ( $post_types as $post_type ) {
if ( post_type_exists( $post_type ) )
$my_post_types[] = $post_type;
}
$post_types = $my_post_types;
}
$post_types_key = implode( ” , $post_types );
$post_types = "’" . implode( "’ , ‘" , $post_types ) . "’";

$cache = array();
$key = md5( $m . $monthnum . $year . $post_types_key );
if ( $cache = wp_cache_get( ‘get_calendar’ , ‘calendar’ ) ) {
if ( is_array( $cache ) && isset( $cache[$key] ) ) {
remove_filter( ‘get_calendar’ , ‘ucc_get_calendar_filter’ );
$output = apply_filters( ‘get_calendar’, $cache[$key] );
add_filter( ‘get_calendar’ , ‘ucc_get_calendar_filter’ );
if ( $echo ) {
echo $output;
return;
} else {
return $output;
}
}
}

if ( !is_array( $cache ) )
$cache = array();

// Quick check. If we have no posts at all, abort!
if ( !$posts ) {
$sql = "SELECT 1 as test FROM $wpdb->posts WHERE post_type IN ( $post_types ) AND post_status = ‘publish’ LIMIT 1";
$gotsome = $wpdb->get_var( $sql );
if ( !$gotsome ) {
$cache[$key] = ”;
wp_cache_set( ‘get_calendar’ , $cache , ‘calendar’ );
return;
}
}

if ( isset( $_GET[‘w’] ) )
$w = ” . intval( $_GET[‘w’] );

// week_begins = 0 stands for Sunday
$week_begins = intval( get_option( ‘start_of_week’ ) );

// Let’s figure out when we are
if ( !empty( $monthnum ) && !empty( $year ) ) {
$thismonth = ” . zeroise( intval( $monthnum ) , 2 );
$thisyear = ”.intval($year);
} elseif ( !empty( $w ) ) {
// We need to get the month from MySQL
$thisyear = ” . intval( substr( $m , 0 , 4 ) );
$d = ( ( $w – 1 ) * 7 ) + 6; //it seems MySQL’s weeks disagree with PHP’s
$thismonth = $wpdb->get_var( "SELECT DATE_FORMAT( ( DATE_ADD( ‘${thisyear}0101’ , INTERVAL $d DAY ) ) , ‘%m’ ) " );
} elseif ( !empty( $m ) ) {
$thisyear = ” . intval( substr( $m , 0 , 4 ) );
if ( strlen( $m ) < 6 )
$thismonth = ’01’;
else
$thismonth = ” . zeroise( intval( substr( $m , 4 , 2 ) ) , 2 );
} else {
$thisyear = gmdate( ‘Y’ , current_time( ‘timestamp’ ) );
$thismonth = gmdate( ‘m’ , current_time( ‘timestamp’ ) );
}

$unixmonth = mktime( 0 , 0 , 0 , $thismonth , 1 , $thisyear);

// Get the next and previous month and year with at least one post
$previous = $wpdb->get_row( "SELECT DISTINCT MONTH( post_date ) AS month , YEAR( post_date ) AS year
FROM $wpdb->posts
WHERE post_date < ‘$thisyear-$thismonth-01’
AND post_type IN ( $post_types ) AND post_status = ‘publish’
ORDER BY post_date DESC
LIMIT 1" );
$next = $wpdb->get_row( "SELECT DISTINCT MONTH( post_date ) AS month, YEAR( post_date ) AS year
FROM $wpdb->posts
WHERE post_date > ‘$thisyear-$thismonth-01’
AND MONTH( post_date ) != MONTH( ‘$thisyear-$thismonth-01’ )
AND post_type IN ( $post_types ) AND post_status = ‘publish’
ORDER BY post_date ASC
LIMIT 1" );

/* 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" summary="’ . esc_attr__( ‘Calendar’ ) . ‘">
<caption>’ . sprintf( $calendar_caption , $wp_locale->get_month( $thismonth ) , date( ‘Y’ , $unixmonth ) ) . ‘</caption>
<thead>
<tr>’;

$myweek = array();

for ( $wdcount = 0 ; $wdcount <= 6 ; $wdcount++ ) {
$myweek[] = $wp_locale->get_weekday( ( $wdcount + $week_begins ) % 7 );
}

foreach ( $myweek as $wd ) {
$day_name = ( true == $initial ) ? $wp_locale->get_weekday_initial( $wd ) : $wp_locale->get_weekday_abbrev( $wd );
$wd = esc_attr( $wd );
$calendar_output .= "\n\t\t<th scope=\"col\" title=\"$wd\">$day_name</th>";
}

$calendar_output .= ‘
</tr>
</thead>

<tfoot>
<tr>’;

if ( $previous ) { $calendar_output .= "\n\t\t" . ‘<td colspan="3" id="prev"><a href="’ . get_month_link( $previous->year , $previous->month ) . ‘" title="’ . sprintf( __( ‘View posts for %1$s %2$s’ ) , $wp_locale->get_month( $previous->month ) , date( ‘Y’ , mktime( 0 , 0 , 0 , $previous->month , 1 , $previous->year ) ) ) . ‘">&laquo; ‘ . $wp_locale->get_month_abbrev( $wp_locale->get_month( $previo
us->month ) ) . ‘</a></td>’;
} else {
$calendar_output .= "\n\t\t" . ‘<td colspan="3" id="prev" class="pad">&nbsp;</td>’;
}

$calendar_output .= "\n\t\t" . ‘<td class="pad">&nbsp;</td>’;

if ( $next ) { $calendar_output .= "\n\t\t" . ‘<td colspan="3" id="next"><a href="’ . get_month_link( $next->year , $next->month ) . ‘" title="’ . esc_attr( sprintf( __( ‘View posts for %1$s %2$s’ ) , $wp_locale->get_month( $next->month ) , date( ‘Y’ , mktime( 0 , 0 , 0 , $next->month , 1 , $next->year ) ) ) ) . ‘">’ . $wp_locale->get_month_abbrev( $wp_locale->get_month( $next->month ) ) . ‘ &r
aquo;</a></td>’;
} else {
$calendar_output .= "\n\t\t" . ‘<td colspan="3" id="next" class="pad">&nbsp;</td>’;
}

$calendar_output .= ‘
</tr>
</tfoot>

<tbody>
<tr>’;

// Get days with posts
$dayswithposts = $wpdb->get_results( "SELECT DISTINCT DAYOFMONTH( post_date )
FROM $wpdb->posts WHERE MONTH( post_date ) = ‘$thismonth’
AND YEAR( post_date ) = ‘$thisyear’
AND post_type IN ( $post_types ) AND post_status = ‘publish’
AND post_date < ‘" . current_time( ‘mysql’ ) . ‘\”, ARRAY_N );
if ( $dayswithposts ) {
foreach ( (array) $dayswithposts as $daywith ) {
$daywithpost[] = $daywith[0];
}
} else {
$daywithpost = array();
}

if ( strpos( $_SERVER[‘HTTP_USER_AGENT’] , ‘MSIE’ ) !== false || stripos( $_SERVER[‘HTTP_USER_AGENT’] , ‘camino’ ) !== false || stripos( $_SERVER[‘HTTP_USER_AGENT’] , ‘safari’ ) !== false )
$ak_title_separator = "\n";
else
$ak_title_separator = ‘, ‘;

$ak_titles_for_day = array();
$ak_post_titles = $wpdb->get_results( "SELECT ID, post_title, DAYOFMONTH( post_date ) as dom "
. "FROM $wpdb->posts "
. "WHERE YEAR( post_date ) = ‘$thisyear’ "
. "AND MONTH( post_date ) = ‘$thismonth’ "
. "AND post_date < ‘" . current_time( ‘mysql’ ) . "’ "
. "AND post_type IN ( $post_types ) AND post_status = ‘publish’"
);
if ( $ak_post_titles ) {
foreach ( (array) $ak_post_titles as $ak_post_title ) {

$post_title = esc_attr( apply_filters( ‘the_title’ , $ak_post_title->post_title , $ak_post_title->ID ) );

if ( empty( $ak_titles_for_day[‘day_’ . $ak_post_title->dom] ) )
$ak_titles_for_day[‘day_’.$ak_post_title->dom] = ”;
if ( empty( $ak_titles_for_day["$ak_post_title->dom"] ) ) // first one
$ak_titles_for_day["$ak_post_title->dom"] = $post_title;
else
$ak_titles_for_day["$ak_post_title->dom"] .= $ak_title_separator . $post_title;
}
}

// See how much we should pad in the beginning
$pad = calendar_week_mod( date( ‘w’ , $unixmonth ) – $week_begins );
if ( 0 != $pad )
$calendar_output .= "\n\t\t" . ‘<td colspan="’ . esc_attr( $pad ) . ‘" class="pad">&nbsp;</td>’;

$daysinmonth = intval( date( ‘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 ( $day == gmdate( ‘j’ , current_time( ‘timestamp’ ) ) && $thismonth == gmdate( ‘m’ , current_time( ‘timestamp’ ) ) && $thisyear == gmdate( ‘Y’ , current_time( ‘timestamp’ ) ) )
$calendar_output .= ‘<td id="today">’;
else
$calendar_output .= ‘<td>’;

if ( in_array( $day , $daywithpost ) ) // any posts today?
$calendar_output .= ‘<a href="’ . get_day_link( $thisyear , $thismonth , $day ) . "\" title=\"" . esc_attr( $ak_titles_for_day[$day] ) . "\">$day</a>";
else
$calendar_output .= $day;
$calendar_output .= ‘</td>’;

if ( 6 == calendar_week_mod( date( ‘w’ , mktime( 0 , 0 , 0 , $thismonth , $day , $thisyear ) ) – $week_begins ) )
$newrow = true;
}

$pad = 7 – calendar_week_mod( date( ‘w’ , mktime( 0 , 0 , 0 , $thismonth , $day , $thisyear ) ) – $week_begins );
if ( $pad != 0 && $pad != 7 )
$calendar_output .= "\n\t\t" . ‘<td class="pad" colspan="’ . esc_attr( $pad ) . ‘">&nbsp;</td>’;

$calendar_output .= "\n\t</tr>\n\t</tbody>\n\t</table>";

$cache[$key] = $calendar_output;
wp_cache_set( ‘get_calendar’ , $cache, ‘calendar’ );

remove_filter( ‘get_calendar’ , ‘ucc_get_calendar_filter’ );
$output = apply_filters( ‘get_calendar’, $calendar_output );
add_filter( ‘get_calendar’ , ‘ucc_get_calendar_filter’ );

if ( $echo )
echo $output;
else
return $output;
}

function ucc_get_calendar_filter( $content ) {
$output = ucc_get_calendar( ” , ” , false );
return $output;
}
add_filter( ‘get_calendar’ , ‘ucc_get_calendar_filter’ , 10 , 2 );
[/php]

## References

[^1]: [Function Reference/get calendar](http://codex.wordpress.org/Function_Reference/get_calendar)

31 thoughts on “Adding Custom Post Types To get_calendar() And The Calendar Widget

  1. Wow! You rock! you rock! you ROCK! Just follow the instructions in comments to get the archives pages working! So cool- Thank you

  2. Hi, I am looking to implement this code with the addition of a category filter, I realize this is probably easiest done by checking the post meta during the SQL request but am not sure about the best way of inserting this.

  3. Hey,

    This works great, just want to know if there’s a simple change to make to display the padded days instead of just the spaces.

    So if there were 3 spaces they could display the last 3 days of the previous month and have a link to the post if there was one on the day.

  4. there is something wrong with your syntax highlighting plugin. I see HTML code everywhere in the code. Also special chars like >, <, & and ” are not displayed correctly.

  5. This is great code. I was wondering about the other way round. What if I want to create a exclusive calender automatically for a custom post type gets create as soon as custom post type get created? I want to make this functionality in plugin. Can you give me high level guidance of it? How can I do this?

  6. Hi there!

    I know your code is based on the WordPress calendar of 2010 and we are in 2014 but there must be a way for me to use your function in 2014…

    Link for a page with a calendar [ with the code ‘echo ucc_get_calendar( $post_types = ‘frivillig’, $initial = true , $echo = true); ]

    http://norrebrojazzklub.dev.dystedogjensen.dk/kalenderen/

    but as you see no post is shown (there is a post on the 28th of July…)

    What can I do ?

    Cheers,
    Adam

Comments are closed.