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 |
||
| 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 ); |
||
| 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; |
||
| 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' |
||
|
0 ignored issues
–
show
|
|||
| 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' |
||
|
0 ignored issues
–
show
There is no parameter named
$context. Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. Loading history...
|
|||
| 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 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italyis not defined by the methodfinale(...).The most likely cause is that the parameter was removed, but the annotation was not.