This is a work in progress. Displays a small calendar with dates specified using a date/time field in Advanced Custom Fields on a Custom Post Type. Currently assumes a posts to posts connection between two CPTs projects and activities.
The PHP
jlv-cpt-calendar.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php /* Plugin Name: JLV CPT Calendar Plugin URI: http://dev.abuyasmeen.com/ Description: CPT Calendar with ACF Version: 0.3 Author: Jeremy Varnham Author URI: https://abuyasmeen.com/ */ define( 'JLV_CPT_CAL_VERSION', '3' ); define( 'JLV_CPT_CAL_URL', plugin_dir_url( __FILE__ ) ); define( 'JLV_CPT_CAL_DIR', dirname( __FILE__ ) . '/' ); require JLV_CPT_CAL_DIR . 'jlv-cpt-calendar-scriptinit.php'; require JLV_CPT_CAL_DIR . 'jlv-cpt-calendar-loader.php'; require JLV_CPT_CAL_DIR . 'jlv-cpt-calendar-widget.php'; ?> |
jlv-cpt-calendar-loader.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | <?php /* */ class jlv_cpt_calendar { /** * Define static values for testing purposes. * Will be replaced with Wordpress options and user input. */ public $strPostType = 'project'; public $strStartTimeACF = 'start_time'; public $intSelectedYear = 0; public $intSelectedMonth = 0; public $intFirstDayOfWeek = 0; /** * Define blank arays to be built up with functions below. */ private $_WeekDays = array(); private $_Structure = array(); private $_TheDays = array(); /** * Defines the days of the week starting with Sunday in English and Arabic. * * @since 0.2 */ private function define_week_days() { $this->_WeekDays['en-US'] = array('Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'); $this->_WeekDays['ar'] = array('الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'); } /** * Extracts various numbers and strings from the given date. * * @since 0.1 */ private function define_day_codes() { $firstDayOfMonthTimeCode = (int) mktime(0, 0, 0, $this->intSelectedMonth, 1, $this->intSelectedYear); $this->_TheDays['Total Days In Month'] = (int) date('t', $firstDayOfMonthTimeCode); $this->_TheDays['Weekday For First Day Of Month'] = (int) date('w', $firstDayOfMonthTimeCode); $this->_TheDays['The Month Name'] = (string) date('F', $firstDayOfMonthTimeCode); $this->_TheDays['Current Date Int'] = (int) date("Ymd",mktime(0,0,0,date("m"),date("d"),date("Y"))); } /** * Defines the HTML parts in one place for more readable output function. * * @since 0.2 */ private function define_html_structure() { $this->_Structure['Start Cal Div'] = '<div class="cal">'; $this->_Structure['End Cal Div'] = '</div>'; $this->_Structure['Start Table'] = '<table class="cal-table" style="background: none;">'; $this->_Structure['End Table'] = '</table>'; $this->_Structure['Start Table Header'] = '<thead><tr>'; $this->_Structure['End Table Header'] = '</tr></thead>'; $this->_Structure['Start Table Caption'] = '<caption class="cal-caption">'; $this->_Structure['End Table Caption'] = '</caption>'; $this->_Structure['Start Table Body'] = '<tbody class="cal-body"><tr>'; $this->_Structure['End Table Body'] = '</tbody>'; $this->_Structure['Start Table Column'] = '<td>'; $this->_Structure['End Table Column'] = '</td>'; $this->_Structure['End Table Row'] = '</tr>'; } /** * Converts slashes to dashes for compatibility with already entered dates * * @since 0.2 * * @param string $the_date the date saved by ACF date/time picker * @return int $the_date_int the date as Ymd */ private function convert_the_date($the_date) { if (strpos($the_date,'/') !== false) { // if it's the old format (dd/mm/yy) $the_date_bits = explode('/',$the_date); $the_date = $the_date_bits[0].'-'.$the_date_bits[1].'-'.$the_date_bits[2]; $the_date_int = (int) date('Ymd', strtotime($the_date)); // Strip time, strip dashes, make integer } else { $the_date_int = (int) date('Ymd', strtotime($the_date)); // Strip time, strip dashes, make integer } return $the_date_int; } /** * Performs the Wordpress query. * * @since 0.1 * * @return object */ private function do_the_query() { wp_reset_postdata(); global $post; $args = array( 'post_type' => $this->strPostType, 'meta_key' => $this->strStartTimeACF, 'orderby' => 'meta_value', 'order' => 'ASC', 'connected_type' => 'activity_to_project', 'connected_items'=>$post->ID ); $loop = new WP_Query( $args ); return $loop; } /** * Loops through days of week starting with defined starting day. * Wraps each day name in a TH * * @since 0.1 * * @return string $html */ private function get_the_table_header() { $html = ''; for ($counter = 0, $i = $this->intFirstDayOfWeek; 7 > $counter; $counter++, $i++) // Loop 7x to output weekday names { $html .= '<th>' . $this->_WeekDays[get_bloginfo('language')][$i] . '</th>'; if (6 == $i) { $i = -1; } // If counter reached to 6, set it to -1 } return $html; } /** * Builds the table caption with pagination / month name and year. * * @since 0.1 * * @return string $html */ private function get_the_table_caption() { $html = ''; //$html .= '<a href="#" class="prev">«</a>'; //$html .= '<a href="#" class="next">»</a>'; $html .= $this->_TheDays['The Month Name'] . ' ' . $this->intSelectedYear; return $html; } /** * If new week has started then close current table row and start new one * * @since 0.1 * * @return string $html */ private function start_new_row($day) { $html = ''; $current_day_of_week = date('w', mktime(0, 0, 0, $this->intSelectedMonth, $day, $this->intSelectedYear)); if (1 < $day && $this->intFirstDayOfWeek == $current_day_of_week ) { $html .= '</tr><tr>'; } return $html; } /** * Checks if 'first day of week' is not equal to weekday for first day of month * then outputs empty TDs * * @since 0.1 * * @return string $html */ private function get_the_empty_days_before() { $html = ''; if ($this->intFirstDayOfWeek != $this->_TheDays['Weekday For First Day Of Month']) { $totalEmptyDays = ($this->_TheDays['Weekday For First Day Of Month'] - $this->intFirstDayOfWeek); // Calculate total empty days if ($this->intFirstDayOfWeek > $this->_TheDays['Weekday For First Day Of Month']) // If 1st day of week > weekday for 1st day of month, +7 days to empty days { $totalEmptyDays += 7; } for ($i = 0; $i < $totalEmptyDays; $i++) // Empty TDs if 1st day of month doesn't start on '1st day of week' { $html .= '<td class="cal-off"> </td>'; } } return $html; } /** * Checks if 'last day of week' is not equal to weekday for last day of month * then outputs empty TDs * * @since 0.1 * * @return string $html */ private function get_the_empty_days_after() { $weekdayForLastDayOfMonth = date('w', mktime(0, 0, 0, $this->intSelectedMonth, $this->_TheDays['Total Days In Month'], $this->intSelectedYear)); $totalEmptyDays = ($this->intFirstDayOfWeek - $weekdayForLastDayOfMonth - 1); // Calculate total empty days if ($this->intFirstDayOfWeek <= $weekdayForLastDayOfMonth) { $totalEmptyDays += 7; } $html = ''; for ($i = 0; $i < $totalEmptyDays; $i++) { $html .= '<td class="cal-off"> </td>'; } return $html; } /** * Prints the day numbers into each table cell * * @since 0.1 * * @return string $html */ private function write_day_numbers($day) { $html = ''; $html .= '<a class="day">' . $day . '</a>'; return $html; } /** * If any post(s) for current day in current month/year then display them * * @since 0.1 * * @return string $html */ private function get_day_activities($loop, $day) { $html = ''; $numberofcolumns = 1; $count = $numberofcolumns; while ($loop->have_posts()) : $loop->the_post(); $start_date = get_field($this->strStartTimeACF); $start_date_int = $this->convert_the_date($start_date); $current_date_int = $this->_TheDays['Current Date Int']; $cal_date = $this->intSelectedYear.'-'.$this->intSelectedMonth.'-'.$day; $cal_date_int = $this->convert_the_date($cal_date); if ($cal_date_int == $start_date_int) { $html .= '<a href="' . get_permalink() . '" class="hasevent">'; $html .= '<p style="padding: 0; margin: 0; ">x</p>'; $html .= '</a>'; } elseif ($cal_date_int == $current_date_int) { $html .= '<a name="istoday" class="istoday"></a>'; } endwhile; return $html; } /** * Outputs HTML before the table. */ private function do_before_the_table() { $html = $this->_Structure['Start Cal Div']; $html .= $this->_Structure['Start Table']; return $html; } /** * Outputs the Table Header. */ private function do_the_table_header() { $html = $this->_Structure['Start Table Header']; $html .= $this->get_the_table_header(); $html .= $this->_Structure['End Table Header']; return $html; } /** * Outputs the Table Caption. */ private function do_the_table_caption() { $html = $this->_Structure['Start Table Caption']; $html .= $this->get_the_table_caption(); $html .= $this->_Structure['End Table Caption']; return $html; } /** * Outputs the Table Body. */ private function do_the_table_body($loop) { $html = $this->_Structure['Start Table Body']; $html .= $this->get_the_empty_days_before(); for ($day = 1; $day <= $this->_TheDays['Total Days In Month']; $day++) { $html .= $this->start_new_row($day); $html .= $this->_Structure['Start Table Column']; $html .= $this->write_day_numbers($day); $html .= $this->get_day_activities($loop,$day); $html .= $this->_Structure['End Table Column']; } $html .= $this->get_the_empty_days_after(); return $html; } /** * Outputs HTML after the table. */ private function do_after_the_table() { $html = $this->_Structure['End Table Row']; $html .= $this->_Structure['End Table Body']; $html .= $this->_Structure['End Table']; $html .= $this->_Structure['End Cal Div']; return $html; } /** * Outputs the HTML. */ private function make_the_output() { $this->define_week_days(); $this->define_day_codes(); $this->define_html_structure(); $loop = $this->do_the_query(); if ($loop->have_posts()) { $html = $this->do_before_the_table(); $html .= $this->do_the_table_header(); $html .= $this->do_the_table_caption(); $html .= $this->do_the_table_body($loop); $html .= $this->do_after_the_table(); } return $html; } public function set_the_date($month,$year) { $this->intSelectedYear = (int) $year; $this->intSelectedMonth = (int) $month; } public function printcalendar($month,$year) { $this->intSelectedYear = (int) $year; $this->intSelectedMonth = (int) $month; echo $this->make_the_output(); } } // end class ?> |
jlv-cpt-calendar-scriptinit.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php /* */ class styleloader { /** * Register and enqueue style sheet. * * @since 0.1 */ public function register_plugin_styles() { wp_register_style( 'jlv_cpt_calendar_style', JLV_CPT_CAL_URL . 'jlv-cpt-calendar.css' ); wp_enqueue_style( 'jlv_cpt_calendar_style' ); } /** * Register and enqueue scripts. * * @since 0.1 */ public function register_plugin_scripts() { wp_register_script( 'jlv_cpt_calendar_script', JLV_CPT_CAL_URL . 'jlv-cpt-calendar.js', array( 'jquery' ) ); wp_enqueue_script( 'jlv_cpt_calendar_script' ); } /** * Add style and script actions. * * @since 0.1 */ private function add_plugin_actions() { add_action( 'wp_enqueue_scripts', array($this, 'register_plugin_styles') ); add_action( 'wp_enqueue_scripts', array($this, 'register_plugin_scripts') ); } } $loadstyles = new styleloader(); $loadstyles->register_plugin_styles(); $loadstyles->register_plugin_scripts(); ?> |
jlv-cpt-calendar-widget.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | <?php /* * @since 0.3 */ class jlv_cpt_acf_cal_widget extends WP_Widget { // constructor function jlv_cpt_acf_cal_widget() { parent::WP_Widget(false, $name = __('Activity Calendar', 'jlv_cpt_acf_widget') ); } // widget form creation function form($instance) { // Check values if ( $instance) { $year = (int) esc_attr($instance['year']); } else { $year = 2013; } if ( $instance) { $month = (int) esc_attr($instance['month']); } else { $month = 1; } ?> <p> <label for="<?php echo $this->get_field_id('year'); ?>"><?php _e('Year:', 'jlv_cpt_acf_widget'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('year'); ?>" name="<?php echo $this->get_field_name('year'); ?>" type="text" value="<?php echo $year; ?>" /> <label for="<?php echo $this->get_field_id('month'); ?>"><?php _e('Month', 'jlv_cpt_acf_widget'); ?></label> <select name="<?php echo $this->get_field_name('month'); ?>" id="<?php echo $this->get_field_id('month'); ?>" class="widefat"> <?php $options = array('Jan' => 1, 'Feb'=> 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12); foreach ($options as $key => $value) { echo '<option value="' . $value . '" id="' . $key . '"', $month == $value ? ' selected="selected"' : '', '>', $key, '</option>'; } ?> </select> </p> <?php } // update widget function update($new_instance, $old_instance) { $instance = $old_instance; // Fields $instance['year'] = strip_tags($new_instance['year']); $instance['month'] = strip_tags($new_instance['month']); return $instance; } // display widget function widget($args, $instance) { //include_once('google-apps-link.php'); extract( $args ); // these are the widget options $year = $instance['year']; $month = $instance['month']; echo $before_widget; // Display the widget $jlv_cpt_calendar = new jlv_cpt_calendar(); $jlv_cpt_calendar->printcalendar($month,$year); echo $after_widget; } } // register widget add_action('widgets_init', create_function('', 'return register_widget("jlv_cpt_acf_cal_widget");')); ?> |
The JS
1 2 3 4 5 6 7 8 9 | jQuery(document).ready(function(){ jQuery("a.hasevent").parent().addClass("cal-check"); jQuery("a.hasevent").parent().children(':first-child').addClass("haschildevent"); jQuery("a.istoday").parent().addClass("cal-today"); jQuery('td.cal-check').click(function(){ var thisHref = jQuery(this).find('a.hasevent').attr('href'); location.href = thisHref; }); }); |
The CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | .cal div, .cal span, .cal p, .cal a, .cal table, .cal tbody, .cal tfoot, .cal thead, .cal tr, .cal th, .cal td { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; line-height: 1; font: 13px/20px 'Lucida Grande', Tahoma, Verdana, sans-serif; } .cal table { border-collapse: collapse; border-spacing: 0; } .cal { position: relative; padding: 4px; font-weight: bold; background: #bebfc0; background: rgba(0, 0, 0, 0.1); border-radius: 5px; display: inline-block; vertical-align: baseline; zoom: 1; *display: inline; *vertical-align: auto; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2), 0 1px rgba(255, 255, 255, 0.4); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2), 0 1px rgba(255, 255, 255, 0.4); } .cal:before { content: ''; position: absolute; bottom: 3px; left: 4px; right: 4px; height: 6px; background: #d9d9d9; border: 1px solid #909090; border-radius: 4px; -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } .cal a { text-decoration: none; } .cal tr:first-child td { border-top: 0; } .cal td:first-child { border-left: 0; } .cal tr:first-child a { border-top: 0; margin-top: 0; } .cal tr:last-child a { border-bottom: 0; margin-bottom: 0; } .cal td:first-child a { border-left: 0; margin-left: 0; } .cal td:last-child a { border-right: 0; margin-right: 0; } .cal tr:last-child td:first-child a { border-radius: 0 0 0 3px; } .cal tr:last-child td:last-child a { border-radius: 0 0 3px 0; } .cal-table { position: relative; margin: 0 0 1px; border-collapse: separate; border-left: 1px solid #979797; border-right: 1px solid #979797; border-bottom: 1px solid #bbb; border-radius: 0 0 3px 3px; -webkit-box-shadow: 1px 0 rgba(0, 0, 0, 0.1), -1px 0 rgba(0, 0, 0, 0.1); box-shadow: 1px 0 rgba(0, 0, 0, 0.1), -1px 0 rgba(0, 0, 0, 0.1); } .cal-caption { width: 100%; padding-bottom: 1px; line-height: 32px; color: white; text-align: center; text-shadow: 0 -1px rgba(0, 0, 0, 0.3); background: #155382; border-radius: 3px 3px 0 0; background-image: -webkit-linear-gradient(top, #358ab4, #155382 75%, #0e4273); background-image: -moz-linear-gradient(top, #358ab4, #155382 75%, #0e4273); background-image: -o-linear-gradient(top, #358ab4, #155382 75%, #0e4273); background-image: linear-gradient(to bottom, #358ab4, #155382 75%, #0e4273); -webkit-box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2), inset 0 1px rgba(0, 0, 0, 0.1), inset 0 2px rgba(255, 255, 255, 0.25), 0 1px 3px rgba(0, 0, 0, 0.4); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2), inset 0 1px rgba(0, 0, 0, 0.1), inset 0 2px rgba(255, 255, 255, 0.25), 0 1px 3px rgba(0, 0, 0, 0.4); } .cal-caption a { line-height: 30px; padding: 0 10px; font-size: 20px; font-weight: normal; color: white; } .cal-caption .prev { float: left; } .cal-caption .next { float: right; } .cal-body td { width: 45px; font-size: 11px; border-top: 1px solid #eaeaea; border-left: 1px solid #eaeaea; } .cal-body a.day { display: block; position: relative; line-height: 28px; color: #555; text-align: center; background: white; cursor: default; } .cal-body a:hover { background: #fafafa; } .cal-body a.hasevent { float: left; position: relative; display: none; } .cal-off { background-color: #eee; } .cal-off a { color: #ccc; font-weight: normal; } .cal-today a.day { color: black; background: #f5f5f5; background-image: -webkit-linear-gradient(top, whitesmoke, white 70%); background-image: -moz-linear-gradient(top, whitesmoke, white 70%); background-image: -o-linear-gradient(top, whitesmoke, white 70%); background-image: linear-gradient(to bottom, whitesmoke, white 70%); } .cal-selected a, .cal-body a:active { margin: -1px; color: #b2494d; background: #fff5f6; border: 1px solid #e7d4d4; } .cal-check a.event, .haschildevent { color: #f79901; overflow: hidden; cursor: pointer!important; cursor: hand!important; } .cal-check a.event:before, .haschildevent:before { content: ''; position: absolute; top: -6px; right: -6px; width: 12px; height: 12px; background: #ffb83b; background-image: -webkit-linear-gradient(top, #ffb83b, #ff6c00); background-image: -moz-linear-gradient(top, #ffb83b, #ff6c00); background-image: -o-linear-gradient(top, #ffb83b, #ff6c00); background-image: linear-gradient(to bottom, #ffb83b, #ff6c00); -webkit-transform: rotate(-45deg); -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); } .lt-ie8 .cal-table { *border-collapse: collapse; } .lt-ie8 .cal-body a { zoom: 1; } |
The CSS is adapted from Mini Calendar
Display the calendar by placing the widget in a sidebar, where you can select the month and year, or directly in a template using:
<?php $jlv_cpt_calendar->printcalendar(12,2013); ?>
where 12 is the month and 2013 is the year
1 Comment
Add Yours →For anyone still looking for a soluion, i have created a calendar plugin that works with custom post type and uses ACF custom_date to display the articles. If you need it, email me at : [email protected], and i can give it to you.
Right now i am trying to clean it a bit, and will be uploading it to wordpress repository asap.