Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Gets and renders iCal feeds for the Upcoming Events widget and shortcode |
||
| 5 | */ |
||
| 6 | |||
| 7 | class iCalendarReader { |
||
| 8 | |||
| 9 | public $todo_count = 0; |
||
| 10 | public $event_count = 0; |
||
| 11 | public $cal = array(); |
||
| 12 | public $_lastKeyWord = ''; |
||
| 13 | public $timezone = null; |
||
| 14 | |||
| 15 | /** |
||
| 16 | * Class constructor |
||
| 17 | * |
||
| 18 | * @return void |
||
|
0 ignored issues
–
show
|
|||
| 19 | */ |
||
| 20 | public function __construct() {} |
||
| 21 | |||
| 22 | /** |
||
| 23 | * Return an array of events |
||
| 24 | * |
||
| 25 | * @param string $url (default: '') |
||
| 26 | * @return array | false on failure |
||
| 27 | */ |
||
| 28 | public function get_events( $url = '', $count = 5 ) { |
||
| 29 | $count = (int) $count; |
||
| 30 | $transient_id = 'icalendar_vcal_' . md5( $url ) . '_' . $count; |
||
| 31 | |||
| 32 | $vcal = get_transient( $transient_id ); |
||
| 33 | |||
| 34 | if ( ! empty( $vcal ) ) { |
||
| 35 | if ( isset( $vcal['TIMEZONE'] ) ) |
||
| 36 | $this->timezone = $this->timezone_from_string( $vcal['TIMEZONE'] ); |
||
| 37 | |||
| 38 | if ( isset( $vcal['VEVENT'] ) ) { |
||
| 39 | $vevent = $vcal['VEVENT']; |
||
| 40 | |||
| 41 | if ( $count > 0 ) |
||
| 42 | $vevent = array_slice( $vevent, 0, $count ); |
||
| 43 | |||
| 44 | $this->cal['VEVENT'] = $vevent; |
||
| 45 | |||
| 46 | return $this->cal['VEVENT']; |
||
| 47 | } |
||
| 48 | } |
||
| 49 | |||
| 50 | if ( ! $this->parse( $url ) ) |
||
| 51 | return false; |
||
| 52 | |||
| 53 | $vcal = array(); |
||
| 54 | |||
| 55 | if ( $this->timezone ) { |
||
| 56 | $vcal['TIMEZONE'] = $this->timezone->getName(); |
||
| 57 | } else { |
||
| 58 | $this->timezone = $this->timezone_from_string( '' ); |
||
| 59 | } |
||
| 60 | |||
| 61 | if ( ! empty( $this->cal['VEVENT'] ) ) { |
||
| 62 | $vevent = $this->cal['VEVENT']; |
||
| 63 | |||
| 64 | // check for recurring events |
||
| 65 | // $vevent = $this->add_recurring_events( $vevent ); |
||
| 66 | |||
| 67 | // remove before caching - no sense in hanging onto the past |
||
| 68 | $vevent = $this->filter_past_and_recurring_events( $vevent ); |
||
| 69 | |||
| 70 | // order by soonest start date |
||
| 71 | $vevent = $this->sort_by_recent( $vevent ); |
||
| 72 | |||
| 73 | $vcal['VEVENT'] = $vevent; |
||
| 74 | } |
||
| 75 | |||
| 76 | set_transient( $transient_id, $vcal, HOUR_IN_SECONDS ); |
||
| 77 | |||
| 78 | if ( !isset( $vcal['VEVENT'] ) ) |
||
| 79 | return false; |
||
| 80 | |||
| 81 | if ( $count > 0 ) |
||
| 82 | return array_slice( $vcal['VEVENT'], 0, $count ); |
||
| 83 | |||
| 84 | return $vcal['VEVENT']; |
||
| 85 | } |
||
| 86 | |||
| 87 | function apply_timezone_offset( $events ) { |
||
| 88 | if ( ! $events ) { |
||
| 89 | return $events; |
||
| 90 | } |
||
| 91 | |||
| 92 | // get timezone offset from the timezone name. |
||
| 93 | $timezone_name = get_option( 'timezone_string' ); |
||
| 94 | if ( $timezone_name ) { |
||
| 95 | $timezone = new DateTimeZone( $timezone_name ); |
||
| 96 | } else { |
||
| 97 | // If the timezone isn't set then the GMT offset must be set. |
||
| 98 | // generate a DateInterval object from the timezone offset |
||
| 99 | $gmt_offset = get_option( 'gmt_offset' ) * HOUR_IN_MINUTES; |
||
| 100 | $timezone_offset_interval = date_interval_create_from_date_string( "{$gmt_offset} minutes" ); |
||
| 101 | $timezone = new DateTimeZone( 'UTC' ); |
||
| 102 | } |
||
| 103 | |||
| 104 | $offsetted_events = array(); |
||
| 105 | |||
| 106 | foreach ( $events as $event ) { |
||
| 107 | // Don't handle all-day events |
||
| 108 | if ( 8 < strlen( $event['DTSTART'] ) ) { |
||
| 109 | $start_time = preg_replace( '/Z$/', '', $event['DTSTART'] ); |
||
| 110 | $start_time = new DateTime( $start_time, $this->timezone ); |
||
| 111 | $start_time->setTimeZone( $timezone ); |
||
| 112 | |||
| 113 | $end_time = preg_replace( '/Z$/', '', $event['DTEND'] ); |
||
| 114 | $end_time = new DateTime( $end_time, $this->timezone ); |
||
| 115 | $end_time->setTimeZone( $timezone ); |
||
| 116 | |||
| 117 | if ( $timezone_offset_interval ) { |
||
| 118 | $start_time->add( $timezone_offset_interval ); |
||
| 119 | $end_time->add( $timezone_offset_interval ); |
||
| 120 | } |
||
| 121 | |||
| 122 | $event['DTSTART'] = $start_time->format( 'YmdHis\Z' ); |
||
| 123 | $event['DTEND'] = $end_time->format( 'YmdHis\Z' ); |
||
| 124 | } |
||
| 125 | |||
| 126 | $offsetted_events[] = $event; |
||
| 127 | } |
||
| 128 | |||
| 129 | return $offsetted_events; |
||
| 130 | } |
||
| 131 | |||
| 132 | protected function filter_past_and_recurring_events( $events ) { |
||
| 133 | $upcoming = array(); |
||
| 134 | $set_recurring_events = array(); |
||
| 135 | $recurrences = array(); |
||
| 136 | /** |
||
| 137 | * This filter allows any time to be passed in for testing or changing timezones, etc... |
||
| 138 | * |
||
| 139 | * @module widgets |
||
| 140 | * |
||
| 141 | * @since 3.4.0 |
||
| 142 | * |
||
| 143 | * @param object time() A time object. |
||
| 144 | */ |
||
| 145 | $current = apply_filters( 'ical_get_current_time', time() ); |
||
| 146 | |||
| 147 | foreach ( $events as $event ) { |
||
| 148 | |||
| 149 | $date_from_ics = strtotime( $event['DTSTART'] ); |
||
| 150 | View Code Duplication | if ( isset( $event['DTEND'] ) ) { |
|
| 151 | $duration = strtotime( $event['DTEND'] ) - strtotime( $event['DTSTART'] ); |
||
| 152 | } else { |
||
| 153 | $duration = 0; |
||
| 154 | } |
||
| 155 | |||
| 156 | if ( isset( $event['RRULE'] ) && $this->timezone->getName() && 8 != strlen( $event['DTSTART'] ) ) { |
||
| 157 | try { |
||
| 158 | $adjusted_time = new DateTime( $event['DTSTART'], new DateTimeZone('UTC') ); |
||
| 159 | $adjusted_time->setTimeZone( new DateTimeZone( $this->timezone->getName() ) ); |
||
| 160 | $event['DTSTART'] = $adjusted_time->format('Ymd\THis'); |
||
| 161 | $date_from_ics = strtotime( $event['DTSTART'] ); |
||
| 162 | |||
| 163 | $event['DTEND'] = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) + $duration ); |
||
| 164 | } catch ( Exception $e ) { |
||
| 165 | // Invalid argument to DateTime |
||
| 166 | } |
||
| 167 | |||
| 168 | if ( isset( $event['EXDATE'] ) ) { |
||
| 169 | $exdates = array(); |
||
| 170 | foreach ( (array) $event['EXDATE'] as $exdate ) { |
||
| 171 | try { |
||
| 172 | $adjusted_time = new DateTime( $exdate, new DateTimeZone('UTC') ); |
||
| 173 | $adjusted_time->setTimeZone( new DateTimeZone( $this->timezone->getName() ) ); |
||
| 174 | if ( 8 == strlen( $event['DTSTART'] ) ) { |
||
| 175 | $exdates[] = $adjusted_time->format( 'Ymd' ); |
||
| 176 | } else { |
||
| 177 | $exdates[] = $adjusted_time->format( 'Ymd\THis' ); |
||
| 178 | } |
||
| 179 | } catch ( Exception $e ) { |
||
| 180 | // Invalid argument to DateTime |
||
| 181 | } |
||
| 182 | } |
||
| 183 | $event['EXDATE'] = $exdates; |
||
| 184 | } else { |
||
| 185 | $event['EXDATE'] = array(); |
||
| 186 | } |
||
| 187 | } |
||
| 188 | |||
| 189 | if ( ! isset( $event['DTSTART'] ) ) { |
||
| 190 | continue; |
||
| 191 | } |
||
| 192 | |||
| 193 | // Process events with RRULE before other events |
||
| 194 | $rrule = isset( $event['RRULE'] ) ? $event['RRULE'] : false ; |
||
| 195 | $uid = $event['UID']; |
||
| 196 | |||
| 197 | if ( $rrule && ! in_array( $uid, $set_recurring_events ) ) { |
||
| 198 | |||
| 199 | // Break down the RRULE into digestible chunks |
||
| 200 | $rrule_array = array(); |
||
| 201 | |||
| 202 | foreach ( explode( ";", $event['RRULE'] ) as $rline ) { |
||
| 203 | list( $rkey, $rvalue ) = explode( "=", $rline, 2 ); |
||
| 204 | $rrule_array[$rkey] = $rvalue; |
||
| 205 | } |
||
| 206 | |||
| 207 | $interval = ( isset( $rrule_array['INTERVAL'] ) ) ? $rrule_array['INTERVAL'] : 1; |
||
| 208 | $rrule_count = ( isset( $rrule_array['COUNT'] ) ) ? $rrule_array['COUNT'] : 0; |
||
| 209 | $until = ( isset( $rrule_array['UNTIL'] ) ) ? strtotime( $rrule_array['UNTIL'] ) : strtotime( '+1 year', $current ); |
||
| 210 | |||
| 211 | // Used to bound event checks |
||
| 212 | $echo_limit = 10; |
||
| 213 | $noop = false; |
||
| 214 | |||
| 215 | // Set bydays for the event |
||
| 216 | $weekdays = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' ); |
||
| 217 | $bydays = $weekdays; |
||
| 218 | |||
| 219 | // Calculate a recent start date for incrementing depending on the frequency and interval |
||
| 220 | switch ( $rrule_array['FREQ'] ) { |
||
| 221 | |||
| 222 | case 'DAILY': |
||
| 223 | $frequency = 'day'; |
||
| 224 | $echo_limit = 10; |
||
| 225 | |||
| 226 | if ( $date_from_ics >= $current ) { |
||
| 227 | $recurring_event_date_start = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) ); |
||
| 228 | } else { |
||
| 229 | // Interval and count |
||
| 230 | $catchup = floor( ( $current - strtotime( $event['DTSTART'] ) ) / ( $interval * DAY_IN_SECONDS ) ); |
||
| 231 | if ( $rrule_count && $catchup > 0 ) { |
||
| 232 | if ( $catchup < $rrule_count ) { |
||
| 233 | $rrule_count = $rrule_count - $catchup; |
||
| 234 | $recurring_event_date_start = date( 'Ymd', strtotime( '+ ' . ( $interval * $catchup ) . ' days', strtotime( $event['DTSTART'] ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 235 | } else { |
||
| 236 | $noop = true; |
||
| 237 | } |
||
| 238 | View Code Duplication | } else { |
|
| 239 | $recurring_event_date_start = date( 'Ymd', strtotime( '+ ' . ( $interval * $catchup ) . ' days', strtotime( $event['DTSTART'] ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 240 | } |
||
| 241 | } |
||
| 242 | break; |
||
| 243 | |||
| 244 | case 'WEEKLY': |
||
| 245 | $frequency = 'week'; |
||
| 246 | $echo_limit = 4; |
||
| 247 | |||
| 248 | // BYDAY exception to current date |
||
| 249 | $day = false; |
||
| 250 | if ( ! isset( $rrule_array['BYDAY'] ) ) { |
||
| 251 | $day = $rrule_array['BYDAY'] = strtoupper( substr( date( 'D', strtotime( $event['DTSTART'] ) ), 0, 2 ) ); |
||
| 252 | } |
||
| 253 | $bydays = explode( ',', $rrule_array['BYDAY'] ); |
||
| 254 | |||
| 255 | if ( $date_from_ics >= $current ) { |
||
| 256 | $recurring_event_date_start = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) ); |
||
| 257 | } else { |
||
| 258 | // Interval and count |
||
| 259 | $catchup = floor( ( $current - strtotime( $event['DTSTART'] ) ) / ( $interval * WEEK_IN_SECONDS ) ); |
||
| 260 | if ( $rrule_count && $catchup > 0 ) { |
||
| 261 | if ( ( $catchup * count( $bydays ) ) < $rrule_count ) { |
||
| 262 | $rrule_count = $rrule_count - ( $catchup * count( $bydays ) ); // Estimate current event count |
||
| 263 | $recurring_event_date_start = date( 'Ymd', strtotime( '+ ' . ( $interval * $catchup ) . ' weeks', strtotime( $event['DTSTART'] ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 264 | } else { |
||
| 265 | $noop = true; |
||
| 266 | } |
||
| 267 | View Code Duplication | } else { |
|
| 268 | $recurring_event_date_start = date( 'Ymd', strtotime( '+ ' . ( $interval * $catchup ) . ' weeks', strtotime( $event['DTSTART'] ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 269 | } |
||
| 270 | } |
||
| 271 | |||
| 272 | // Set to Sunday start |
||
| 273 | if ( ! $noop && 'SU' !== strtoupper( substr( date( 'D', strtotime( $recurring_event_date_start ) ), 0, 2 ) ) ) { |
||
| 274 | $recurring_event_date_start = date( 'Ymd', strtotime( "last Sunday", strtotime( $recurring_event_date_start ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 275 | } |
||
| 276 | break; |
||
| 277 | |||
| 278 | case 'MONTHLY': |
||
| 279 | $frequency = 'month'; |
||
| 280 | $echo_limit = 1; |
||
| 281 | |||
| 282 | if ( $date_from_ics >= $current ) { |
||
| 283 | $recurring_event_date_start = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) ); |
||
| 284 | } else { |
||
| 285 | // Describe the date in the month |
||
| 286 | if ( isset( $rrule_array['BYDAY'] ) ) { |
||
| 287 | $day_number = substr( $rrule_array['BYDAY'], 0, 1 ); |
||
| 288 | $week_day = substr( $rrule_array['BYDAY'], 1 ); |
||
| 289 | $day_cardinals = array( 1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth' ); |
||
| 290 | $weekdays = array( 'SU' => 'Sunday', 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday' ); |
||
| 291 | $event_date_desc = "{$day_cardinals[$day_number]} {$weekdays[$week_day]} of "; |
||
| 292 | } else { |
||
| 293 | $event_date_desc = date( 'd ', strtotime( $event['DTSTART'] ) ); |
||
| 294 | } |
||
| 295 | |||
| 296 | // Interval only |
||
| 297 | if ( $interval > 1 ) { |
||
| 298 | $catchup = 0; |
||
| 299 | $maybe = strtotime( $event['DTSTART'] ); |
||
| 300 | while ( $maybe < $current ) { |
||
| 301 | $maybe = strtotime( '+ ' . ( $interval * $catchup ) . ' months', strtotime( $event['DTSTART'] ) ); |
||
| 302 | $catchup++; |
||
| 303 | } |
||
| 304 | $recurring_event_date_start = date( 'Ymd', strtotime( $event_date_desc . date( 'F Y', strtotime( '+ ' . ( $interval * ( $catchup - 1 ) ) . ' months', strtotime( $event['DTSTART'] ) ) ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 305 | View Code Duplication | } else { |
|
| 306 | $recurring_event_date_start = date( 'Ymd', strtotime( $event_date_desc . date( 'F Y', $current ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 307 | } |
||
| 308 | |||
| 309 | // Add one interval if necessary |
||
| 310 | if ( strtotime( $recurring_event_date_start ) < $current ) { |
||
| 311 | if ( $interval > 1 ) { |
||
| 312 | $recurring_event_date_start = date( 'Ymd', strtotime( $event_date_desc . date( 'F Y', strtotime( '+ ' . ( $interval * $catchup ) . ' months', strtotime( $event['DTSTART'] ) ) ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 313 | View Code Duplication | } else { |
|
| 314 | try { |
||
| 315 | $adjustment = new DateTime( date( 'Y-m-d', $current ) ); |
||
| 316 | $adjustment->modify( 'first day of next month' ); |
||
| 317 | $recurring_event_date_start = date( 'Ymd', strtotime( $event_date_desc . $adjustment->format( 'F Y' ) ) ) . date( '\THis', strtotime( $event['DTSTART'] ) ); |
||
| 318 | } catch ( Exception $e ) { |
||
| 319 | // Invalid argument to DateTime |
||
| 320 | } |
||
| 321 | } |
||
| 322 | } |
||
| 323 | } |
||
| 324 | break; |
||
| 325 | |||
| 326 | case 'YEARLY': |
||
| 327 | $frequency = 'year'; |
||
| 328 | $echo_limit = 1; |
||
| 329 | |||
| 330 | if ( $date_from_ics >= $current ) { |
||
| 331 | $recurring_event_date_start = date( "Ymd\THis", strtotime( $event['DTSTART'] ) ); |
||
| 332 | } else { |
||
| 333 | $recurring_event_date_start = date( 'Y', $current ) . date( "md\THis", strtotime( $event['DTSTART'] ) ); |
||
| 334 | View Code Duplication | if ( strtotime( $recurring_event_date_start ) < $current ) { |
|
| 335 | try { |
||
| 336 | $next = new DateTime( date( 'Y-m-d', $current ) ); |
||
| 337 | $next->modify( 'first day of next year' ); |
||
| 338 | $recurring_event_date_start = $next->format( 'Y' ) . date ( 'md\THis', strtotime( $event['DTSTART'] ) ); |
||
| 339 | } catch ( Exception $e ) { |
||
| 340 | // Invalid argument to DateTime |
||
| 341 | } |
||
| 342 | } |
||
| 343 | } |
||
| 344 | break; |
||
| 345 | |||
| 346 | default: |
||
| 347 | $frequency = false; |
||
| 348 | } |
||
| 349 | |||
| 350 | if ( $frequency !== false && ! $noop ) { |
||
| 351 | $count_counter = 1; |
||
| 352 | |||
| 353 | // If no COUNT limit, go to 10 |
||
| 354 | if ( empty( $rrule_count ) ) { |
||
| 355 | $rrule_count = 10; |
||
| 356 | } |
||
| 357 | |||
| 358 | // Set up EXDATE handling for the event |
||
| 359 | $exdates = ( isset( $event['EXDATE'] ) ) ? $event['EXDATE'] : array(); |
||
| 360 | |||
| 361 | for ( $i = 1; $i <= $echo_limit; $i++ ) { |
||
| 362 | |||
| 363 | // Weeks need a daily loop and must check for inclusion in BYDAYS |
||
| 364 | if ( 'week' == $frequency ) { |
||
| 365 | $byday_event_date_start = strtotime( $recurring_event_date_start ); |
||
| 366 | |||
| 367 | foreach ( $weekdays as $day ) { |
||
| 368 | |||
| 369 | $event_start_timestamp = $byday_event_date_start; |
||
| 370 | $start_time = date( 'His', $event_start_timestamp ); |
||
| 371 | $event_end_timestamp = $event_start_timestamp + $duration; |
||
| 372 | $end_time = date( 'His', $event_end_timestamp ); |
||
| 373 | View Code Duplication | if ( 8 == strlen( $event['DTSTART'] ) ) { |
|
| 374 | $exdate_compare = date( 'Ymd', $event_start_timestamp ); |
||
| 375 | } else { |
||
| 376 | $exdate_compare = date( 'Ymd\THis', $event_start_timestamp ); |
||
| 377 | } |
||
| 378 | |||
| 379 | View Code Duplication | if ( in_array( $day, $bydays ) && $event_end_timestamp > $current && $event_start_timestamp < $until && $count_counter <= $rrule_count && $event_start_timestamp >= $date_from_ics && ! in_array( $exdate_compare, $exdates ) ) { |
|
| 380 | if ( 8 == strlen( $event['DTSTART'] ) ) { |
||
| 381 | $event['DTSTART'] = date( 'Ymd', $event_start_timestamp ); |
||
| 382 | $event['DTEND'] = date( 'Ymd', $event_end_timestamp ); |
||
| 383 | } else { |
||
| 384 | $event['DTSTART'] = date( 'Ymd\THis', $event_start_timestamp ); |
||
| 385 | $event['DTEND'] = date( 'Ymd\THis', $event_end_timestamp ); |
||
| 386 | } |
||
| 387 | if ( $this->timezone->getName() && 8 != strlen( $event['DTSTART'] ) ) { |
||
| 388 | try { |
||
| 389 | $adjusted_time = new DateTime( $event['DTSTART'], new DateTimeZone( $this->timezone->getName() ) ); |
||
| 390 | $adjusted_time->setTimeZone( new DateTimeZone( 'UTC' ) ); |
||
| 391 | $event['DTSTART'] = $adjusted_time->format('Ymd\THis'); |
||
| 392 | |||
| 393 | $event['DTEND'] = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) + $duration ); |
||
| 394 | } catch ( Exception $e ) { |
||
| 395 | // Invalid argument to DateTime |
||
| 396 | } |
||
| 397 | } |
||
| 398 | $upcoming[] = $event; |
||
| 399 | $count_counter++; |
||
| 400 | } |
||
| 401 | |||
| 402 | // Move forward one day |
||
| 403 | $byday_event_date_start = strtotime( date( 'Ymd\T', strtotime( '+ 1 day', $event_start_timestamp ) ) . $start_time ); |
||
| 404 | } |
||
| 405 | |||
| 406 | // Restore first event timestamp |
||
| 407 | $event_start_timestamp = strtotime( $recurring_event_date_start ); |
||
| 408 | |||
| 409 | } else { |
||
| 410 | |||
| 411 | $event_start_timestamp = strtotime( $recurring_event_date_start ); |
||
| 412 | $start_time = date( 'His', $event_start_timestamp ); |
||
| 413 | $event_end_timestamp = $event_start_timestamp + $duration; |
||
| 414 | $end_time = date( 'His', $event_end_timestamp ); |
||
| 415 | View Code Duplication | if ( 8 == strlen( $event['DTSTART'] ) ) { |
|
| 416 | $exdate_compare = date( 'Ymd', $event_start_timestamp ); |
||
| 417 | } else { |
||
| 418 | $exdate_compare = date( 'Ymd\THis', $event_start_timestamp ); |
||
| 419 | } |
||
| 420 | |||
| 421 | View Code Duplication | if ( $event_end_timestamp > $current && $event_start_timestamp < $until && $count_counter <= $rrule_count && $event_start_timestamp >= $date_from_ics && ! in_array( $exdate_compare, $exdates ) ) { |
|
| 422 | if ( 8 == strlen( $event['DTSTART'] ) ) { |
||
| 423 | $event['DTSTART'] = date( 'Ymd', $event_start_timestamp ); |
||
| 424 | $event['DTEND'] = date( 'Ymd', $event_end_timestamp ); |
||
| 425 | } else { |
||
| 426 | $event['DTSTART'] = date( 'Ymd\T', $event_start_timestamp ) . $start_time; |
||
| 427 | $event['DTEND'] = date( 'Ymd\T', $event_end_timestamp ) . $end_time; |
||
| 428 | } |
||
| 429 | if ( $this->timezone->getName() && 8 != strlen( $event['DTSTART'] ) ) { |
||
| 430 | try { |
||
| 431 | $adjusted_time = new DateTime( $event['DTSTART'], new DateTimeZone( $this->timezone->getName() ) ); |
||
| 432 | $adjusted_time->setTimeZone( new DateTimeZone( 'UTC' ) ); |
||
| 433 | $event['DTSTART'] = $adjusted_time->format('Ymd\THis'); |
||
| 434 | |||
| 435 | $event['DTEND'] = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) + $duration ); |
||
| 436 | } catch ( Exception $e ) { |
||
| 437 | // Invalid argument to DateTime |
||
| 438 | } |
||
| 439 | } |
||
| 440 | $upcoming[] = $event; |
||
| 441 | $count_counter++; |
||
| 442 | } |
||
| 443 | } |
||
| 444 | |||
| 445 | // Set up next interval and reset $event['DTSTART'] and $event['DTEND'], keeping timestamps intact |
||
| 446 | $next_start_timestamp = strtotime( "+ {$interval} {$frequency}s", $event_start_timestamp ); |
||
| 447 | if ( 8 == strlen( $event['DTSTART'] ) ) { |
||
| 448 | $event['DTSTART'] = date( 'Ymd', $next_start_timestamp ); |
||
| 449 | $event['DTEND'] = date( 'Ymd', strtotime( $event['DTSTART'] ) + $duration ); |
||
| 450 | View Code Duplication | } else { |
|
| 451 | $event['DTSTART'] = date( 'Ymd\THis', $next_start_timestamp ); |
||
| 452 | $event['DTEND'] = date( 'Ymd\THis', strtotime( $event['DTSTART'] ) + $duration ); |
||
| 453 | } |
||
| 454 | |||
| 455 | // Move recurring event date forward |
||
| 456 | $recurring_event_date_start = $event['DTSTART']; |
||
| 457 | } |
||
| 458 | $set_recurring_events[] = $uid; |
||
| 459 | |||
| 460 | } |
||
| 461 | |||
| 462 | View Code Duplication | } else { |
|
| 463 | // Process normal events |
||
| 464 | if ( strtotime( isset( $event['DTEND'] ) ? $event['DTEND'] : $event['DTSTART'] ) >= $current ) { |
||
| 465 | $upcoming[] = $event; |
||
| 466 | } |
||
| 467 | } |
||
| 468 | } |
||
| 469 | return $upcoming; |
||
| 470 | } |
||
| 471 | |||
| 472 | /** |
||
| 473 | * Parse events from an iCalendar feed |
||
| 474 | * |
||
| 475 | * @param string $url (default: '') |
||
| 476 | * @return array | false on failure |
||
| 477 | */ |
||
| 478 | public function parse( $url = '' ) { |
||
| 479 | $cache_group = 'icalendar_reader_parse'; |
||
| 480 | $disable_get_key = 'disable:' . md5( $url ); |
||
| 481 | |||
| 482 | // Check to see if previous attempts have failed |
||
| 483 | if ( false !== wp_cache_get( $disable_get_key, $cache_group ) ) |
||
| 484 | return false; |
||
| 485 | |||
| 486 | // rewrite webcal: URI schem to HTTP |
||
| 487 | $url = preg_replace('/^webcal/', 'http', $url ); |
||
| 488 | // try to fetch |
||
| 489 | $r = wp_remote_get( $url, array( 'timeout' => 3, 'sslverify' => false ) ); |
||
| 490 | if ( 200 !== wp_remote_retrieve_response_code( $r ) ) { |
||
| 491 | // We were unable to fetch any content, so don't try again for another 60 seconds |
||
| 492 | wp_cache_set( $disable_get_key, 1, $cache_group, 60 ); |
||
| 493 | return false; |
||
| 494 | } |
||
| 495 | |||
| 496 | $body = wp_remote_retrieve_body( $r ); |
||
| 497 | if ( empty( $body ) ) |
||
| 498 | return false; |
||
| 499 | |||
| 500 | $body = str_replace( "\r\n", "\n", $body ); |
||
| 501 | $lines = preg_split( "/\n(?=[A-Z])/", $body ); |
||
| 502 | |||
| 503 | if ( empty( $lines ) ) |
||
| 504 | return false; |
||
| 505 | |||
| 506 | if ( false === stristr( $lines[0], 'BEGIN:VCALENDAR' ) ) |
||
| 507 | return false; |
||
| 508 | |||
| 509 | foreach ( $lines as $line ) { |
||
| 510 | $add = $this->key_value_from_string( $line ); |
||
| 511 | if ( ! $add ) { |
||
| 512 | $this->add_component( $type, false, $line ); |
||
|
0 ignored issues
–
show
The variable
$type does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
false is of type boolean, but the function expects a string.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 513 | continue; |
||
| 514 | } |
||
| 515 | list( $keyword, $value ) = $add; |
||
| 516 | |||
| 517 | switch ( $keyword ) { |
||
| 518 | case 'BEGIN': |
||
| 519 | case 'END': |
||
| 520 | switch ( $line ) { |
||
| 521 | case 'BEGIN:VTODO': |
||
| 522 | $this->todo_count++; |
||
| 523 | $type = 'VTODO'; |
||
| 524 | break; |
||
| 525 | case 'BEGIN:VEVENT': |
||
| 526 | $this->event_count++; |
||
| 527 | $type = 'VEVENT'; |
||
| 528 | break; |
||
| 529 | case 'BEGIN:VCALENDAR': |
||
| 530 | case 'BEGIN:DAYLIGHT': |
||
| 531 | case 'BEGIN:VTIMEZONE': |
||
| 532 | case 'BEGIN:STANDARD': |
||
| 533 | $type = $value; |
||
| 534 | break; |
||
| 535 | case 'END:VTODO': |
||
| 536 | case 'END:VEVENT': |
||
| 537 | case 'END:VCALENDAR': |
||
| 538 | case 'END:DAYLIGHT': |
||
| 539 | case 'END:VTIMEZONE': |
||
| 540 | case 'END:STANDARD': |
||
| 541 | $type = 'VCALENDAR'; |
||
| 542 | break; |
||
| 543 | } |
||
| 544 | break; |
||
| 545 | case 'TZID': |
||
| 546 | if ( 'VTIMEZONE' == $type && ! $this->timezone ) |
||
| 547 | $this->timezone = $this->timezone_from_string( $value ); |
||
| 548 | break; |
||
| 549 | case 'X-WR-TIMEZONE': |
||
| 550 | if ( ! $this->timezone ) |
||
| 551 | $this->timezone = $this->timezone_from_string( $value ); |
||
| 552 | break; |
||
| 553 | default: |
||
| 554 | $this->add_component( $type, $keyword, $value ); |
||
| 555 | break; |
||
| 556 | } |
||
| 557 | } |
||
| 558 | |||
| 559 | // Filter for RECURRENCE-IDs |
||
| 560 | $recurrences = array(); |
||
| 561 | if ( array_key_exists( 'VEVENT', $this->cal ) ) { |
||
| 562 | foreach ( $this->cal['VEVENT'] as $event ) { |
||
| 563 | if ( isset( $event['RECURRENCE-ID'] ) ) { |
||
| 564 | $recurrences[] = $event; |
||
| 565 | } |
||
| 566 | } |
||
| 567 | foreach ( $recurrences as $recurrence ) { |
||
| 568 | for ( $i = 0; $i < count( $this->cal['VEVENT'] ); $i++ ) { |
||
| 569 | if ( $this->cal['VEVENT'][ $i ]['UID'] == $recurrence['UID'] && ! isset( $this->cal['VEVENT'][ $i ]['RECURRENCE-ID'] ) ) { |
||
| 570 | $this->cal['VEVENT'][ $i ]['EXDATE'][] = $recurrence['RECURRENCE-ID']; |
||
| 571 | break; |
||
| 572 | } |
||
| 573 | } |
||
| 574 | } |
||
| 575 | } |
||
| 576 | |||
| 577 | return $this->cal; |
||
| 578 | } |
||
| 579 | |||
| 580 | /** |
||
| 581 | * Parse key:value from a string |
||
| 582 | * |
||
| 583 | * @param string $text (default: '') |
||
| 584 | * @return array |
||
| 585 | */ |
||
| 586 | public function key_value_from_string( $text = '' ) { |
||
| 587 | preg_match( '/([^:]+)(;[^:]+)?[:]([\w\W]*)/', $text, $matches ); |
||
| 588 | |||
| 589 | if ( 0 == count( $matches ) ) |
||
| 590 | return false; |
||
| 591 | |||
| 592 | return array( $matches[1], $matches[3] ); |
||
| 593 | } |
||
| 594 | |||
| 595 | /** |
||
| 596 | * Convert a timezone name into a timezone object. |
||
| 597 | * |
||
| 598 | * @param string $text Timezone name. Example: America/Chicago |
||
| 599 | * @return object|null A DateTimeZone object if the conversion was successful. |
||
| 600 | */ |
||
| 601 | private function timezone_from_string( $text ) { |
||
| 602 | try { |
||
| 603 | $timezone = new DateTimeZone( $text ); |
||
| 604 | } catch ( Exception $e ) { |
||
| 605 | $blog_timezone = get_option( 'timezone_string' ); |
||
| 606 | if ( ! $blog_timezone ) { |
||
| 607 | $blog_timezone = 'Etc/UTC'; |
||
| 608 | } |
||
| 609 | |||
| 610 | $timezone = new DateTimeZone( $blog_timezone ); |
||
| 611 | } |
||
| 612 | |||
| 613 | return $timezone; |
||
| 614 | } |
||
| 615 | |||
| 616 | /** |
||
| 617 | * Add a component to the calendar array |
||
| 618 | * |
||
| 619 | * @param string $component (default: '') |
||
| 620 | * @param string $keyword (default: '') |
||
| 621 | * @param string $value (default: '') |
||
| 622 | * @return void |
||
| 623 | */ |
||
| 624 | public function add_component( $component = '', $keyword = '', $value = '' ) { |
||
| 625 | if ( false == $keyword ) { |
||
| 626 | $keyword = $this->last_keyword; |
||
|
0 ignored issues
–
show
The property
last_keyword does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
| 627 | switch ( $component ) { |
||
| 628 | case 'VEVENT': |
||
| 629 | $value = $this->cal[ $component ][ $this->event_count - 1 ][ $keyword ] . $value; |
||
| 630 | break; |
||
| 631 | case 'VTODO' : |
||
| 632 | $value = $this->cal[ $component ][ $this->todo_count - 1 ][ $keyword ] . $value; |
||
| 633 | break; |
||
| 634 | } |
||
| 635 | } |
||
| 636 | |||
| 637 | /* |
||
| 638 | * Some events have a specific timezone set in their start/end date, |
||
| 639 | * and it may or may not be different than the calendar timzeone. |
||
| 640 | * Valid formats include: |
||
| 641 | * DTSTART;TZID=Pacific Standard Time:20141219T180000 |
||
| 642 | * DTEND;TZID=Pacific Standard Time:20141219T200000 |
||
| 643 | * EXDATE:19960402T010000Z,19960403T010000Z,19960404T010000Z |
||
| 644 | * EXDATE;VALUE=DATE:2015050 |
||
| 645 | * EXDATE;TZID=America/New_York:20150424T170000 |
||
| 646 | * EXDATE;TZID=Pacific Standard Time:20120615T140000,20120629T140000,20120706T140000 |
||
| 647 | */ |
||
| 648 | |||
| 649 | // Always store EXDATE as an array |
||
| 650 | if ( stristr( $keyword, 'EXDATE' ) ) { |
||
| 651 | $value = explode( ',', $value ); |
||
| 652 | } |
||
| 653 | |||
| 654 | // Adjust DTSTART, DTEND, and EXDATE according to their TZID if set |
||
| 655 | if ( strpos( $keyword, ';' ) && ( stristr( $keyword, 'DTSTART' ) || stristr( $keyword, 'DTEND' ) || stristr( $keyword, 'EXDATE' ) || stristr( $keyword, 'RECURRENCE-ID' ) ) ) { |
||
| 656 | $keyword = explode( ';', $keyword ); |
||
| 657 | |||
| 658 | $tzid = false; |
||
| 659 | if ( 2 == count( $keyword ) ) { |
||
| 660 | $tparam = $keyword[1]; |
||
| 661 | |||
| 662 | if ( strpos( $tparam, "TZID" ) !== false ) { |
||
| 663 | $tzid = $this->timezone_from_string( str_replace( 'TZID=', '', $tparam ) ); |
||
| 664 | } |
||
| 665 | } |
||
| 666 | |||
| 667 | // Normalize all times to default UTC |
||
| 668 | if ( $tzid ) { |
||
| 669 | $adjusted_times = array(); |
||
| 670 | foreach ( (array) $value as $v ) { |
||
| 671 | try { |
||
| 672 | $adjusted_time = new DateTime( $v, $tzid ); |
||
| 673 | $adjusted_time->setTimeZone( new DateTimeZone( 'UTC' ) ); |
||
| 674 | $adjusted_times[] = $adjusted_time->format('Ymd\THis'); |
||
| 675 | } catch ( Exception $e ) { |
||
| 676 | // Invalid argument to DateTime |
||
| 677 | return; |
||
| 678 | } |
||
| 679 | } |
||
| 680 | $value = $adjusted_times; |
||
| 681 | } |
||
| 682 | |||
| 683 | // Format for adding to event |
||
| 684 | $keyword = $keyword[0]; |
||
| 685 | if ( 'EXDATE' != $keyword ) { |
||
| 686 | $value = implode( (array) $value ); |
||
| 687 | } |
||
| 688 | } |
||
| 689 | |||
| 690 | foreach ( (array) $value as $v ) { |
||
| 691 | switch ($component) { |
||
| 692 | View Code Duplication | case 'VTODO': |
|
| 693 | if ( 'EXDATE' == $keyword ) { |
||
| 694 | $this->cal[ $component ][ $this->todo_count - 1 ][ $keyword ][] = $v; |
||
| 695 | } else { |
||
| 696 | $this->cal[ $component ][ $this->todo_count - 1 ][ $keyword ] = $v; |
||
| 697 | } |
||
| 698 | break; |
||
| 699 | View Code Duplication | case 'VEVENT': |
|
| 700 | if ( 'EXDATE' == $keyword ) { |
||
| 701 | $this->cal[ $component ][ $this->event_count - 1 ][ $keyword ][] = $v; |
||
| 702 | } else { |
||
| 703 | $this->cal[ $component ][ $this->event_count - 1 ][ $keyword ] = $v; |
||
| 704 | } |
||
| 705 | break; |
||
| 706 | default: |
||
| 707 | $this->cal[ $component ][ $keyword ] = $v; |
||
| 708 | break; |
||
| 709 | } |
||
| 710 | } |
||
| 711 | $this->last_keyword = $keyword; |
||
| 712 | } |
||
| 713 | |||
| 714 | /** |
||
| 715 | * Escape strings with wp_kses, allow links |
||
| 716 | * |
||
| 717 | * @param string $string (default: '') |
||
| 718 | * @return string |
||
| 719 | */ |
||
| 720 | public function escape( $string = '' ) { |
||
| 721 | // Unfold content lines per RFC 5545 |
||
| 722 | $string = str_replace( "\n\t", '', $string ); |
||
| 723 | $string = str_replace( "\n ", '', $string ); |
||
| 724 | |||
| 725 | $allowed_html = array( |
||
| 726 | 'a' => array( |
||
| 727 | 'href' => array(), |
||
| 728 | 'title' => array() |
||
| 729 | ) |
||
| 730 | ); |
||
| 731 | |||
| 732 | $allowed_tags = ''; |
||
| 733 | foreach ( array_keys( $allowed_html ) as $tag ) { |
||
| 734 | $allowed_tags .= "<{$tag}>"; |
||
| 735 | } |
||
| 736 | |||
| 737 | // Running strip_tags() first with allowed tags to get rid of remaining gallery markup, etc |
||
| 738 | // because wp_kses() would only htmlentity'fy that. Then still running wp_kses(), for extra |
||
| 739 | // safety and good measure. |
||
| 740 | return wp_kses( strip_tags( $string, $allowed_tags ), $allowed_html ); |
||
| 741 | } |
||
| 742 | |||
| 743 | /** |
||
| 744 | * Render the events |
||
| 745 | * |
||
| 746 | * @param string $url (default: '') |
||
| 747 | * @param string $context (default: 'widget') or 'shortcode' |
||
| 748 | * @return mixed bool|string false on failure, rendered HTML string on success. |
||
| 749 | */ |
||
| 750 | public function render( $url = '', $args = array() ) { |
||
| 751 | |||
| 752 | $args = wp_parse_args( $args, array( |
||
| 753 | 'context' => 'widget', |
||
| 754 | 'number' => 5 |
||
| 755 | ) ); |
||
| 756 | |||
| 757 | $events = $this->get_events( $url, $args['number'] ); |
||
| 758 | $events = $this->apply_timezone_offset( $events ); |
||
| 759 | |||
| 760 | if ( empty( $events ) ) |
||
| 761 | return false; |
||
| 762 | |||
| 763 | ob_start(); |
||
| 764 | |||
| 765 | if ( 'widget' == $args['context'] ) : ?> |
||
| 766 | <ul class="upcoming-events"> |
||
| 767 | <?php foreach ( $events as $event ) : ?> |
||
| 768 | <li> |
||
| 769 | <strong class="event-summary"><?php echo $this->escape( stripslashes( $event['SUMMARY'] ) ); ?></strong> |
||
| 770 | <span class="event-when"><?php echo $this->formatted_date( $event ); ?></span> |
||
| 771 | View Code Duplication | <?php if ( ! empty( $event['LOCATION'] ) ) : ?> |
|
| 772 | <span class="event-location"><?php echo $this->escape( stripslashes( $event['LOCATION'] ) ); ?></span> |
||
| 773 | <?php endif; ?> |
||
| 774 | View Code Duplication | <?php if ( ! empty( $event['DESCRIPTION'] ) ) : ?> |
|
| 775 | <span class="event-description"><?php echo wp_trim_words( $this->escape( stripcslashes( $event['DESCRIPTION'] ) ) ); ?></span> |
||
| 776 | <?php endif; ?> |
||
| 777 | </li> |
||
| 778 | <?php endforeach; ?> |
||
| 779 | </ul> |
||
| 780 | <?php endif; |
||
| 781 | |||
| 782 | if ( 'shortcode' == $args['context'] ) : ?> |
||
| 783 | <table class="upcoming-events"> |
||
| 784 | <thead> |
||
| 785 | <tr> |
||
| 786 | <th><?php esc_html_e( 'Location', 'jetpack' ); ?></th> |
||
| 787 | <th><?php esc_html_e( 'When', 'jetpack' ); ?></th> |
||
| 788 | <th><?php esc_html_e( 'Summary', 'jetpack' ); ?></th> |
||
| 789 | <th><?php esc_html_e( 'Description', 'jetpack' ); ?></th> |
||
| 790 | </tr> |
||
| 791 | </thead> |
||
| 792 | <tbody> |
||
| 793 | <?php foreach ( $events as $event ) : ?> |
||
| 794 | <tr> |
||
| 795 | <td><?php echo empty( $event['LOCATION'] ) ? ' ' : $this->escape( stripslashes( $event['LOCATION'] ) ); ?></td> |
||
| 796 | <td><?php echo $this->formatted_date( $event ); ?></td> |
||
| 797 | <td><?php echo empty( $event['SUMMARY'] ) ? ' ' : $this->escape( stripslashes( $event['SUMMARY'] ) ); ?></td> |
||
| 798 | <td><?php echo empty( $event['DESCRIPTION'] ) ? ' ' : wp_trim_words( $this->escape( stripcslashes( $event['DESCRIPTION'] ) ) ); ?></td> |
||
| 799 | </tr> |
||
| 800 | <?php endforeach; ?> |
||
| 801 | </tbody> |
||
| 802 | </table> |
||
| 803 | <?php endif; |
||
| 804 | |||
| 805 | $rendered = ob_get_clean(); |
||
| 806 | |||
| 807 | if ( empty( $rendered ) ) |
||
| 808 | return false; |
||
| 809 | |||
| 810 | return $rendered; |
||
| 811 | } |
||
| 812 | |||
| 813 | public function formatted_date( $event ) { |
||
| 814 | |||
| 815 | $date_format = get_option( 'date_format' ); |
||
| 816 | $time_format = get_option( 'time_format' ); |
||
| 817 | $start = strtotime( $event['DTSTART'] ); |
||
| 818 | $end = isset( $event['DTEND'] ) ? strtotime( $event['DTEND'] ) : false; |
||
| 819 | |||
| 820 | $all_day = ( 8 == strlen( $event['DTSTART'] ) ); |
||
| 821 | |||
| 822 | if ( !$all_day && $this->timezone ) { |
||
| 823 | try { |
||
| 824 | $start_time = new DateTime( $event['DTSTART'] ); |
||
| 825 | $timezone_offset = $this->timezone->getOffset( $start_time ); |
||
| 826 | $start += $timezone_offset; |
||
| 827 | |||
| 828 | if ( $end ) { |
||
| 829 | $end += $timezone_offset; |
||
| 830 | } |
||
| 831 | } catch ( Exception $e ) { |
||
| 832 | // Invalid argument to DateTime |
||
| 833 | } |
||
| 834 | } |
||
| 835 | $single_day = $end ? ( $end - $start ) <= DAY_IN_SECONDS : true; |
||
| 836 | |||
| 837 | /* Translators: Date and time */ |
||
| 838 | $date_with_time = __( '%1$s at %2$s' , 'jetpack' ); |
||
| 839 | /* Translators: Two dates with a separator */ |
||
| 840 | $two_dates = __( '%1$s – %2$s' , 'jetpack' ); |
||
| 841 | |||
| 842 | // we'll always have the start date. Maybe with time |
||
| 843 | View Code Duplication | if ( $all_day ) |
|
| 844 | $date = date_i18n( $date_format, $start ); |
||
| 845 | else |
||
| 846 | $date = sprintf( $date_with_time, date_i18n( $date_format, $start ), date_i18n( $time_format, $start ) ); |
||
| 847 | |||
| 848 | // single day, timed |
||
| 849 | if ( $single_day && ! $all_day && false !== $end ) |
||
| 850 | $date = sprintf( $two_dates, $date, date_i18n( $time_format, $end ) ); |
||
| 851 | |||
| 852 | // multi-day |
||
| 853 | if ( ! $single_day ) { |
||
| 854 | |||
| 855 | View Code Duplication | if ( $all_day ) { |
|
| 856 | // DTEND for multi-day events represents "until", not "including", so subtract one minute |
||
| 857 | $end_date = date_i18n( $date_format, $end - 60 ); |
||
| 858 | } else { |
||
| 859 | $end_date = sprintf( $date_with_time, date_i18n( $date_format, $end ), date_i18n( $time_format, $end ) ); |
||
| 860 | } |
||
| 861 | |||
| 862 | $date = sprintf( $two_dates, $date, $end_date ); |
||
| 863 | |||
| 864 | } |
||
| 865 | |||
| 866 | return $date; |
||
| 867 | } |
||
| 868 | |||
| 869 | protected function sort_by_recent( $list ) { |
||
| 870 | $dates = $sorted_list = array(); |
||
| 871 | |||
| 872 | foreach ( $list as $key => $row ) { |
||
| 873 | $date = $row['DTSTART']; |
||
| 874 | // pad some time onto an all day date |
||
| 875 | if ( 8 === strlen( $date ) ) |
||
| 876 | $date .= 'T000000Z'; |
||
| 877 | $dates[$key] = $date; |
||
| 878 | } |
||
| 879 | asort( $dates ); |
||
| 880 | foreach( $dates as $key => $value ) { |
||
| 881 | $sorted_list[$key] = $list[$key]; |
||
| 882 | } |
||
| 883 | unset($list); |
||
| 884 | return $sorted_list; |
||
| 885 | } |
||
| 886 | |||
| 887 | } |
||
| 888 | |||
| 889 | |||
| 890 | /** |
||
| 891 | * Wrapper function for iCalendarReader->get_events() |
||
| 892 | * |
||
| 893 | * @param string $url (default: '') |
||
| 894 | * @return array |
||
| 895 | */ |
||
| 896 | function icalendar_get_events( $url = '', $count = 5 ) { |
||
| 897 | // Find your calendar's address http://support.google.com/calendar/bin/answer.py?hl=en&answer=37103 |
||
| 898 | $ical = new iCalendarReader(); |
||
| 899 | return $ical->get_events( $url, $count ); |
||
| 900 | } |
||
| 901 | |||
| 902 | /** |
||
| 903 | * Wrapper function for iCalendarReader->render() |
||
| 904 | * |
||
| 905 | * @param string $url (default: '') |
||
| 906 | * @param string $context (default: 'widget') or 'shortcode' |
||
| 907 | * @return mixed bool|string false on failure, rendered HTML string on success. |
||
| 908 | */ |
||
| 909 | function icalendar_render_events( $url = '', $args = array() ) { |
||
| 910 | $ical = new iCalendarReader(); |
||
| 911 | return $ical->render( $url, $args ); |
||
| 912 | } |
||
| 913 |
Adding a
@returnannotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.