1 <?php
2
3 /**
4 * Handles event dates lists.
5 *
6 * Use this class to retrieve a list of event dates or a fully formatted HTML list of event dates.
7 *
8 * ## Basic usage
9 * <code>
10 * // Retrieve a list of all dates.
11 * $dates = new Theater_Dates;
12 * foreach ( $dates() as $date ) {
13 * // $date is a Theater_Date object.
14 * echo $date->title();
15 * }
16 * </code>
17 *
18 * <code>
19 * // Output a formatted list of all dates.
20 * $dates = new Theater_Dates;
21 * echo $dates;
22 * </code>
23 *
24 * ### Filtered lists
25 * You can pass extra filter arguments to customize the events that are in the list:
26 *
27 * <code>
28 * // Retrieve a list of upcoming dates.
29 * $dates = new Theater_Dates( array( 'start' => 'now' ) );
30 * </code>
31 * <code>
32 * // Retrieve a list of dates for a single event.
33 * $dates = new Theater_Dates( array( 'event' => 123 ) );
34 * </code>
35 * <code>
36 * // Retrieve a list of upcoming dates for a single event.
37 * $dates = new Theater_Dates( array( 'event' => 123, 'start' => 'now' ) );
38 * </code>
39 *
40 * See [Theater_Dates::get()](#_get) for a full list of accepted arguments.
41 *
42 * ### Customized output
43 * You can also formatting arguments to customize the HTML output of the list:
44 *
45 * <code>
46 * // Retrieve a list of upcoming dates.
47 * $dates = new Theater_Dates( array( 'start' => 'now' ) );
48 * </code>
49 *
50 * See [Theater_Dates::get_html()](#_get_html) for a full list of accepted arguments.
51 *
52 * @since 0.5
53 * @since 0.10 Complete rewrite, while maintaining backwards compatibility.
54 * @since 0.16 Another rewrite.
55 * @package Theater/Events
56 */
57
58 class Theater_Event_Date_List extends Theater_List {
59
60 /**
61 * The default filter arguments for event dates lists.
62 *
63 * @var array[string]
64 * @access protected
65 * @static
66 */
67 protected $default_args = array(
68 'cat' => false,
69 'category_name' => false,
70 'category__and' => false,
71 'category__in' => false,
72 'category__not_in' => false,
73 'tag' => false,
74 'end' => false,
75 'event' => false,
76 'limit' => false,
77 'order' => 'asc',
78 'past' => false,
79 'post__in' => false,
80 'post__not_in' => false,
81 'production' => false,
82 'season' => false,
83 's' => false,
84 'start' => false,
85 'status' => array( 'publish' ),
86 'template' => '',
87 'upcoming' => false,
88 );
89
90 /**
91 * Gets a list of event dates.
92 *
93 * ## Usage
94 * <code>
95 * // Retrieve a list of all dates.
96 * Theater_Dates::get();
97 * </code>
98 *
99 * <code>
100 * // Retrieve a list of upcoming dates for a single event.
101 * Theater_Dates::get( array( 'event' => 123, 'start' => 'now' ) );
102 * </code>
103 *
104 * ### Shorthand
105 * This method is also used if you call the `Theater_Dates` class as a function:
106 * <code>
107 * // Retrieve a list of all dates.
108 * $dates = new Theater_Dates;
109 * foreach ( $dates() as $date ) {
110 * // $date is a Theater_Date object.
111 * echo $date->title();
112 * }
113 * </code>
114 *
115 * @since 0.5
116 * @since 0.10 Renamed method from `load()` to `get()`.
117 * Added 'order' to $args.
118 * @since 0.10.14 Preload events with their productions.
119 * This dramatically decreases the number of queries needed to show a listing of events.
120 * @since 0.10.15 'Start' and 'end' $args now account for timezones.
121 * Fixes #117.
122 * @since 0.11.8 Support for 'post__in' and 'post__not_in'.
123 * Fixes #128.
124 * @since 0.13 Added support for multiple productions.
125 * @since 0.13.1 'Start' and 'end' filter explicitly set to 'NUMERIC'.
126 * Fixes #168.
127 * @since 0.15 Added support for 's' (keyword search).
128 * @since 0.16 Replaced the `production` filter with the `event` filter.
129 *
130 * @uses Theater_Dates::$default_args
131 * @uses WPT_Order::meta_key to get the key to filter when the 'start' or 'end' filter is used.
132 * @uses Theater_Date::post_type_name to get the event date post type.
133 * @uses WPT_Production::post_type_name to get the events post type if the 'event' or
134 * 's' (keyword search) filter is used.
135 * @uses WPT_Season::post_type_name to get the seasons post type if the 'season' filter is used.
136 * @uses WPT_Productions::get() to find productions if the 's' (keyword search) filter is used.
137 * @uses Theater_Date to create a new event date object for each event in the list.
138 *
139 * @param array[string] $filters An array of filter arguments. Optional.
140 *
141 * Possible argument values:
142 * | argument | type | description |
143 * | ------------------ | --------------- | ------------------------------------------------------------------------- |
144 * | `cat` | int|string | Category ID or comma-separated list of IDs. |
145 * | `category_name` | string | Category slug. |
146 * | `category__and` | string | An array of category IDs (AND in). |
147 * | `category__in` | int[] | An array of category IDs (OR in, no children). |
148 * | `category__not_in` | int[] | An array of category IDs (NOT in). |
149 * | `tag` | string | Tag slug. Comma-separated (either), Plus-separated (all). |
150 * | `end` | string | A date/time string. Only show event dates that start before this date. |
151 * | | | Valid formats are explained in |
152 * | | | [Date and Time Formats](http://php.net/manual/en/datetime.formats.php). |
153 * | `event` | int|array | Event ID of an array of event IDs. Only show dates of one or more events. |
154 * | `limit` | int | Number of dates to return. Use `-1` to show all event dates. |
155 * | `order` | string | The order in which to return the event dates. Either `ASC` or `DESC`. |
156 * | `post__in` | int[] | Array of event date IDs. |
157 * | `post__not_in` | int[] | Array of event date IDs. |
158 * | `season` | int | Season ID. Only show event dates for this season |
159 * | `s` | string | Search keyword(s). Prepending a term with a hyphen will |
160 * | | | exclude events matching that term. Eg, 'pillow -sofa' will |
161 * | | | return events containing 'pillow' but not 'sofa'. |
162 * | `start` | string | A date/time string. Only show event dates that start after this date. |
163 * | | | Valid formats are explained in |
164 * | | | [Date and Time Formats](http://php.net/manual/en/datetime.formats.php). |
165 * | `status` | array | Array of post statusses. Only show event dates of events with these |
166 * | | | statuses. |
167 *
168 * @return Theater_Date[] An array of events.
169 */
170 function get( $filters = array() ) {
171 global $wp_theatre;
172
173 /**
174 * Filter the defaults for the list of events.
175 *
176 * @since 0.11.9
177 * @param array $defaults The current defaults.
178 */
179 $defaults = apply_filters( 'wpt/events/get/defaults', $this->default_args );
180
181 $filters = wp_parse_args( $filters, $defaults );
182
183 $args = array(
184 'post_type' => Theater_Event_Date::post_type_name,
185 'post_status' => $filters['status'],
186 'meta_query' => array(),
187 'order' => $filters['order'],
188 );
189
190 /**
191 * Apply upcoming filter.
192 * Ignore when one of the other time related filters are set.
193 * Maybe deprecate in favor of `start="now"`.
194 */
195
196 if (
197 $filters['upcoming'] &&
198 ! $filters['start'] &&
199 ! $filters['end']
200 ) {
201 $filters['start'] = 'now';
202 }
203
204 if ( $filters['production'] && !$filters['event']) {
205 $filters['event'] = $filters['production'];
206 unset($filters['production']);
207 }
208
209 if ( $filters['event'] ) {
210 $args['meta_query'][] = array(
211 'key' => Theater_Event::post_type_name,
212 'value' => (array) $filters['event'],
213 'compare' => 'IN',
214 );
215 }
216 /**
217 * Apply start filter.
218 * Only show events that start after the `start` value.
219 * Can be any value that is supported by strtotime().
220 * @since 0.9
221 */
222
223 if ( $filters['start'] ) {
224 $args['meta_query'][] = array(
225 'key' => $wp_theatre->order->meta_key,
226 'value' => strtotime( $filters['start'], current_time( 'timestamp' ) ) - get_option( 'gmt_offset' ) * 3600,
227 'compare' => '>=',
228 'type' => 'NUMERIC',
229 );
230 }
231
232 /**
233 * Apply end filter.
234 * Only show events that start before the `end` value.
235 * Can be any value that is supported by strtotime().
236 * @since 0.9
237 */
238
239 if ( $filters['end'] ) {
240 $args['meta_query'][] = array(
241 'key' => $wp_theatre->order->meta_key,
242 'value' => strtotime( $filters['end'], current_time( 'timestamp' ) ) - get_option( 'gmt_offset' ) * 3600,
243 'compare' => '<=',
244 'type' => 'NUMERIC',
245 );
246 }
247
248 if ( $filters['post__in'] ) {
249 $args['post__in'] = $filters['post__in'];
250 }
251
252 if ( $filters['post__not_in'] ) {
253 $args['post__not_in'] = $filters['post__not_in'];
254 }
255
256 if($filters['s']) {
257 $productions_by_keyword_args = array(
258 's' => $filters['s'],
259 'status' => $filters['status'],
260 );
261 $productions_by_keyword = $wp_theatre->productions->get($productions_by_keyword_args);
262
263 $args['meta_query'][] = array(
264 'key' => WPT_Production::post_type_name,
265 'value' => $productions_by_keyword,
266 'compare' => 'IN',
267 );
268 }
269
270 if ( $filters['season'] ) {
271 $args['meta_query'][] = array(
272 'key' => WPT_Season::post_type_name,
273 'value' => $filters['season'],
274 'compare' => '=',
275 );
276 }
277
278 if ( $filters['cat'] ) {
279 $args['cat'] = $filters['cat'];
280 }
281
282 if ( $filters['category_name'] ) {
283 $args['category_name'] = $filters['category_name'];
284 }
285
286 if ( $filters['category__and'] ) {
287 $args['category__and'] = $filters['category__and'];
288 }
289
290 if ( $filters['category__in'] ) {
291 $args['category__in'] = $filters['category__in'];
292 }
293
294 if ( $filters['category__not_in'] ) {
295 $args['category__not_in'] = $filters['category__not_in'];
296 }
297
298 if ( $filters['tag'] ) {
299 $args['tag'] = $filters['tag'];
300 }
301
302 if ( $filters['limit'] ) {
303 $args['posts_per_page'] = $filters['limit'];
304 $args['numberposts'] = $filters['limit'];
305 } else {
306 $args['posts_per_page'] = -1;
307 $args['numberposts'] = -1;
308 }
309
310 /**
311 * Filter the $args before doing get_posts().
312 *
313 * @since 0.9.2
314 * @since 0.11.9 New filter added, with an extra 'filter' param.
315 *
316 * @param array $args The arguments to use in get_posts to retrieve events.
317 * @param array $filters The filters for the list of event dates.
318 */
319 $args = apply_filters( 'wpt_events_load_args',$args );
320 $args = apply_filters( 'wpt_events_get_args',$args );
321 $args = apply_filters( 'wpt/events/get/args', $args, $filters );
322
323 $posts = array();
324
325 /**
326 * Don't try to retrieve event dates if the 's' argument (keyword search) is used,
327 * but no events match the search.
328 */
329 if (
330 empty($filters['s']) || // True when the 's' filter is not used.
331 ! empty($productions_by_keyword) // True when the 's' filter resulted in matching productions.
332 ) {
333 $posts = get_posts( $args );
334 }
335
336 /*
337 * Use the general default template for events.
338 * @see WPT_Event_Template::get_default();
339 */
340 $template = false;
341
342 /**
343 * Filter the default template for event dates in lists.
344 *
345 * @since 0.14.6
346 * @param string $template The default template.
347 */
348 $template = apply_filters( 'theater/dates/template/default', $template );
349
350 /**
351 * @deprecated 0.16
352 */
353 $template = apply_filters( 'wpt/events/event/template/default', $template );
354
355 if ( ! empty( $filters['template'] ) ) {
356 $template = $filters['template'];
357 }
358
359 $dates = array();
360 for ( $i = 0;$i < count( $posts );$i++ ) {
361 $date = new Theater_Event_Date( $posts[ $i ], $template );
362 $dates[] = $date;
363 }
364
365 return $dates;
366 }
367
368 /**
369 * Gets an array of all categories for an event dates list.
370 *
371 * @since 0.5
372 * @since 0.10 Renamed method from `categories()` to `get_categories()`.
373 * @since 0.10.2 Now returns the slug instead of the term_id as the array keys.
374 * @since 0.10.14 Significally decreased the number of queries used.
375 *
376 * @uses Theater_Dates::get() to get a list of all event dates for a list.
377 *
378 * @param array $filters See Theater_Dates::get() for possible values.
379 * @return array[string]string An array of category slug => name pairs.
380 */
381 function get_categories( $filters = array() ) {
382 $filters['category'] = false;
383 $dates = $this->get( $filters );
384 $date_ids = wp_list_pluck( $dates, 'ID' );
385 $terms = wp_get_object_terms( $date_ids, 'category' );
386 $categories = array();
387
388 foreach ( $terms as $term ) {
389 $categories[ $term->slug ] = $term->name;
390 }
391
392 asort( $categories );
393 return $categories;
394 }
395
396 /**
397 * Gets the CSS classes for an event dates list.
398 *
399 * @uses Theater_Lists::get_classes_for_html() to retrieve the default classes for a list.
400 *
401 * @since 0.10
402 * @since 0.14.7 Added `$args` to `parent::get_classes_for_html()`.
403 *
404 * @access protected
405 * @param array $args See `Theater_Dates::get_html()` for possible values. Default: array().
406 * @return array The CSS classes.
407 */
408 protected function get_classes_for_html( $args = array() ) {
409
410 $classes = parent::get_classes_for_html( $args );
411
412 $classes[] = 'wpt_events';
413
414 // Thumbnail
415 if ( ! empty( $args['template'] ) && false === strpos( $args['template'],'{{thumbnail}}' ) ) {
416 $classes[] = 'wpt_events_without_thumbnail';
417 }
418
419 /**
420 * Filter the CSS classes.
421 *
422 * @since 0.10
423 *
424 * @param array $classes The CSS classes.
425 * @param array $args The $args that are being used for the listing.
426 * See Theater_Dates::get_html() for possible values.
427 */
428 $classes = apply_filters( 'wpt_events_classes', $classes, $args );
429
430 return $classes;
431 }
432
433 /**
434 * Gets an array of all days with event dates.
435 *
436 * @since 0.8
437 * @since 0.10 No longer limits the output to days with upcoming events.
438 * See: https://github.com/slimndap/wp-theatre/issues/75
439 * Renamed method from `days()` to `get_days()`.
440 * @since 0.10.1 Removed custom sorting. Rely on the sorting order of the events instead.
441 * @since 0.10.6 Added custom sorting again.
442 * Can't rely on sorting order of events, because historic events have no
443 * `_wpt_order` set.
444 *
445 * @uses Theater_Dates::get() to get a list of all event dates for a list.
446 *
447 * @param array $filters See `Theater_Dates::get()` for possible values.
448 * @return array Days.
449 */
450 function get_days( $filters = array() ) {
451 $dates = $this->get( $filters );
452 $days = array();
453 foreach ( $dates as $date ) {
454 $days[ date( 'Y-m-d',$date->datetime() + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ] = date_i18n( 'D j M',$date->datetime() + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
455 }
456
457 if ( ! empty( $filters['order'] ) && 'desc' == $filters['order'] ) {
458 krsort( $days );
459 } else {
460 ksort( $days );
461 }
462
463 return $days;
464 }
465
466 /**
467 * Gets a fully formatted list of event dates in HTML.
468 *
469 * The list of dates is compiled using filter arguments that are part of `$args`.
470 *
471 * ##Basic usage
472 *
473 * <code>
474 * // Output an HTML list with all dates.
475 * echo Theater_Dates::get_html();
476 * </code>
477 *
478 * <code>
479 * // Output an HTML list with upcoming dates.
480 * echo Theater_Dates::get_html( array( 'start' => 'now' ) );
481 * </code>
482 *
483 * See [Theater_Dates::get()](#_get) for possible values for `$args`.
484 *
485 * ### Customized output
486 * Additionally, it is possible to customize the output using formatting argument:
487 *
488 * <code>
489 * // Output an HTML list with a 'category' filter at the top.
490 * echo Theater_Dates::get_html( array( 'paginateby' => 'category' ) );
491 * </code>
492 *
493 * <code>
494 * // Output an HTML list with upcoming dates.
495 * echo Theater_Dates::get_html( array( 'start' => 'now' ) );
496 * </code>
497 *
498
499 * The event dates can be shown on a single page or be cut up into multiple pages by setting
500 * `$paginateby`. If `$paginateby` is set then a page navigation is added to the top of
501 * the listing.
502 *
503 * The dates can be grouped inside the pages by setting `$groupby`.
504 *
505 * @since 0.5
506 * @since 0.10 Moved parts of this method to seperate reusable methods.
507 * Renamed method from `html()` to `get_html()`.
508 * Rewrote documentation.
509 *
510 * @uses Theater_List::get_html() to generate the HTML for an event dates list.
511 *
512 * @param array[string] $args An array of arguments. Optional.
513 *
514 * The possible argument are identical to `Theater_Dates::get()`, plus the following formatting arguments:
515 *
516 *
517 * Possible argument values:
518 * | argument | type | description |
519 * | ------------------ | --------------- | ------------------------------------------------------------------------- |
520 * | `paginateby` | string[] | Array of field names to paginate the list by. |
521 * | | | Possible values: `day`, `month`, `year` and `category`. |
522 * | `groupby` | string | Field name to group the list by. |
523 * | | | Possible values: `day`, `month`, `year` and `category`. |
524 * | `template` | string | Template to use for the individual event dates. |
525 *
526 * @return string A fully formatted list of event dates in HTML.
527 */
528 function get_html( $args = array() ) {
529
530 $html = parent::get_html( $args );
531
532 /**
533 * Filter the formatted listof event dates in HTML.
534 *
535 * @since 0.10
536 *
537 * @param string $html The HTML.
538 * @param array $args The $args that are being used for the listing.
539 */
540 $html = apply_filters( 'theater/dates/html', $html, $args );
541
542 /**
543 * @deprecated 0.16
544 */
545 $html = apply_filters( 'wpt_events_html', $html, $args );
546
547 return $html;
548 }
549
550 /**
551 * Gets a list of event dates in HTML for a single category.
552 *
553 * @since 0.10
554 * @since 0.10.2 Category now uses slug instead of term_id.
555 *
556 * @uses Theater_Dates::get_html_grouped();
557 *
558 * @access protected
559 * @param string $category_slug Slug of the category.
560 * @param array $args See Theater_Dates::get_html() for possible values.
561 * @return string The HTML.
562 */
563 protected function get_html_for_category( $category_slug, $args = array() ) {
564 if ( $category = get_category_by_slug( $category_slug ) ) {
565 $args['cat'] = $category->term_id;
566 }
567
568 return $this->get_html_grouped( $args );
569 }
570
571 /**
572 * Gets a list of event dates in HTML for a single day.
573 *
574 * @since 0.10
575 *
576 * @uses Theater_Dates::get_html_grouped();
577 *
578 * @access protected
579 * @param string $day The day in `YYYY-MM-DD` format.
580 * @param array $args See Theater_Dates::get_html() for possible values.
581 * @return string The HTML.
582 */
583 protected function get_html_for_day( $day, $args = array() ) {
584
585 /*
586 * Set the `start`-filter to today.
587 * Except when the active `start`-filter is set to a later date.
588 */
589 if (
590 empty( $args['start'] ) ||
591 (strtotime( $args['start'] ) < strtotime( $day ))
592 ) {
593 $args['start'] = $day;
594 }
595
596 /*
597 * Set the `end`-filter to the next day.
598 * Except when the active `end`-filter is set to an earlier date.
599 */
600 if (
601 empty( $args['end'] ) ||
602 (strtotime( $args['end'] ) > strtotime( $day.' +1 day' ))
603 ) {
604 $args['end'] = $day.' +1 day';
605 }
606
607 return $this->get_html_grouped( $args );
608 }
609
610 /**
611 * Gets a list of event dates in HTML for a single month.
612 *
613 * @since 0.10
614 *
615 * @uses Theater_Dates::get_html_grouped();
616 *
617 * @access protected
618 * @param string $day The month in `YYYY-MM` format.
619 * @param array $args See Theater_Dates::get_html() for possible values.
620 * @return string The HTML.
621 */
622 protected function get_html_for_month( $month, $args = array() ) {
623
624 /*
625 * Set the `start`-filter to the first day of the month.
626 * Except when the active `start`-filter is set to a later date.
627 */
628 if (
629 empty( $args['start'] ) ||
630 (strtotime( $args['start'] ) < strtotime( $month ))
631 ) {
632 $args['start'] = $month;
633 }
634
635 /*
636 * Set the `end`-filter to the first day of the next month.
637 * Except when the active `end`-filter is set to an earlier date.
638 */
639 if (
640 empty( $args['end'] ) ||
641 (strtotime( $args['end'] ) > strtotime( $month.' +1 month' ))
642 ) {
643 $args['end'] = $month.' +1 month';
644 }
645
646 return $this->get_html_grouped( $args );
647 }
648
649 /**
650 * Gets a list of event dates in HTML for a single year.
651 *
652 * @since 0.10
653 *
654 * @uses Theater_Dates::get_html_grouped();
655 *
656 * @access protected
657 * @param string $day The year in `YYYY` format.
658 * @param array $args See Theater_Dates::get_html() for possible values.
659 * @return string The HTML.
660 */
661 protected function get_html_for_year( $year, $args = array() ) {
662
663 /*
664 * Set the `start`-filter to the first day of the year.
665 * Except when the active `start`-filter is set to a later date.
666 */
667 if (
668 empty( $args['start'] ) ||
669 (strtotime( $args['start'] ) < strtotime( $year.'-01-01' ))
670 ) {
671 $args['start'] = $year.'-01-01';
672 }
673
674 /*
675 * Set the `end`-filter to the first day of the next year.
676 * Except when the active `end`-filter is set to an earlier date.
677 */
678 if (
679 empty( $args['end'] ) ||
680 (strtotime( $args['end'] ) > strtotime( $year.'-01-01 +1 year' ))
681 ) {
682 $args['end'] = $year.'-01-01 +1 year';
683 }
684
685 return $this->get_html_grouped( $args );
686 }
687
688 /**
689 * Gets a list of event dates in HTML for a page.
690 *
691 * @since 0.10
692 *
693 * @uses Theater_Dates::get_html_grouped()
694 * @uses Theater_Dates::get_html_for_year()
695 * @uses Theater_Dates::get_html_for_month()
696 * @uses Theater_Dates::get_html_for_day()
697 * @uses Theater_Dates::get_html_for_category()
698 *
699 * @access protected
700 * @param array $args See Theater_Dates::get_html() for possible values.
701 * @return string The HTML.
702 */
703 protected function get_html_for_page( $args = array() ) {
704 global $wp_query;
705
706 $html = '';
707
708 /*
709 * Check if the user used the page navigation to select a particular page.
710 * Then revert to the corresponding Theater_Dates::get_html_for_* method.
711 * @see Theater_Dates::get_html_page_navigation().
712 */
713
714 if ( ! empty( $wp_query->query_vars['wpt_year'] ) ) {
715 $html = $this->get_html_for_year( $wp_query->query_vars['wpt_year'], $args );
716 } elseif ( ! empty( $wp_query->query_vars['wpt_month'] ) ) {
717 $html = $this->get_html_for_month( $wp_query->query_vars['wpt_month'], $args );
718 } elseif ( ! empty( $wp_query->query_vars['wpt_day'] ) ) {
719 $html = $this->get_html_for_day( $wp_query->query_vars['wpt_day'], $args );
720 } elseif ( ! empty( $wp_query->query_vars['wpt_category'] ) ) {
721 $html = $this->get_html_for_category( $wp_query->query_vars['wpt_category'], $args );
722 } else {
723 /*
724 * The user didn't select a page.
725 * Show the full listing.
726 */
727 $html = $this->get_html_grouped( $args );
728 }
729
730 /**
731 * Filter the HTML for a page in an event dates list.
732 *
733 * @since 0.12.2
734 * @param string $html_group The HTML for this page.
735 * @param array $args The arguments for the HTML for a page in this event dates list.
736 */
737 $html = apply_filters( 'theater/dates/html/page', $html, $args );
738
739 /**
740 * @deprecated 0.16
741 */
742 $html = apply_filters( 'wpt/events/html/page', $html, $args );
743
744 return $html;
745 }
746
747 /**
748 * Gets a grouped list of event dates in HTML.
749 *
750 * The event dates can be grouped inside a page by setting $groupby.
751 * If $groupby is not set then all events are show in a single, ungrouped list.
752 *
753 * @since 0.10
754 * @since 0.14.7 Added $args to $event->html().
755 *
756 * @uses Theater_Dates::$default_args_for_html
757 * @uses Theater_Dates::html()
758 * @uses Theater_Dates::get_html_for_month()
759 * @uses Theater_Dates::get_html_for_day()
760 * @uses Theater_Dates::get_html_for_category()
761 * @uses Theater_Dates::get()
762 * @uses Theater_Dates::preload_dates_with_events()
763 * @uses Theater_Date::get_html() to get the HTML output of an event date.
764 *
765 * @access protected
766 * @param array $args See Theater_Dates::get_html() for possible values.
767 * @return string The HTML.
768 */
769 protected function get_html_grouped( $args = array() ) {
770
771 $args = wp_parse_args( $args, $this->default_args_for_html );
772
773 /*
774 * Get the `groupby` setting and remove it from $args.
775 * $args can now be passed on to any of the other `get_html_*`-methods safely
776 * without the risk of creating grouped listings within grouped listings.
777 */
778 $groupby = $args['groupby'];
779 $args['groupby'] = false;
780
781 $html = '';
782 switch ( $groupby ) {
783 case 'day':
784 $days = $this->get_days( $args );
785 foreach ( $days as $day => $name ) {
786 if ( $day_html = $this->get_html_for_day( $day, $args ) ) {
787
788 $day_header = date_i18n( 'l d F',strtotime( $day ) );
789 $day_header = apply_filters( 'theater/dates/group/day', $day_header, $day );
790
791 /**
792 * @deprecated 0.16
793 */
794 $day_header = apply_filters( 'wpt_listing_group_day', $day_header, $day );
795
796 ob_start();
797 ?><h3 class="wpt_listing_group day"><?php echo $day_header; ?></h3><?php
798 echo $day_html;
799
800 $html .= ob_get_clean();
801
802 }
803 }
804 break;
805 case 'month':
806 $months = $this->get_months( $args );
807 foreach ( $months as $month => $name ) {
808 if ( $month_html = $this->get_html_for_month( $month, $args ) ) {
809
810 $month_header = date_i18n( 'F',strtotime( $month ) );
811 $month_header = apply_filters( 'theater/dates/group/month',$month_header,$month );
812
813 /**
814 * @deprecated 0.16
815 */
816 $month_header = apply_filters( 'wpt_listing_group_month',$month_header,$month );
817
818 ob_start();
819 ?><h3 class="wpt_listing_group month"><?php echo $month_header; ?></h3><?php
820 echo $month_html;
821
822 $html .= ob_get_clean();
823 }
824 }
825 break;
826 case 'year':
827 $years = $this->get_years( $args );
828 foreach ( $years as $year => $name ) {
829 if ( $year_html = $this->get_html_for_year( $year, $args ) ) {
830
831 $year_header = date_i18n( 'Y',strtotime( $year.'-01-01' ) );
832
833 $year_header = apply_filters( 'theater/dates/group/year',$year_header,$year );
834
835 /**
836 * @deprecated 0.16
837 */
838 $year_header = apply_filters( 'wpt_listing_group_year',$year_header,$year );
839
840 ob_start();
841 ?><h3 class="wpt_listing_group year"><?php echo $year_header; ?></h3><?php
842 echo $year_html;
843
844 $html .= ob_get_clean();
845 }
846 }
847 break;
848 case 'category':
849 $categories = $this->get_categories( $args );
850 foreach ( $categories as $cat_id => $name ) {
851 if ( $cat_html = $this->get_html_for_category( $cat_id, $args ) ) {
852
853 $cat_header = $name;
854 $cat_header = apply_filters( 'theater/dates/group/category',$cat_header,$cat_id );
855
856 /**
857 * @deprecated 0.16
858 */
859 $cat_header = apply_filters( 'wpt_listing_group_category',$cat_header,$cat_id );
860
861 ob_start();
862 ?><h3 class="wpt_listing_group category"><?php echo $cat_header; ?></h3><?php
863 echo $cat_html;
864
865 $html .= ob_get_clean();
866
867 }
868 }
869 break;
870 default:
871 $events = $this->get( $args );
872 $events = $this->preload_dates_with_events( $events );
873 $html_group = '';
874
875 foreach ( $events as $event ) {
876
877 $html_event = $event->get_html();
878
879 /**
880 * Filters the event HTML in lists.
881 *
882 * @since 0.14.6
883 *
884 * @param string $html_event The event HTML.
885 * @param Theater_Date $event The event.
886 */
887 $html_event = apply_filters( 'theater/dates/date/html', $html_event, $event );
888
889 /**
890 * @deprecated 0.16
891 */
892 $html_event = apply_filters( 'wpt/events/event/html', $html_event, $event );
893
894 $html_group .= $html_event;
895 }
896
897 /**
898 * Filter the HTML for a group in a list.
899 *
900 * @since 0.12.2
901 * @param string $html_group The HTML for this group.
902 * @param array $args The arguments for the HTML of this listing.
903 */
904 $html_group = apply_filters( 'theater/dates/group/html', $html_group, $args );
905
906 /**
907 * @deprecated 0.16
908 */
909 $html_group = apply_filters( 'wpt/events/html/grouped/group', $html_group, $args );
910
911 $html .= $html_group;
912 }
913 return $html;
914 }
915
916 /**
917 * Gets the page navigation for an event dates list in HTML.
918 *
919 * @since 0.10
920 * @since 0.13.4 Show the pagination filters in the same order as the
921 * the 'paginateby' argument.
922 *
923 * @access protected
924 * @uses Theater_Dates::get_pagination_filters()
925 * @uses Theater_List::filter_pagination()
926 * @param array $args The arguments being used for the event listing.
927 * See Theater_Dates::get_html() for possible values.
928 * @return string The HTML for the page navigation.
929 */
930 protected function get_html_page_navigation( $args = array() ) {
931 global $wp_query;
932
933 $html = '';
934
935 $paginateby = empty( $args['paginateby'] ) ? array() : $args['paginateby'];
936
937 $filters = $this->get_pagination_filters();
938
939 foreach ( $filters as $filter_name => $filter_options ) {
940 if ( ! empty( $wp_query->query_vars[ $filter_options['query_arg'] ] ) ) {
941 $paginateby[] = $filter_name;
942 }
943 }
944
945 $paginateby = array_unique( $paginateby );
946
947 foreach ( $paginateby as $paginateby_filter ) {
948 $options = call_user_func_array(
949 $filters[ $paginateby_filter ]['callback'],
950 array( $args )
951 );
952 $html .= $this->filter_pagination(
953 $paginateby_filter,
954 $options,
955 $args
956 );
957 }
958
959 /**
960 * Filter the HTML of the page navigation for an event dates list.
961 *
962 * @since 0.13.3
963 * @param string $html The HTML of the page navigation for an event listing.
964 * @param array $args The arguments being used for the event listing.
965 */
966 $html = apply_filters( 'theater/dates/navigation/html', $html, $args );
967
968 /**
969 * @deprecated 0.16
970 */
971 $html = apply_filters( 'wpt/events/html/page/navigation', $html, $args );
972
973 return $html;
974 }
975
976 /**
977 * Gets all months that have events.
978 *
979 * @since 0.5
980 * @since 0.10 No longer limits the output to months with upcoming events.
981 * See: https://github.com/slimndap/wp-theatre/issues/75
982 * Renamed method from `months()` to `get_months()`.
983 * @since 0.10.1 Removed custom sorting. Rely on the sorting order of the events instead.
984 * @since 0.10.6 Added custom sorting again.
985 * Can't rely on sorting order of events, because historic events have no
986 * `_wpt_order` set.
987 *
988 * @uses Theater_Dates::get() to get a list of all event dates for a list.
989 * @uses Theater_Date::datetime()
990 *
991 * @param array $filters See Theater_Dates::get() for possible values.
992 * @return array Months.
993 */
994 function get_months( $filters = array() ) {
995 $events = $this->get( $filters );
996 $months = array();
997 foreach ( $events as $event ) {
998 $months[ date( 'Y-m',$event->datetime() + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ] = date_i18n( 'M Y',$event->datetime() + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
999 }
1000
1001 if ( ! empty( $filters['order'] ) && 'desc' == $filters['order'] ) {
1002 krsort( $months );
1003 } else {
1004 ksort( $months );
1005 }
1006
1007 return $months;
1008 }
1009
1010 /**
1011 * Gets the pagination filters for an event listing.
1012 *
1013 * @since 0.13.4
1014 * @uses Theater_Dates::get_pagination_filters()
1015 * @return array The pagination filters for an event listing.
1016 */
1017 protected function get_pagination_filters() {
1018
1019 $filters = parent::get_pagination_filters();
1020
1021 $filters['day'] = array(
1022 'title' => __( 'Days', 'theatre' ),
1023 'query_arg' => 'wpt_day',
1024 'callback' => array( __CLASS__, 'get_days' ),
1025 );
1026
1027 $filters['month'] = array(
1028 'title' => __( 'Months', 'theatre' ),
1029 'query_arg' => 'wpt_month',
1030 'callback' => array( __CLASS__, 'get_months' ),
1031 );
1032
1033 $filters['year'] = array(
1034 'title' => __( 'Years', 'theatre' ),
1035 'query_arg' => 'wpt_year',
1036 'callback' => array( __CLASS__, 'get_years' ),
1037 );
1038
1039 $filters['category'] = array(
1040 'title' => __( 'Categories', 'theatre' ),
1041 'query_arg' => 'wpt_category',
1042 'callback' => array( __CLASS__, 'get_categories' ),
1043 );
1044
1045 /**
1046 * Filter the pagination filters for an event listing.
1047 *
1048 * @since 0.13.4
1049 * @param array $filters The current pagination filters for an event listing..
1050 */
1051 $filters = apply_filters( 'theater/dates/pagination/filters', $filters );
1052
1053 /**
1054 * @deprecated 0.16
1055 */
1056 $filters = apply_filters( 'wpt/events/pagination/filters', $filters );
1057
1058 return $filters;
1059 }
1060
1061 /**
1062 * Gets all distincs years for an event dates list.
1063 *
1064 * @since 0.10
1065 * @since 0.10.1 Removed custom sorting. Rely on the sorting order of the events instead.
1066 * @since 0.10.6 Added custom sorting again.
1067 * Can't rely on sorting order of events, because historic events have no
1068 * `_wpt_order` set.
1069 *
1070 * @uses Theater_Dates::get() to get a list of all event dates for a list.
1071 * @uses Theater_Date::datetime()
1072 *
1073 * @param array $filters See Theater_Dates::get() for possible values.
1074 * @return array Years.
1075 */
1076 function get_years( $filters = array() ) {
1077 $events = $this->get( $filters );
1078 $years = array();
1079 foreach ( $events as $event ) {
1080 $years[ date( 'Y',$event->datetime() + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ] = date_i18n( 'Y',$event->datetime() + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
1081 }
1082
1083 if ( ! empty( $filters['order'] ) && 'desc' == $filters['order'] ) {
1084 krsort( $years );
1085 } else {
1086 ksort( $years );
1087 }
1088
1089 return $years;
1090 }
1091
1092 /**
1093 * Preloads dates with their events.
1094 *
1095 * Sets the event of a each date in a list of event dates with a single query.
1096 * This dramatically decreases the number of queries needed to show a list of event dates.
1097 *
1098 * @since 0.10.14
1099 * @access private
1100 * @uses WPT_Production::post_type_name
1101 * @uses Theater_Date::$ID
1102 * @uses Theater_Date::$production
1103 * @uses WPT_Production
1104 * @param Theater_Date[] $events An array of Theater_Date objects.
1105 * @return Theater_Date[] An array of Theater_Date objects, with the event preloaded.
1106 */
1107 protected function preload_dates_with_events( $dates ) {
1108
1109 $event_ids = array();
1110
1111 foreach ( $dates as $date ) {
1112 $event_ids[] = get_post_meta( $date->ID, WPT_Production::post_type_name, true );
1113 }
1114
1115 $event_ids = array_unique( $event_ids );
1116
1117 $events = get_posts(
1118 array(
1119 'post_type' => WPT_Production::post_type_name,
1120 'post__in' => array_unique( $event_ids ),
1121 'posts_per_page' => -1,
1122 )
1123 );
1124
1125 $events_with_keys = array();
1126
1127 foreach ( $events as $event ) {
1128 $events_with_keys[ $event->ID ] = $event;
1129 }
1130
1131 for ( $i = 0; $i < count( $dates );$i++ ) {
1132 $event_id = get_post_meta( $dates[ $i ]->ID, WPT_Production::post_type_name, true );
1133 if ( in_array( $event_id, array_keys( $events_with_keys ) ) ) {
1134 $dates[ $i ]->event = new WPT_Production( $events_with_keys[ $event_id ] );
1135 }
1136 }
1137 return $dates;
1138 }
1139
1140 /**
1141 * @deprecated 0.10
1142 * @see Theater_Dates::get_categories()
1143 */
1144 function categories( $filters = array() ) {
1145 _deprecated_function( 'Theater_Dates::categories()', '0.10', 'Theater_Dates::get_categories()' );
1146 return selfget_categories( $filters );
1147 }
1148
1149 /**
1150 * @deprecated 0.10
1151 * @see Theater_Dates::get_days()
1152 */
1153 function days( $filters = array() ) {
1154 _deprecated_function( 'Theater_Dates::days()', '0.10', 'Theater_Dates::get_days()' );
1155 return $this->get_days( $filters );
1156 }
1157
1158 /**
1159 * Gets the last event date.
1160 *
1161 * @since 0.8
1162 * @deprecated 0.16
1163 * @return Theater_Date|bool The last event date or <false> if no event date is found.
1164 */
1165 function last() {
1166 _deprecated_function( 'Theater_Dates::months()', '0.16', 'Theater_Dates( array(\'limit\' => 0, \'order\' => \'DESC\') )' );
1167
1168 $args = array(
1169 'post_type' => Theater_Date::post_type_name,
1170 'post_status' => 'publish',
1171 'order' => 'desc',
1172 'posts_per_page' => 1,
1173 );
1174
1175 $events = get_posts( $args );
1176
1177 if ( empty( $events ) ) {
1178 return false;
1179 } else {
1180 return new Theater_Date( $events[0] );
1181 }
1182 }
1183
1184 /**
1185 * @deprecated 0.10
1186 * @see Theater_Dates::get_months()
1187 */
1188 function months( $filters = array() ) {
1189 _deprecated_function( 'Theater_Dates::months()', '0.10', 'Theater_Dates::get_months()' );
1190 return $this->get_months( $filters );
1191 }
1192 }
1193 ?>
1194