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