Simple Calendar – Google Calendar Plugin - Version 3.1.5

Version Description

  • September 25, 2016 =

  • Fix: Multi-day events in the future should now display first day of event when selecting "No, display on all days of event up to current day".

  • Fix: Correct dates in day headings in list view being off for some time zones.

  • Tweak: Clearer warning about using timezone setting "Event source default".

  • Dev: Added filters to add your own custom event template tags. Props @Brummolix

  • Dev: Remove all calls to date_default_timezone_set() due to the way WordPress core sets it to 'UTC' to calculate offsets from there.

Download this release

Release Info

Developer pderksen
Plugin Icon 128x128 Simple Calendar – Google Calendar Plugin
Version 3.1.5
Comparing to
See all releases

Code changes from version 3.1.4 to 3.1.5

assets/css/admin-add-calendar.min.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/css/admin.min.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/css/default-calendar-grid.min.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/css/default-calendar-list.min.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/js/admin-add-calendar.min.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/js/admin.min.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/js/default-calendar.min.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! Simple Calendar - 3.1.4
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
1
+ /*! Simple Calendar - 3.1.5
2
  * https://simplecalendar.io
3
  * Copyright (c) Moonstone Media 2016
4
  * Licensed GPLv2+ */
assets/js/vendor/moment.js CHANGED
@@ -1,5 +1,5 @@
1
  //! moment.js
2
- //! version : 2.15.0
3
  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
  //! license : MIT
5
  //! momentjs.com
@@ -1791,10 +1791,10 @@
1791
  var oldLocale = null;
1792
  // TODO: Find a better way to register and load all the locales in Node
1793
  if (!locales[name] && (typeof module !== 'undefined') &&
1794
- module && module.require) {
1795
  try {
1796
  oldLocale = globalLocale._abbr;
1797
- module.require('./locale/' + name);
1798
  // because defineLocale currently also sets the global locale, we
1799
  // want to undo that for lazy loaded locales
1800
  locale_locales__getSetGlobalLocale(oldLocale);
@@ -4195,7 +4195,7 @@
4195
  // Side effect imports
4196
 
4197
 
4198
- utils_hooks__hooks.version = '2.15.0';
4199
 
4200
  setHookCallback(local__createLocal);
4201
 
1
  //! moment.js
2
+ //! version : 2.15.1
3
  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
  //! license : MIT
5
  //! momentjs.com
1791
  var oldLocale = null;
1792
  // TODO: Find a better way to register and load all the locales in Node
1793
  if (!locales[name] && (typeof module !== 'undefined') &&
1794
+ module && module.exports) {
1795
  try {
1796
  oldLocale = globalLocale._abbr;
1797
+ require('./locale/' + name);
1798
  // because defineLocale currently also sets the global locale, we
1799
  // want to undo that for lazy loaded locales
1800
  locale_locales__getSetGlobalLocale(oldLocale);
4195
  // Side effect imports
4196
 
4197
 
4198
+ utils_hooks__hooks.version = '2.15.1';
4199
 
4200
  setHookCallback(local__createLocal);
4201
 
assets/js/vendor/moment.min.js CHANGED
@@ -1,5 +1,5 @@
1
  //! moment.js
2
- //! version : 2.15.0
3
  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
  //! license : MIT
5
  //! momentjs.com
@@ -101,7 +101,7 @@ function Xa(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Wa(a[f]).split("-"),b=e.le
101
  //the next array item is better than a shallower substring of this one
102
  break;b--}f++}return null}function Ya(a){var b=null;
103
  // TODO: Find a better way to register and load all the locales in Node
104
- if(!we[a]&&"undefined"!=typeof module&&module&&module.require)try{b=se._abbr,module.require("./locale/"+a),
105
  // because defineLocale currently also sets the global locale, we
106
  // want to undo that for lazy loaded locales
107
  Za(b)}catch(c){}return we[a]}
@@ -492,4 +492,4 @@ T("X",0,0,"unix"),T("x",0,0,"valueOf"),
492
  // PARSING
493
  Y("x",Rd),Y("X",Ud),aa("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),aa("x",function(a,b,c){c._d=new Date(t(a))}),
494
  // Side effect imports
495
- a.version="2.15.0",b(rb),a.fn=Se,a.min=tb,a.max=ub,a.now=Fe,a.utc=j,a.unix=Jc,a.months=Pc,a.isDate=f,a.locale=Za,a.invalid=n,a.duration=Nb,a.isMoment=r,a.weekdays=Rc,a.parseZone=Kc,a.localeData=ab,a.isDuration=wb,a.monthsShort=Qc,a.weekdaysMin=Tc,a.defineLocale=$a,a.updateLocale=_a,a.locales=bb,a.weekdaysShort=Sc,a.normalizeUnits=J,a.relativeTimeRounding=id,a.relativeTimeThreshold=jd,a.calendarFormat=Tb,a.prototype=Se;var nf=a;return nf});
1
  //! moment.js
2
+ //! version : 2.15.1
3
  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
  //! license : MIT
5
  //! momentjs.com
101
  //the next array item is better than a shallower substring of this one
102
  break;b--}f++}return null}function Ya(a){var b=null;
103
  // TODO: Find a better way to register and load all the locales in Node
104
+ if(!we[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=se._abbr,require("./locale/"+a),
105
  // because defineLocale currently also sets the global locale, we
106
  // want to undo that for lazy loaded locales
107
  Za(b)}catch(c){}return we[a]}
492
  // PARSING
493
  Y("x",Rd),Y("X",Ud),aa("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),aa("x",function(a,b,c){c._d=new Date(t(a))}),
494
  // Side effect imports
495
+ a.version="2.15.1",b(rb),a.fn=Se,a.min=tb,a.max=ub,a.now=Fe,a.utc=j,a.unix=Jc,a.months=Pc,a.isDate=f,a.locale=Za,a.invalid=n,a.duration=Nb,a.isMoment=r,a.weekdays=Rc,a.parseZone=Kc,a.localeData=ab,a.isDuration=wb,a.monthsShort=Qc,a.weekdaysMin=Tc,a.defineLocale=$a,a.updateLocale=_a,a.locales=bb,a.weekdaysShort=Sc,a.normalizeUnits=J,a.relativeTimeRounding=id,a.relativeTimeThreshold=jd,a.calendarFormat=Tb,a.prototype=Se;var nf=a;return nf});
google-calendar-events.php CHANGED
@@ -5,7 +5,7 @@
5
  * Description: Add Google Calendar events to your WordPress site in minutes. Beautiful calendar displays. Fully responsive.
6
  * Author: Moonstone Media
7
  * Author URI: https://simplecalendar.io
8
- * Version: 3.1.4
9
  * Text Domain: google-calendar-events
10
  * Domain Path: /i18n
11
  *
@@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
21
  $this_plugin_path = trailingslashit( dirname( __FILE__ ) );
22
  $this_plugin_dir = plugin_dir_url( __FILE__ );
23
  $this_plugin_constants = array(
24
- 'SIMPLE_CALENDAR_VERSION' => '3.1.4',
25
  'SIMPLE_CALENDAR_MAIN_FILE' => __FILE__,
26
  'SIMPLE_CALENDAR_URL' => $this_plugin_dir,
27
  'SIMPLE_CALENDAR_ASSETS' => $this_plugin_dir . 'assets/',
5
  * Description: Add Google Calendar events to your WordPress site in minutes. Beautiful calendar displays. Fully responsive.
6
  * Author: Moonstone Media
7
  * Author URI: https://simplecalendar.io
8
+ * Version: 3.1.5
9
  * Text Domain: google-calendar-events
10
  * Domain Path: /i18n
11
  *
21
  $this_plugin_path = trailingslashit( dirname( __FILE__ ) );
22
  $this_plugin_dir = plugin_dir_url( __FILE__ );
23
  $this_plugin_constants = array(
24
+ 'SIMPLE_CALENDAR_VERSION' => '3.1.5',
25
  'SIMPLE_CALENDAR_MAIN_FILE' => __FILE__,
26
  'SIMPLE_CALENDAR_URL' => $this_plugin_dir,
27
  'SIMPLE_CALENDAR_ASSETS' => $this_plugin_dir . 'assets/',
includes/abstracts/calendar.php CHANGED
@@ -820,13 +820,11 @@ abstract class Calendar {
820
  . 'data-events-last="' . $this->latest_event . '"'
821
  . '>';
822
 
823
- date_default_timezone_set( $this->timezone );
824
  do_action( 'simcal_calendar_html_before', $this->id );
825
 
826
  $view->html();
827
 
828
  do_action( 'simcal_calendar_html_after', $this->id );
829
- date_default_timezone_set( $this->site_timezone );
830
 
831
  //$settings = get_option( 'simple-calendar_settings_calendars' );
832
  $poweredby = get_post_meta( $this->id, '_poweredby', true );
820
  . 'data-events-last="' . $this->latest_event . '"'
821
  . '>';
822
 
 
823
  do_action( 'simcal_calendar_html_before', $this->id );
824
 
825
  $view->html();
826
 
827
  do_action( 'simcal_calendar_html_after', $this->id );
 
828
 
829
  //$settings = get_option( 'simple-calendar_settings_calendars' );
830
  $poweredby = get_post_meta( $this->id, '_poweredby', true );
includes/admin/metaboxes/settings.php CHANGED
@@ -572,7 +572,7 @@ class Settings implements Meta_Box {
572
  data-show-field-on-choice="true">
573
  <option value="use_site" <?php selected( 'use_site', $timezone_setting, true ); ?>><?php printf( _x( 'Site default', 'Use this site default setting', 'google-calendar-events' ) . ' (%s)', $timezone_default ); ?></option>
574
  <?php if ( $show_use_calendar ) { ?>
575
- <option id="use_calendar" value="use_calendar" data-show-field="_use_calendar_warning" <?php selected( 'use_calendar', $timezone_setting, true ); ?>><?php _ex( 'Events source default', 'Use the calendar default setting', 'google-calendar-events' ); ?></option>
576
  <?php } ?>
577
  <option value="use_custom" data-show-field="_feed_timezone" <?php selected( 'use_custom', $timezone_setting, true ); ?>><?php _ex( 'Custom', 'Use a custom setting', 'google-calendar-events' ); ?></option>
578
  </select>
@@ -582,9 +582,11 @@ class Settings implements Meta_Box {
582
  <?php echo 'use_custom' != $timezone_setting ? 'style="display: none;"' : ''; ?>>
583
  <?php echo wp_timezone_choice( $timezone ); ?>
584
  </select>
585
- <i class="simcal-icon-help simcal-help-tip" data-tip="<?php _e( 'Using a different timezone may alter the date and time display of your calendar events. It is recommended to keep the calendar default timezone.', 'google-calendar-events' ); ?>"></i>
586
  <p id="_use_calendar_warning" style="display: none;" class="simcal-field">
587
- <?php printf( __( '<strong>Warning:</strong> Using this option can return unexpected results if you have specified <a href="%s" target="_blank">event level</a> timezones.', 'google-calendar-events' ), 'http://docs.simplecalendar.io/timezone-settings/' ); ?>
 
 
588
  </p>
589
  </td>
590
  </tr>
572
  data-show-field-on-choice="true">
573
  <option value="use_site" <?php selected( 'use_site', $timezone_setting, true ); ?>><?php printf( _x( 'Site default', 'Use this site default setting', 'google-calendar-events' ) . ' (%s)', $timezone_default ); ?></option>
574
  <?php if ( $show_use_calendar ) { ?>
575
+ <option id="use_calendar" value="use_calendar" data-show-field="_use_calendar_warning" <?php selected( 'use_calendar', $timezone_setting, true ); ?>><?php _ex( 'Event source default', 'Use the calendar default setting', 'google-calendar-events' ); ?></option>
576
  <?php } ?>
577
  <option value="use_custom" data-show-field="_feed_timezone" <?php selected( 'use_custom', $timezone_setting, true ); ?>><?php _ex( 'Custom', 'Use a custom setting', 'google-calendar-events' ); ?></option>
578
  </select>
582
  <?php echo 'use_custom' != $timezone_setting ? 'style="display: none;"' : ''; ?>>
583
  <?php echo wp_timezone_choice( $timezone ); ?>
584
  </select>
585
+ <i class="simcal-icon-help simcal-help-tip" data-tip="<?php _e( 'Using a different timezone may alter the date and time display of your calendar events. We recommended using the site default timezone.', 'google-calendar-events' ); ?>"></i>
586
  <p id="_use_calendar_warning" style="display: none;" class="simcal-field">
587
+ <span class="attention"><?php _e( 'Warning', 'google-calendar-events' ); ?>:</span>
588
+ <?php _e( 'Setting this to <code>Event source default</code> can at times cause unexpected results. Please test thoroughly.', 'google-calendar-events' ); ?>
589
+ <a href="http://docs.simplecalendar.io/timezone-settings/" target="_blank"><?php _e( 'See details.', 'google-calendar-events' ); ?></a>
590
  </p>
591
  </td>
592
  </tr>
includes/calendars/views/default-calendar-grid.php CHANGED
@@ -421,12 +421,6 @@ class Default_Calendar_Grid implements Calendar_View {
421
 
422
  if ( $event instanceof Event ) :
423
 
424
- if ( $feed->type == 'grouped-calendars' ) {
425
- date_default_timezone_set( $feed_timezone );
426
- } else {
427
- date_default_timezone_set( $event->timezone );
428
- }
429
-
430
  // Store the calendar id where the event belongs (useful in grouped calendar feeds)
431
  $calendar_class = 'simcal-events-calendar-' . strval( $event->calendar );
432
  $calendar_classes[] = $calendar_class ;
@@ -566,8 +560,6 @@ class Default_Calendar_Grid implements Calendar_View {
566
  echo "\t" . '</tr>' . "\n";
567
  echo '</tbody>' . "\n";
568
 
569
- date_default_timezone_set( $calendar->site_timezone );
570
-
571
  return ob_get_clean();
572
  }
573
 
421
 
422
  if ( $event instanceof Event ) :
423
 
 
 
 
 
 
 
424
  // Store the calendar id where the event belongs (useful in grouped calendar feeds)
425
  $calendar_class = 'simcal-events-calendar-' . strval( $event->calendar );
426
  $calendar_classes[] = $calendar_class ;
560
  echo "\t" . '</tr>' . "\n";
561
  echo '</tbody>' . "\n";
562
 
 
 
563
  return ob_get_clean();
564
  }
565
 
includes/calendars/views/default-calendar-list.php CHANGED
@@ -468,11 +468,13 @@ class Default_Calendar_List implements Calendar_View {
468
  }
469
 
470
  $feed = simcal_get_feed( $calendar );
 
 
471
  $feed_timezone = get_post_meta( $feed->post_id, '_feed_timezone', true );
472
 
473
  $now = $calendar->now;
474
  $current_events = $this->get_events( $timestamp );
475
- $day_format = explode( ' ', $calendar->date_format );
476
 
477
  ob_start();
478
 
@@ -493,15 +495,15 @@ class Default_Calendar_List implements Calendar_View {
493
 
494
  if ( ! empty( $current_events ) && is_array( $current_events ) ) :
495
 
496
- foreach ( $current_events as $ymd => $events ) :
497
-
498
 
 
499
 
500
  // This is where we can find out if an event is a multi-day event and if it needs to be shown.
501
  // Since this is for list view we are showing the event on the day viewed if it is part of that day even when
502
  // expand multi-day events are turned off.
503
  if ( isset( $events[0][0]->multiple_days ) && $events[0][0]->multiple_days > 0 ) {
504
- if ( 'current_day_only' == get_post_meta($calendar->id, '_default_calendar_expand_multi_day_events', true ) ) {
505
 
506
  $year = substr( $ymd, 0, 4 );
507
  $month = substr( $ymd, 4, 2 );
@@ -509,19 +511,28 @@ class Default_Calendar_List implements Calendar_View {
509
 
510
  $temp_date = Carbon::createFromDate( $year, $month, $day );
511
 
512
- if( ! ( $temp_date < Carbon::now()->endOfDay() ) ) {
513
- continue;
 
 
 
 
 
 
 
514
  }
515
  }
516
  }
517
 
518
- $day_ts = Carbon::createFromFormat( 'Ymd', $ymd, $calendar->timezone )->startOfDay()->getTimestamp();
 
 
519
 
520
  if ( ! $calendar->compact_list ) :
521
 
522
  $date = new Carbon( 'now', $calendar->timezone );
523
  $date->setLocale( substr( get_locale(), 0, 2 ) );
524
- $date->setTimestamp( $day_ts );
525
 
526
  if ( $date->isToday() ) {
527
  $the_color = new Color( $calendar->today_color );
@@ -536,9 +547,7 @@ class Default_Calendar_List implements Calendar_View {
536
 
537
  echo "\t" . '<dt class="simcal-day-label"' . $border_style . '>';
538
  echo '<span' . $bg_style .'>';
539
- foreach ( $day_format as $format ) {
540
- echo $format ? '<span class="simcal-date-format" data-date-format="' . $format . '">' . date_i18n( $format, $day_ts ) . '</span> ' : ' ';
541
- }
542
  echo '</span>';
543
  echo '</dt>' . "\n";
544
 
@@ -547,7 +556,7 @@ class Default_Calendar_List implements Calendar_View {
547
  $list_events = '<ul class="simcal-events">' . "\n";
548
 
549
  $calendar_classes = array();
550
- $day_classes = 'simcal-weekday-' . date( 'w', $day_ts );
551
 
552
  // Is this the present, the past or the future, Doc?
553
  if ( $timestamp <= $now && $timestamp >= $now ) {
@@ -565,12 +574,6 @@ class Default_Calendar_List implements Calendar_View {
565
 
566
  if ( $event instanceof Event ) :
567
 
568
- if ( $feed->type == 'grouped-calendars' ) {
569
- date_default_timezone_set( $feed_timezone );
570
- } else {
571
- date_default_timezone_set( $event->timezone );
572
- }
573
-
574
  $event_classes = $event_visibility = '';
575
 
576
  $calendar_class = 'simcal-events-calendar-' . strval( $event->calendar );
@@ -656,8 +659,6 @@ class Default_Calendar_List implements Calendar_View {
656
 
657
  echo '</' . $block_tag . '>';
658
 
659
- date_default_timezone_set( $calendar->site_timezone );
660
-
661
  return ob_get_clean();
662
  }
663
 
468
  }
469
 
470
  $feed = simcal_get_feed( $calendar );
471
+
472
+ // TODO Need $feed_timezone?
473
  $feed_timezone = get_post_meta( $feed->post_id, '_feed_timezone', true );
474
 
475
  $now = $calendar->now;
476
  $current_events = $this->get_events( $timestamp );
477
+ $format = $calendar->date_format;
478
 
479
  ob_start();
480
 
495
 
496
  if ( ! empty( $current_events ) && is_array( $current_events ) ) :
497
 
498
+ $last_event = null;
 
499
 
500
+ foreach ( $current_events as $ymd => $events ) :
501
 
502
  // This is where we can find out if an event is a multi-day event and if it needs to be shown.
503
  // Since this is for list view we are showing the event on the day viewed if it is part of that day even when
504
  // expand multi-day events are turned off.
505
  if ( isset( $events[0][0]->multiple_days ) && $events[0][0]->multiple_days > 0 ) {
506
+ if ( 'current_day_only' == get_post_meta( $calendar->id, '_default_calendar_expand_multi_day_events', true ) ) {
507
 
508
  $year = substr( $ymd, 0, 4 );
509
  $month = substr( $ymd, 4, 2 );
511
 
512
  $temp_date = Carbon::createFromDate( $year, $month, $day );
513
 
514
+ if ( ! ( $temp_date < Carbon::now()->endOfDay() ) ) {
515
+
516
+ // Break here only if event already shown once.
517
+ if ( $last_event == $events[0][0] ) {
518
+ continue;
519
+ } else {
520
+ // Save event as "last" for next time through, then break.
521
+ $last_event = $events[0][0];
522
+ }
523
  }
524
  }
525
  }
526
 
527
+ // Calculate timestamp offset for list view day headings.
528
+ $day_date = Carbon::createFromFormat( 'Ymd', $ymd, $calendar->timezone );
529
+ $day_ts_offset = $day_date->addSeconds( $day_date->offset )->timestamp;
530
 
531
  if ( ! $calendar->compact_list ) :
532
 
533
  $date = new Carbon( 'now', $calendar->timezone );
534
  $date->setLocale( substr( get_locale(), 0, 2 ) );
535
+ $date->setTimestamp( $day_ts_offset );
536
 
537
  if ( $date->isToday() ) {
538
  $the_color = new Color( $calendar->today_color );
547
 
548
  echo "\t" . '<dt class="simcal-day-label"' . $border_style . '>';
549
  echo '<span' . $bg_style .'>';
550
+ echo $format ? '<span class="simcal-date-format" data-date-format="' . $format . '">' . date_i18n( $format, $day_ts_offset ) . '</span> ' : ' ';
 
 
551
  echo '</span>';
552
  echo '</dt>' . "\n";
553
 
556
  $list_events = '<ul class="simcal-events">' . "\n";
557
 
558
  $calendar_classes = array();
559
+ $day_classes = 'simcal-weekday-' . date( 'w', $day_ts_offset );
560
 
561
  // Is this the present, the past or the future, Doc?
562
  if ( $timestamp <= $now && $timestamp >= $now ) {
574
 
575
  if ( $event instanceof Event ) :
576
 
 
 
 
 
 
 
577
  $event_classes = $event_visibility = '';
578
 
579
  $calendar_class = 'simcal-events-calendar-' . strval( $event->calendar );
659
 
660
  echo '</' . $block_tag . '>';
661
 
 
 
662
  return ob_get_clean();
663
  }
664
 
includes/events/event-builder.php CHANGED
@@ -68,94 +68,153 @@ class Event_Builder {
68
  * @return array
69
  */
70
  public function get_content_tags() {
71
- return array(
72
 
73
  /* ============ *
74
  * Content Tags *
75
  * ============ */
76
 
77
- 'title', // The event title.
78
- 'event-title', // @deprecated An alias for 'title' tag.
79
- 'description', // The event description.
80
-
81
- 'when', // Date and time of the event.
82
- 'start-time', // Start time of the event.
83
- 'start-date', // Start date of the event.
84
- 'start-custom', // @deprecated Start time in a user defined format (set by tag 'format' attribute).
85
- 'start-human', // Start time in a human friendly format.
86
- 'end-time', // End time of the event.
87
- 'end-date', // End date of the event.
88
- 'end-custom', // @deprecated End date-time in a user defined format (set by tag 'format' attribute).
89
- 'end-human', // End date-time in a human friendly format.
90
-
91
- 'duration', // How long the events lasts, in a human-readable format.
92
- 'length', // @deprecated An alias of 'duration' tag.
93
-
94
- 'location', // Alias of start-location.
95
- 'start-location', // Location name where the event starts.
96
- 'maps-link', // @deprecated An alias for 'start-location-link' tag.
97
- 'start-location-link', // Link to Google Maps querying the event start location address.
98
- 'end-location', // Location name where the event ends.
99
- 'end-location-link', // Link to Google Maps querying the event end location address.
100
-
101
- 'link', // An HTML link to the event URL.
102
- 'url', // A string with the raw event link URL.
103
- 'add-to-gcal-link', // Link for viewers to add to their GCals.
104
-
105
- 'calendar', // The title of the source calendar.
106
- 'feed-title', // @deprecated An alias of 'calendar'.
107
-
108
- 'id', // The event unique ID.
109
- 'uid', // An alias of ID.
110
- 'ical-id', // iCal ID.
111
- 'event-id', // @deprecated An alias for 'id' tag.
112
- 'calendar-id', // The calendar ID.
113
- 'feed-id', // @deprecated An alias for 'calendar-id' tag.
114
- 'cal-id', // @deprecated An alias for 'calendar-id' tag.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  /* ========= *
117
  * Meta Tags *
118
  * ========= */
119
 
120
- 'attachments', // List of attachments.
121
- 'attendees', // List of attendees.
122
- 'organizer', // Creator info.
 
 
 
123
 
124
  /* ================ *
125
  * Conditional Tags *
126
  * ================ */
127
 
128
- 'if-title', // If the event has a title.
129
- 'if-description', // If the event has a description.
130
-
131
- 'if-now', // If the event is taking place now.
132
- 'if-not-now', // If the event is not taking place now (may have ended or just not started yet).
133
- 'if-started', // If the event has started (and may as well as ended).
134
- 'if-not-started', // If the event has NOT started yet (event could be any time in the future).
135
- 'if-ended', // If the event has ended (event could be any time in the past).
136
- 'if-not-ended', // If the event has NOT ended (may as well as not started yet).
137
-
138
- 'if-whole-day', // If the event lasts the whole day.
139
- 'if-all-day', // @deprecated Alias for 'if-whole-day'.
140
- 'if-not-whole-day', // If the event does NOT last the whole day.
141
- 'if-not-all-day', // @deprecated Alias for 'if-not-whole-day'.
142
- 'if-end-time', // If the event has a set end time.
143
- 'if-no-end-time', // If the event has NOT a set end time.
144
-
145
- 'if-multi-day', // If the event spans multiple days.
146
- 'if-single-day', // If the event does not span multiple days.
147
-
148
- 'if-recurring', // If the event is a recurring event.
149
- 'if-not-recurring', // If the event is NOT a recurring event.
150
-
151
- 'if-location', // @deprecated Alias for 'if-start-location'.
152
- 'if-start-location', // Does the event has a start location?
153
- 'if-end-location', // Does the event has an end location?
154
- 'if-not-location', // @deprecated Alias for 'if-not-start-location'.
155
- 'if-not-start-location', // Does the event has NOT a start location?
156
- 'if-not-end-location', // Does the event has NOT an end location?
157
-
158
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
 
161
  /**
@@ -170,15 +229,12 @@ class Event_Builder {
170
  public function parse_event_template_tags( $template_tags = '' ) {
171
 
172
  // Process tags.
173
- $result = preg_replace_callback(
174
- $this->get_regex(),
175
- array( $this, 'process_event_content' ),
176
- $template_tags
177
- );
178
 
179
  // Removes extra consecutive <br> tags.
180
  // TODO: Doesn't seem to work but going to remove it to allow multiple <br> tags in the editor
181
  /*return preg_replace( '#(<br *//*?>\s*)+#i', '<br />', trim( $result ) );*/
 
182
  return do_shortcode( trim( $result ) );
183
  }
184
 
@@ -194,7 +250,7 @@ class Event_Builder {
194
  public function process_event_content( $match ) {
195
 
196
  if ( $match[1] == '[' && $match[6] == ']' ) {
197
- return substr( $match[0], 1, - 1 );
198
  }
199
 
200
  $tag = $match[2]; // Tag name without square brackets.
@@ -243,12 +299,13 @@ class Event_Builder {
243
  $duration = '-1';
244
  $value = __( 'No end time', 'google-calendar-events' );
245
  }
 
246
  return ' <span class="simcal-event-duration" data-event-duration="' . $duration . '">' . $value . '</span>';
247
 
248
  case 'location' :
249
  case 'start-location' :
250
  case 'end-location' :
251
- $location = ( 'end-location' == $tag ) ? $event->end_location['address'] : $event->start_location['address'];
252
  $location_class = ( 'end-location' == $tag ) ? 'end' : 'start';
253
 
254
  // location, location.name, location.address (type PostalAddress) all required for schema data.
@@ -258,11 +315,7 @@ class Event_Builder {
258
  // Wrap with wp_strip_all_tags().
259
  $meta_location_name_and_address = empty( $location ) ? wp_strip_all_tags( $event->title ) : wp_strip_all_tags( $location );
260
 
261
- return ' <span class="simcal-event-address simcal-event-' . $location_class . '-location" itemprop="location" itemscope itemtype="http://schema.org/Place">' .
262
- '<meta itemprop="name" content="' . $meta_location_name_and_address . '" />' .
263
- '<meta itemprop="address" content="' . $meta_location_name_and_address . '" />' .
264
- wp_strip_all_tags( $location ) .
265
- '</span>';
266
 
267
  case 'start-location-link':
268
  case 'end-location-link' :
@@ -270,6 +323,7 @@ class Event_Builder {
270
  $location = ( 'end-location-link' == $tag ) ? $event->end_location['address'] : $event->start_location['address'];
271
  if ( ! empty( $location ) ) {
272
  $url = '//maps.google.com?q=' . urlencode( $location );
 
273
  return $this->make_link( $tag, $url, $calendar->get_event_html( $event, $partial ), $attr );
274
  }
275
  break;
@@ -277,7 +331,8 @@ class Event_Builder {
277
  case 'link' :
278
  case 'url' :
279
  $content = ( 'link' == $tag ) ? $calendar->get_event_html( $event, $partial ) : '';
280
- return $this->make_link( $tag, $event->link, $content , $attr );
 
281
 
282
  case 'add-to-gcal-link';
283
  $content = ( 'add-to-gcal-link' == $tag ) ? $calendar->get_event_html( $event, $partial ) : '';
@@ -350,7 +405,7 @@ class Event_Builder {
350
  case 'if-not-now' :
351
 
352
  $start_dt = $event->start_dt->setTimezone( $calendar->timezone );
353
- $start = $start_dt->getTimestamp();
354
 
355
  if ( $event->end_dt instanceof Carbon ) {
356
  $end = $event->end_dt->setTimezone( $calendar->timezone )->getTimestamp();
@@ -457,6 +512,7 @@ class Event_Builder {
457
  if ( ! empty( $event->start_location['address'] ) ) {
458
  return $calendar->get_event_html( $event, $partial );
459
  }
 
460
  return false;
461
 
462
  case 'if-not-location' :
@@ -464,25 +520,33 @@ class Event_Builder {
464
  if ( empty( $event->start_location['address'] ) ) {
465
  return $calendar->get_event_html( $event, $partial );
466
  }
 
467
  return '';
468
 
469
  case 'if-not-end-location' :
470
  if ( empty( $event->end_location['address'] ) ) {
471
  return $calendar->get_event_html( $event, $partial );
472
  }
 
473
  return '';
474
 
475
  case 'if-end-location' :
476
  if ( ! empty( $event->end_location['address'] ) ) {
477
  return $calendar->get_event_html( $event, $partial );
478
  }
 
479
  return '';
480
 
481
  /* ======= *
482
- * Default *
483
  * ======= */
484
 
485
  default :
 
 
 
 
 
486
  return wp_kses_post( $before . $partial . $after );
487
  }
488
  }
@@ -497,7 +561,7 @@ class Event_Builder {
497
  * @access private
498
  *
499
  * @param string $text
500
- * @param int $limit
501
  *
502
  * @return string
503
  */
@@ -506,9 +570,9 @@ class Event_Builder {
506
  $limit = max( absint( $limit ), 0 );
507
 
508
  if ( $limit > 0 && ( str_word_count( $text, 0 ) > $limit ) ) {
509
- $words = str_word_count( $text, 2 );
510
- $pos = array_keys( $words );
511
- $text = trim( substr( $text, 0, $pos[ $limit ] ) ) . '&hellip;';
512
  }
513
 
514
  return $text;
@@ -538,10 +602,10 @@ class Event_Builder {
538
 
539
  if ( ! empty( $attr['html'] ) ) {
540
  $title = wp_kses_post( $title );
541
- $tag = 'div';
542
  } else {
543
  $title = $this->limit_words( $title, $attr['limit'] );
544
- $tag = 'span';
545
  }
546
 
547
  return '<' . $tag . ' class="simcal-event-title" itemprop="name">' . $title . '</' . $tag . '>';
@@ -565,13 +629,13 @@ class Event_Builder {
565
  }
566
 
567
  $attr = array_merge( array(
568
- 'limit' => 0, // Trim length to number of words
569
- 'html' => 'no', // Parse HTML content
570
- 'markdown' => 'no', // Parse Markdown content
571
- 'autolink' => 'no', // Automatically convert plaintext URIs to anchors
572
  ), (array) shortcode_parse_atts( $attr ) );
573
 
574
- $allow_html = 'no' != $attr['html'] ? true : false;
575
  $allow_md = 'no' != $attr['markdown'] ? true : false;
576
 
577
  $html = '<div class="simcal-event-description" itemprop="description">';
@@ -581,7 +645,7 @@ class Event_Builder {
581
  if ( $allow_html ) {
582
  $description = wp_kses_post( $description );
583
  } elseif ( $allow_md ) {
584
- $markdown = new \Parsedown();
585
  $description = $markdown->text( wp_strip_all_tags( $description ) );
586
  }
587
  } else {
@@ -611,30 +675,25 @@ class Event_Builder {
611
  */
612
  private function get_when( Event $event ) {
613
 
614
- $start = $event->start_dt->setTimezone( $event->timezone );
615
- $end = ! is_null( $event->end_dt ) ? $event->end_dt->setTimezone( $event->timezone ) : null;
 
 
616
 
617
  $time_start = '';
618
- $time_end = '';
 
 
 
 
619
 
620
  if ( ! $event->whole_day ) {
621
 
622
- $time_start = $this->calendar->datetime_separator .
623
- ' <span class="simcal-event-start simcal-event-start-time" ' .
624
- 'data-event-start="' . $start->getTimestamp() . '" ' .
625
- 'data-event-format="' . $this->calendar->time_format . '" ' .
626
- 'itemprop="startDate" content="' . $start->toIso8601String() . '">' .
627
- date_i18n( $this->calendar->time_format, $start->getTimestamp() ) .
628
- '</span> ';
629
 
630
  if ( $end instanceof Carbon ) {
631
 
632
- $time_end = ' <span class="simcal-event-end simcal-event-end-time" ' .
633
- 'data-event-end="' . $end->getTimestamp() . '" ' .
634
- 'data-event-format="' . $this->calendar->time_format . '" ' .
635
- 'itemprop="endDate" content="' . $end->toIso8601String() . '">' .
636
- date_i18n( $this->calendar->time_format, $end->getTimestamp() ) .
637
- '</span> ';
638
 
639
  }
640
 
@@ -642,24 +701,11 @@ class Event_Builder {
642
 
643
  if ( $event->multiple_days ) {
644
 
645
- $output = ' <span class="simcal-event-start simcal-event-start-date" ' .
646
- 'data-event-start="' . $start->getTimestamp() . '" ' .
647
- 'data-event-format="' . $this->calendar->date_format . '" ' .
648
- 'itemprop="startDate" content="' . $start->toIso8601String() . '">' .
649
- date_i18n( $this->calendar->date_format, $start->getTimestamp() ) .
650
- '</span> ' .
651
- $time_start;
652
 
653
  if ( $end instanceof Carbon ) {
654
 
655
- $output .= '-' .
656
- ' <span class="simcal-event-start simcal-event-end-date" ' .
657
- 'data-event-start="' . $end->getTimestamp() . '" ' .
658
- 'data-event-format="' . $this->calendar->date_format . '" ' .
659
- 'itemprop="endDate" content="' . $end->toIso8601String() . '">' .
660
- date_i18n( $this->calendar->date_format, $end->getTimestamp() ) .
661
- '</span> ' .
662
- $time_end;
663
  }
664
 
665
  } else {
@@ -667,14 +713,7 @@ class Event_Builder {
667
  $time_end = ! empty( $time_start ) && ! empty( $time_end ) ? ' - ' . $time_end : '';
668
 
669
  // All-day events also need startDate for schema data.
670
- $output = ' <span class="simcal-event-start simcal-event-start-date" ' .
671
- 'data-event-start="' . $start->getTimestamp() . '" ' .
672
- 'data-event-format="' . $this->calendar->date_format . '" ' .
673
- 'itemprop="startDate" content="' . $start->toIso8601String() . '">' .
674
- date_i18n( $this->calendar->date_format, $start->getTimestamp() ) .
675
- '</span> ' .
676
- $time_start .
677
- $time_end;
678
 
679
  }
680
 
@@ -696,22 +735,26 @@ class Event_Builder {
696
  private function get_dt( $tag, Event $event, $attr ) {
697
 
698
  $bound = 0 === strpos( $tag, 'end' ) ? 'end' : 'start';
 
699
  if ( ( 'end' == $bound ) && ( false === $event->end ) ) {
700
  return '';
701
  }
702
 
703
  $dt = $bound . '_dt';
 
704
  if ( ! $event->$dt instanceof Carbon ) {
705
  return '';
706
  }
707
- $event_dt = $event->$dt->setTimezone( $event->timezone );
 
708
 
709
  $attr = array_merge( array(
710
- 'format' => '',
711
  ), (array) shortcode_parse_atts( $attr ) );
712
 
713
- $format = ltrim( strstr( $tag, '-' ), '-' );
714
  $dt_format = '';
 
715
  if ( ! empty( $attr['format'] ) ) {
716
  $dt_format = esc_attr( wp_strip_all_tags( $attr['format'] ) );
717
  } elseif ( 'date' == $format ) {
@@ -720,24 +763,21 @@ class Event_Builder {
720
  $dt_format = $this->calendar->time_format;
721
  }
722
 
 
 
723
  if ( 'human' == $format ) {
724
- $value = human_time_diff( $event_dt->getTimestamp(), Carbon::now( $event->timezone )->getTimestamp() );
725
 
726
- if ( $event_dt->getTimestamp() < Carbon::now( $event->timezone )->getTimestamp() ) {
727
  $value .= ' ' . _x( 'ago', 'human date event builder code modifier', 'google-calendar-events' );
728
  } else {
729
  $value .= ' ' . _x( 'from now', 'human date event builder code modifier', 'google-calendar-events' );
730
  }
731
  } else {
732
- $value = date_i18n( $dt_format, $event_dt->getTimestamp() );
733
  }
734
 
735
- return '<span class="simcal-event-' . $bound . ' ' . 'simcal-event-' . $bound . '-' . $format . '" ' .
736
- 'data-event-' . $bound . '="' . $event_dt->getTimestamp() . '" ' .
737
- 'data-event-format="' . $dt_format . '" ' .
738
- 'itemprop="' . $bound . 'Date" content="' . $event_dt->toIso8601String() . '">' .
739
- $value .
740
- '</span>';
741
  }
742
 
743
  /**
@@ -814,15 +854,15 @@ class Event_Builder {
814
  private function get_attendees( $attendees, $attr ) {
815
 
816
  $attr = array_merge( array(
817
- 'photo' => 'show', // show/hide attendee photo
818
- 'email' => 'hide', // show/hide attendee email address
819
- 'rsvp' => 'hide', // show/hide rsvp response status
820
- 'response' => '', // filter attendees by rsvp response (yes/no/maybe)
821
  ), (array) shortcode_parse_atts( $attr ) );
822
 
823
  $html = '<ul class="simcal-attendees" itemprop="attendees">' . "\n\t";
824
 
825
- $known = 0;
826
  $unknown = 0;
827
 
828
  foreach ( $attendees as $attendee ) {
@@ -837,9 +877,9 @@ class Event_Builder {
837
 
838
  if ( ! empty( $attendee['name'] ) ) {
839
 
840
- $photo = 'hide' != $attr['photo'] ? '<img class="avatar avatar-128 photo" src="' . $attendee['photo'] . '" itemprop="image" />' : '';
841
- $response = 'hide' != $attr['rsvp'] ? $this->get_rsvp_response( $attendee['response'] ) : '';
842
- $guest = $photo . '<span itemprop="name">' . $attendee['name'] . $response . '</span>';
843
 
844
  if ( ! empty( $attendee['email'] ) && ( 'show' == $attr['email'] ) ) {
845
  $guest = sprintf( '<a href="mailto:' . $attendee['email'] . '" itemprop="email">%s</a>', $guest );
@@ -921,8 +961,8 @@ class Event_Builder {
921
  'email' => 'hide', // show/hide attendee email address
922
  ), (array) shortcode_parse_atts( $attr ) );
923
 
924
- $photo = 'hide' != $attr['photo'] ? '<img class="avatar avatar-128 photo" src="' . $organizer['photo'] . '" itemprop="image" />' : '';
925
- $organizer_html = $photo . '<span itemprop="name">' . $organizer['name'] . '</span>';
926
 
927
  if ( ! empty( $organizer['email'] ) && ( 'show' == $attr['email'] ) ) {
928
  $organizer_html = sprintf( '<a href="mailto:' . $organizer['email'] . '" itemprop="email">%s</a>', $organizer_html );
@@ -955,36 +995,37 @@ class Event_Builder {
955
 
956
  $tagregexp = implode( '|', array_values( $this->tags ) );
957
 
958
- return '/'
959
- . '\\[' // Opening bracket
960
  . '(\\[?)' // 1: Optional second opening bracket for escaping tags: [[tag]]
961
  . "($tagregexp)" // 2: Tag name
962
  . '(?![\\w-])' // Not followed by word character or hyphen
963
  . '(' // 3: Unroll the loop: Inside the opening tag
964
- . '[^\\]\\/]*' // Not a closing bracket or forward slash
965
- . '(?:'
966
- . '\\/(?!\\])' // A forward slash not followed by a closing bracket
967
- . '[^\\]\\/]*' // Not a closing bracket or forward slash
968
- . ')*?'
969
- . ')'
970
- . '(?:'
971
- . '(\\/)' // 4: Self closing tag ...
972
- . '\\]' // ... and closing bracket
973
- . '|'
974
- . '\\]' // Closing bracket
975
- . '(?:'
976
- . '(' // 5: Unroll the loop: Optionally, anything between the opening and closing tags
977
- . '[^\\[]*+' // Not an opening bracket
978
- . '(?:'
979
- . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing tag
980
- . '[^\\[]*+' // Not an opening bracket
981
- . ')*+'
982
- . ')'
983
- . '\\[\\/\\2\\]' // Closing tag
984
- . ')?'
985
- . ')'
986
- . '(\\]?)' // 6: Optional second closing bracket for escaping tags: [[tag]]
987
  . '/s';
988
  }
989
 
 
 
 
 
 
 
 
 
 
 
 
 
 
990
  }
68
  * @return array
69
  */
70
  public function get_content_tags() {
71
+ return array_merge( array(
72
 
73
  /* ============ *
74
  * Content Tags *
75
  * ============ */
76
 
77
+ 'title',
78
+ // The event title.
79
+ 'event-title',
80
+ // @deprecated An alias for 'title' tag.
81
+ 'description',
82
+ // The event description.
83
+
84
+ 'when',
85
+ // Date and time of the event.
86
+ 'start-time',
87
+ // Start time of the event.
88
+ 'start-date',
89
+ // Start date of the event.
90
+ 'start-custom',
91
+ // @deprecated Start time in a user defined format (set by tag 'format' attribute).
92
+ 'start-human',
93
+ // Start time in a human friendly format.
94
+ 'end-time',
95
+ // End time of the event.
96
+ 'end-date',
97
+ // End date of the event.
98
+ 'end-custom',
99
+ // @deprecated End date-time in a user defined format (set by tag 'format' attribute).
100
+ 'end-human',
101
+ // End date-time in a human friendly format.
102
+
103
+ 'duration',
104
+ // How long the events lasts, in a human-readable format.
105
+ 'length',
106
+ // @deprecated An alias of 'duration' tag.
107
+
108
+ 'location',
109
+ // Alias of start-location.
110
+ 'start-location',
111
+ // Location name where the event starts.
112
+ 'maps-link',
113
+ // @deprecated An alias for 'start-location-link' tag.
114
+ 'start-location-link',
115
+ // Link to Google Maps querying the event start location address.
116
+ 'end-location',
117
+ // Location name where the event ends.
118
+ 'end-location-link',
119
+ // Link to Google Maps querying the event end location address.
120
+
121
+ 'link',
122
+ // An HTML link to the event URL.
123
+ 'url',
124
+ // A string with the raw event link URL.
125
+ 'add-to-gcal-link',
126
+ // Link for viewers to add to their GCals.
127
+
128
+ 'calendar',
129
+ // The title of the source calendar.
130
+ 'feed-title',
131
+ // @deprecated An alias of 'calendar'.
132
+
133
+ 'id',
134
+ // The event unique ID.
135
+ 'uid',
136
+ // An alias of ID.
137
+ 'ical-id',
138
+ // iCal ID.
139
+ 'event-id',
140
+ // @deprecated An alias for 'id' tag.
141
+ 'calendar-id',
142
+ // The calendar ID.
143
+ 'feed-id',
144
+ // @deprecated An alias for 'calendar-id' tag.
145
+ 'cal-id',
146
+ // @deprecated An alias for 'calendar-id' tag.
147
 
148
  /* ========= *
149
  * Meta Tags *
150
  * ========= */
151
 
152
+ 'attachments',
153
+ // List of attachments.
154
+ 'attendees',
155
+ // List of attendees.
156
+ 'organizer',
157
+ // Creator info.
158
 
159
  /* ================ *
160
  * Conditional Tags *
161
  * ================ */
162
 
163
+ 'if-title',
164
+ // If the event has a title.
165
+ 'if-description',
166
+ // If the event has a description.
167
+
168
+ 'if-now',
169
+ // If the event is taking place now.
170
+ 'if-not-now',
171
+ // If the event is not taking place now (may have ended or just not started yet).
172
+ 'if-started',
173
+ // If the event has started (and may as well as ended).
174
+ 'if-not-started',
175
+ // If the event has NOT started yet (event could be any time in the future).
176
+ 'if-ended',
177
+ // If the event has ended (event could be any time in the past).
178
+ 'if-not-ended',
179
+ // If the event has NOT ended (may as well as not started yet).
180
+
181
+ 'if-whole-day',
182
+ // If the event lasts the whole day.
183
+ 'if-all-day',
184
+ // @deprecated Alias for 'if-whole-day'.
185
+ 'if-not-whole-day',
186
+ // If the event does NOT last the whole day.
187
+ 'if-not-all-day',
188
+ // @deprecated Alias for 'if-not-whole-day'.
189
+ 'if-end-time',
190
+ // If the event has a set end time.
191
+ 'if-no-end-time',
192
+ // If the event has NOT a set end time.
193
+
194
+ 'if-multi-day',
195
+ // If the event spans multiple days.
196
+ 'if-single-day',
197
+ // If the event does not span multiple days.
198
+
199
+ 'if-recurring',
200
+ // If the event is a recurring event.
201
+ 'if-not-recurring',
202
+ // If the event is NOT a recurring event.
203
+
204
+ 'if-location',
205
+ // @deprecated Alias for 'if-start-location'.
206
+ 'if-start-location',
207
+ // Does the event has a start location?
208
+ 'if-end-location',
209
+ // Does the event has an end location?
210
+ 'if-not-location',
211
+ // @deprecated Alias for 'if-not-start-location'.
212
+ 'if-not-start-location',
213
+ // Does the event has NOT a start location?
214
+ 'if-not-end-location',
215
+ // Does the event has NOT an end location?
216
+
217
+ ), (array) $this->add_custom_event_tags() );
218
  }
219
 
220
  /**
229
  public function parse_event_template_tags( $template_tags = '' ) {
230
 
231
  // Process tags.
232
+ $result = preg_replace_callback( $this->get_regex(), array( $this, 'process_event_content' ), $template_tags );
 
 
 
 
233
 
234
  // Removes extra consecutive <br> tags.
235
  // TODO: Doesn't seem to work but going to remove it to allow multiple <br> tags in the editor
236
  /*return preg_replace( '#(<br *//*?>\s*)+#i', '<br />', trim( $result ) );*/
237
+
238
  return do_shortcode( trim( $result ) );
239
  }
240
 
250
  public function process_event_content( $match ) {
251
 
252
  if ( $match[1] == '[' && $match[6] == ']' ) {
253
+ return substr( $match[0], 1, -1 );
254
  }
255
 
256
  $tag = $match[2]; // Tag name without square brackets.
299
  $duration = '-1';
300
  $value = __( 'No end time', 'google-calendar-events' );
301
  }
302
+
303
  return ' <span class="simcal-event-duration" data-event-duration="' . $duration . '">' . $value . '</span>';
304
 
305
  case 'location' :
306
  case 'start-location' :
307
  case 'end-location' :
308
+ $location = ( 'end-location' == $tag ) ? $event->end_location['address'] : $event->start_location['address'];
309
  $location_class = ( 'end-location' == $tag ) ? 'end' : 'start';
310
 
311
  // location, location.name, location.address (type PostalAddress) all required for schema data.
315
  // Wrap with wp_strip_all_tags().
316
  $meta_location_name_and_address = empty( $location ) ? wp_strip_all_tags( $event->title ) : wp_strip_all_tags( $location );
317
 
318
+ return ' <span class="simcal-event-address simcal-event-' . $location_class . '-location" itemprop="location" itemscope itemtype="http://schema.org/Place">' . '<meta itemprop="name" content="' . $meta_location_name_and_address . '" />' . '<meta itemprop="address" content="' . $meta_location_name_and_address . '" />' . wp_strip_all_tags( $location ) . '</span>';
 
 
 
 
319
 
320
  case 'start-location-link':
321
  case 'end-location-link' :
323
  $location = ( 'end-location-link' == $tag ) ? $event->end_location['address'] : $event->start_location['address'];
324
  if ( ! empty( $location ) ) {
325
  $url = '//maps.google.com?q=' . urlencode( $location );
326
+
327
  return $this->make_link( $tag, $url, $calendar->get_event_html( $event, $partial ), $attr );
328
  }
329
  break;
331
  case 'link' :
332
  case 'url' :
333
  $content = ( 'link' == $tag ) ? $calendar->get_event_html( $event, $partial ) : '';
334
+
335
+ return $this->make_link( $tag, $event->link, $content, $attr );
336
 
337
  case 'add-to-gcal-link';
338
  $content = ( 'add-to-gcal-link' == $tag ) ? $calendar->get_event_html( $event, $partial ) : '';
405
  case 'if-not-now' :
406
 
407
  $start_dt = $event->start_dt->setTimezone( $calendar->timezone );
408
+ $start = $start_dt->getTimestamp();
409
 
410
  if ( $event->end_dt instanceof Carbon ) {
411
  $end = $event->end_dt->setTimezone( $calendar->timezone )->getTimestamp();
512
  if ( ! empty( $event->start_location['address'] ) ) {
513
  return $calendar->get_event_html( $event, $partial );
514
  }
515
+
516
  return false;
517
 
518
  case 'if-not-location' :
520
  if ( empty( $event->start_location['address'] ) ) {
521
  return $calendar->get_event_html( $event, $partial );
522
  }
523
+
524
  return '';
525
 
526
  case 'if-not-end-location' :
527
  if ( empty( $event->end_location['address'] ) ) {
528
  return $calendar->get_event_html( $event, $partial );
529
  }
530
+
531
  return '';
532
 
533
  case 'if-end-location' :
534
  if ( ! empty( $event->end_location['address'] ) ) {
535
  return $calendar->get_event_html( $event, $partial );
536
  }
537
+
538
  return '';
539
 
540
  /* ======= *
541
+ * Custom Event Tags or Default *
542
  * ======= */
543
 
544
  default :
545
+ $resultCustom = $this->do_custom_event_tag( $tag, $partial, $attr, $event );
546
+ if ( $resultCustom != "" ) {
547
+ return $resultCustom;
548
+ }
549
+
550
  return wp_kses_post( $before . $partial . $after );
551
  }
552
  }
561
  * @access private
562
  *
563
  * @param string $text
564
+ * @param int $limit
565
  *
566
  * @return string
567
  */
570
  $limit = max( absint( $limit ), 0 );
571
 
572
  if ( $limit > 0 && ( str_word_count( $text, 0 ) > $limit ) ) {
573
+ $words = str_word_count( $text, 2 );
574
+ $pos = array_keys( $words );
575
+ $text = trim( substr( $text, 0, $pos[ $limit ] ) ) . '&hellip;';
576
  }
577
 
578
  return $text;
602
 
603
  if ( ! empty( $attr['html'] ) ) {
604
  $title = wp_kses_post( $title );
605
+ $tag = 'div';
606
  } else {
607
  $title = $this->limit_words( $title, $attr['limit'] );
608
+ $tag = 'span';
609
  }
610
 
611
  return '<' . $tag . ' class="simcal-event-title" itemprop="name">' . $title . '</' . $tag . '>';
629
  }
630
 
631
  $attr = array_merge( array(
632
+ 'limit' => 0, // Trim length to number of words
633
+ 'html' => 'no', // Parse HTML content
634
+ 'markdown' => 'no', // Parse Markdown content
635
+ 'autolink' => 'no', // Automatically convert plaintext URIs to anchors
636
  ), (array) shortcode_parse_atts( $attr ) );
637
 
638
+ $allow_html = 'no' != $attr['html'] ? true : false;
639
  $allow_md = 'no' != $attr['markdown'] ? true : false;
640
 
641
  $html = '<div class="simcal-event-description" itemprop="description">';
645
  if ( $allow_html ) {
646
  $description = wp_kses_post( $description );
647
  } elseif ( $allow_md ) {
648
+ $markdown = new \Parsedown();
649
  $description = $markdown->text( wp_strip_all_tags( $description ) );
650
  }
651
  } else {
675
  */
676
  private function get_when( Event $event ) {
677
 
678
+ //$start = $event->start_dt->setTimezone( $event->timezone );
679
+ //$end = ! is_null( $event->end_dt ) ? $event->end_dt->setTimezone( $event->timezone ) : null;
680
+ $start = $event->start_dt;
681
+ $end = $event->end_dt;
682
 
683
  $time_start = '';
684
+ $time_end = '';
685
+ $start_ts = $start->timestamp;
686
+ $end_ts = $end->timestamp;
687
+ $start_iso = $start->toIso8601String();
688
+ $end_iso = $end->toIso8601String();
689
 
690
  if ( ! $event->whole_day ) {
691
 
692
+ $time_start = $this->calendar->datetime_separator . ' <span class="simcal-event-start simcal-event-start-time" ' . 'data-event-start="' . $start_ts . '" ' . 'data-event-format="' . $this->calendar->time_format . '" ' . 'itemprop="startDate" content="' . $start_iso . '">' . $start->format( $this->calendar->time_format ) . '</span> ';
 
 
 
 
 
 
693
 
694
  if ( $end instanceof Carbon ) {
695
 
696
+ $time_end = ' <span class="simcal-event-end simcal-event-end-time" ' . 'data-event-end="' . $end_ts . '" ' . 'data-event-format="' . $this->calendar->time_format . '" ' . 'itemprop="endDate" content="' . $end_iso . '">' . $end->format( $this->calendar->time_format ) . '</span> ';
 
 
 
 
 
697
 
698
  }
699
 
701
 
702
  if ( $event->multiple_days ) {
703
 
704
+ $output = ' <span class="simcal-event-start simcal-event-start-date" ' . 'data-event-start="' . $start_ts . '" ' . 'data-event-format="' . $this->calendar->date_format . '" ' . 'itemprop="startDate" content="' . $start_iso . '">' . $start->format( $this->calendar->date_format ) . '</span> ' . $time_start;
 
 
 
 
 
 
705
 
706
  if ( $end instanceof Carbon ) {
707
 
708
+ $output .= '-' . ' <span class="simcal-event-start simcal-event-end-date" ' . 'data-event-start="' . $end_ts . '" ' . 'data-event-format="' . $this->calendar->date_format . '" ' . 'itemprop="endDate" content="' . $end_iso . '">' . $end->format( $this->calendar->date_format ) . '</span> ' . $time_end;
 
 
 
 
 
 
 
709
  }
710
 
711
  } else {
713
  $time_end = ! empty( $time_start ) && ! empty( $time_end ) ? ' - ' . $time_end : '';
714
 
715
  // All-day events also need startDate for schema data.
716
+ $output = ' <span class="simcal-event-start simcal-event-start-date" ' . 'data-event-start="' . $start_ts . '" ' . 'data-event-format="' . $this->calendar->date_format . '" ' . 'itemprop="startDate" content="' . $start_iso . '">' . $start->format( $this->calendar->date_format ) . '</span> ' . $time_start . $time_end;
 
 
 
 
 
 
 
717
 
718
  }
719
 
735
  private function get_dt( $tag, Event $event, $attr ) {
736
 
737
  $bound = 0 === strpos( $tag, 'end' ) ? 'end' : 'start';
738
+
739
  if ( ( 'end' == $bound ) && ( false === $event->end ) ) {
740
  return '';
741
  }
742
 
743
  $dt = $bound . '_dt';
744
+
745
  if ( ! $event->$dt instanceof Carbon ) {
746
  return '';
747
  }
748
+
749
+ $event_dt = $event->$dt;
750
 
751
  $attr = array_merge( array(
752
+ 'format' => '',
753
  ), (array) shortcode_parse_atts( $attr ) );
754
 
755
+ $format = ltrim( strstr( $tag, '-' ), '-' );
756
  $dt_format = '';
757
+
758
  if ( ! empty( $attr['format'] ) ) {
759
  $dt_format = esc_attr( wp_strip_all_tags( $attr['format'] ) );
760
  } elseif ( 'date' == $format ) {
763
  $dt_format = $this->calendar->time_format;
764
  }
765
 
766
+ $dt_ts = $event_dt->timestamp;
767
+
768
  if ( 'human' == $format ) {
769
+ $value = human_time_diff( $dt_ts, Carbon::now( $event->timezone )->getTimestamp() );
770
 
771
+ if ( $dt_ts < Carbon::now( $event->timezone )->getTimestamp() ) {
772
  $value .= ' ' . _x( 'ago', 'human date event builder code modifier', 'google-calendar-events' );
773
  } else {
774
  $value .= ' ' . _x( 'from now', 'human date event builder code modifier', 'google-calendar-events' );
775
  }
776
  } else {
777
+ $value = $event->$dt->format( $dt_format );
778
  }
779
 
780
+ return '<span class="simcal-event-' . $bound . ' ' . 'simcal-event-' . $bound . '-' . $format . '" ' . 'data-event-' . $bound . '="' . $dt_ts . '" ' . 'data-event-format="' . $dt_format . '" ' . 'itemprop="' . $bound . 'Date" content="' . $event_dt->toIso8601String() . '">' . $value . '</span>';
 
 
 
 
 
781
  }
782
 
783
  /**
854
  private function get_attendees( $attendees, $attr ) {
855
 
856
  $attr = array_merge( array(
857
+ 'photo' => 'show', // show/hide attendee photo
858
+ 'email' => 'hide', // show/hide attendee email address
859
+ 'rsvp' => 'hide', // show/hide rsvp response status
860
+ 'response' => '', // filter attendees by rsvp response (yes/no/maybe)
861
  ), (array) shortcode_parse_atts( $attr ) );
862
 
863
  $html = '<ul class="simcal-attendees" itemprop="attendees">' . "\n\t";
864
 
865
+ $known = 0;
866
  $unknown = 0;
867
 
868
  foreach ( $attendees as $attendee ) {
877
 
878
  if ( ! empty( $attendee['name'] ) ) {
879
 
880
+ $photo = 'hide' != $attr['photo'] ? '<img class="avatar avatar-128 photo" src="' . $attendee['photo'] . '" itemprop="image" />' : '';
881
+ $response = 'hide' != $attr['rsvp'] ? $this->get_rsvp_response( $attendee['response'] ) : '';
882
+ $guest = $photo . '<span itemprop="name">' . $attendee['name'] . $response . '</span>';
883
 
884
  if ( ! empty( $attendee['email'] ) && ( 'show' == $attr['email'] ) ) {
885
  $guest = sprintf( '<a href="mailto:' . $attendee['email'] . '" itemprop="email">%s</a>', $guest );
961
  'email' => 'hide', // show/hide attendee email address
962
  ), (array) shortcode_parse_atts( $attr ) );
963
 
964
+ $photo = 'hide' != $attr['photo'] ? '<img class="avatar avatar-128 photo" src="' . $organizer['photo'] . '" itemprop="image" />' : '';
965
+ $organizer_html = $photo . '<span itemprop="name">' . $organizer['name'] . '</span>';
966
 
967
  if ( ! empty( $organizer['email'] ) && ( 'show' == $attr['email'] ) ) {
968
  $organizer_html = sprintf( '<a href="mailto:' . $organizer['email'] . '" itemprop="email">%s</a>', $organizer_html );
995
 
996
  $tagregexp = implode( '|', array_values( $this->tags ) );
997
 
998
+ return '/' . '\\[' // Opening bracket
 
999
  . '(\\[?)' // 1: Optional second opening bracket for escaping tags: [[tag]]
1000
  . "($tagregexp)" // 2: Tag name
1001
  . '(?![\\w-])' // Not followed by word character or hyphen
1002
  . '(' // 3: Unroll the loop: Inside the opening tag
1003
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash
1004
+ . '(?:' . '\\/(?!\\])' // A forward slash not followed by a closing bracket
1005
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash
1006
+ . ')*?' . ')' . '(?:' . '(\\/)' // 4: Self closing tag ...
1007
+ . '\\]' // ... and closing bracket
1008
+ . '|' . '\\]' // Closing bracket
1009
+ . '(?:' . '(' // 5: Unroll the loop: Optionally, anything between the opening and closing tags
1010
+ . '[^\\[]*+' // Not an opening bracket
1011
+ . '(?:' . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing tag
1012
+ . '[^\\[]*+' // Not an opening bracket
1013
+ . ')*+' . ')' . '\\[\\/\\2\\]' // Closing tag
1014
+ . ')?' . ')' . '(\\]?)' // 6: Optional second closing bracket for escaping tags: [[tag]]
 
 
 
 
 
 
 
 
 
 
 
1015
  . '/s';
1016
  }
1017
 
1018
+ //allow other plugins to register own event tags
1019
+ private function add_custom_event_tags() {
1020
+ $array = apply_filters( 'simcal_event_tags_add_custom', array() );
1021
+
1022
+ return $array;
1023
+ }
1024
+
1025
+ //allow other plugins to replace own (registered) event tags with their value
1026
+ private function do_custom_event_tag( $tag, $partial, $attr, $event ) {
1027
+ $returnvalue = apply_filters( 'simcal_event_tags_do_custom', "", $tag, $partial, $attr, $event );
1028
+
1029
+ return $returnvalue;
1030
+ }
1031
  }
includes/events/event.php CHANGED
@@ -318,13 +318,13 @@ class Event {
318
 
319
  if ( ! empty( $event['end'] ) ) {
320
  $this->end = is_numeric( $event['end'] ) ? intval( $event['end'] ): false;
321
- if ( ! empty( $event['end_timezone'] ) ) {
322
- $this->end_timezone = esc_attr( $event['end_timezone'] );
323
- }
324
  if ( ! empty( $event['end_utc'] ) ) {
325
  $this->end_utc = is_numeric( $event['end_utc'] ) ? intval( $event['end_utc'] ) : false;
326
- $this->end_dt = Carbon::createFromTimestamp( $this->end, $this->end_timezone );
327
  }
 
 
 
 
328
  $end_location = isset( $event['end_location'] ) ? $event['end_location'] : '';
329
  $this->end_location = $this->esc_location( $end_location );
330
  }
318
 
319
  if ( ! empty( $event['end'] ) ) {
320
  $this->end = is_numeric( $event['end'] ) ? intval( $event['end'] ): false;
 
 
 
321
  if ( ! empty( $event['end_utc'] ) ) {
322
  $this->end_utc = is_numeric( $event['end_utc'] ) ? intval( $event['end_utc'] ) : false;
 
323
  }
324
+ if ( ! empty( $event['end_timezone'] ) ) {
325
+ $this->end_timezone = esc_attr( $event['end_timezone'] );
326
+ }
327
+ $this->end_dt = Carbon::createFromTimestamp( $this->end, $this->end_timezone );
328
  $end_location = isset( $event['end_location'] ) ? $event['end_location'] : '';
329
  $this->end_location = $this->esc_location( $end_location );
330
  }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: moonstonemedia, pderksen, nickyoung87, nekojira, rosshanney
3
  Tags: google calendar, calendar, calendars, google, event calendar, custom calendar, custom calendars, event, events
4
  Requires at least: 4.2
5
  Tested up to: 4.6
6
- Stable tag: 3.1.4
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -96,6 +96,14 @@ We'd love your help! Here's a few things you can do:
96
 
97
  == Changelog ==
98
 
 
 
 
 
 
 
 
 
99
  = 3.1.4 - September 19, 2016 =
100
 
101
  * Fix: "Add to Google Calendar" link now uses source calendar's timezone (except for all-day and UTC timezone events).
3
  Tags: google calendar, calendar, calendars, google, event calendar, custom calendar, custom calendars, event, events
4
  Requires at least: 4.2
5
  Tested up to: 4.6
6
+ Stable tag: 3.1.5
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
96
 
97
  == Changelog ==
98
 
99
+ = 3.1.5 - September 25, 2016 =
100
+
101
+ * Fix: Multi-day events in the future should now display first day of event when selecting "No, display on all days of event up to current day".
102
+ * Fix: Correct dates in day headings in list view being off for some time zones.
103
+ * Tweak: Clearer warning about using timezone setting "Event source default".
104
+ * Dev: Added filters to add your own custom event template tags. Props [@Brummolix](https://github.com/Brummolix)
105
+ * Dev: Remove all calls to date_default_timezone_set() due to the way WordPress core sets it to 'UTC' to calculate offsets from there.
106
+
107
  = 3.1.4 - September 19, 2016 =
108
 
109
  * Fix: "Add to Google Calendar" link now uses source calendar's timezone (except for all-day and UTC timezone events).