PluginProbe
Radio Station by netmix® – Manage and play your Show Schedule in WordPress! / trunk
Radio Station by netmix® – Manage and play your Show Schedule in WordPress! vtrunk
2.7.1 trunk 2.2.6 2.2.7 2.2.8 2.3.0 2.3.1 2.3.2 2.3.3 2.3.3.1 2.3.3.2 2.3.3.3 2.3.3.4 2.3.3.5 2.3.3.6 2.3.3.7 2.3.3.8 2.3.3.9 2.4.0 2.4.0.3 2.4.0.4 2.4.0.5 2.4.0.6 2.4.0.7 2.4.0.8 All 44 releases
radio-station / includes / shortcodes.php

shortcodes.php in Radio Station by netmix® – Manage and play your Show Schedule in WordPress! trunk, at includes/shortcodes.php

4,815 lines 178.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /* Shortcode for displaying the current song
4 * Since 2.0.0
5 */
6
7 // note: Master Schedule Shortcode in /includes/master-schedule.php
8
9 // === Time Shortcodes ===
10 // - Radio Timezone Shortcode
11 // - Radio Clock Shortcode
12 // === Archive Shortcodes ===
13 // - Archive List Shortcode Router
14 // - Archive List Shortcode Abstract
15 // - Show Archive Shortcode
16 // - Playlist Archive Shortcode
17 // - Override Archive Shortcode
18 // - Genre Archive Shortcode
19 // - Language Archive Shortcode
20 // - Archive Pagination Javascript
21 // === Show Related Shortcodes ===
22 // - Show List Shortcode Abstract
23 // - Show Posts Archive Shortcode
24 // - Show Overrides Archive Shortcode
25 // - Show Playlists Archive Shortcode
26 // - Show Lists Pagination Javascript
27 // === Widget Shortcodes ===
28 // - Current Show Shortcode
29 // - AJAX Current Show Loader
30 // - Upcoming Shows Shortcode
31 // - AJAX Upcoming Shows Shortcode
32 // - Current Playlist Shortcode
33 // =-AJAX Current Playlist Loader
34 // - Countdown Script
35 // === Legacy Shortcodes ===
36 // - Show List Shortcode
37 // - Show Playlist Shortcode
38
39
40 // -----------------------
41 // === Time Shortcodes ===
42 // -----------------------
43
44 // --------------------
45 // Get Timezone Display
46 // --------------------
47 // 2.5.18: added for use by both clock and timezone shortcodes
48 function radio_station_get_timezone_display( $timezone, $atts ) {
49
50 // --- get radio timezone values ---
51 if ( !$timezone || ( '' == $timezone ) ) {
52 // --- fallback to WordPress timezone ---
53 $timezone = get_option( 'timezone_string' );
54 if ( false !== strpos( $timezone, 'Etc/GMT' ) ) {
55 $timezone = '';
56 }
57 if ( '' == $timezone ) {
58 $offset = get_option( 'gmt_offset' );
59 if ( !$offset || ( 0 == $offset ) ) {
60 $offset = '';
61 } elseif ( $offset > 0 ) {
62 $offset = '+' . $offset;
63 }
64 // 2.5.0: added square brackets around UTC timezone display
65 $timezone_display = '[' . __( 'UTC', 'radio-station' ) . ' ' . $offset . ']';
66 }
67 } elseif ( strstr( $timezone, 'UTC' ) ) {
68 // 2.5.0: added fallback for returned UTC timezone string
69 $utc = __( 'UTC', 'radio-station' );
70 if ( strstr( $timezone, 'UTC-') ) {
71 $timezone_display = '[' . str_replace( 'UTC-', $utc . ' -', $timezone ) . ']';
72 } else {
73 $timezone_display = '[' . str_replace( 'UTC', $utc . ' +', $timezone ) . ']';
74 }
75 }
76
77 if ( !isset( $timezone_display ) ) {
78
79 // --- get offset and code from timezone location ---
80 $datetimezone = new DateTimeZone( $timezone );
81 $offset = $datetimezone->getOffset( new DateTime() );
82 if ( 0 == $offset ) {
83 $utc_offset = '[' . __( 'UTC', 'radio-station' ) . ']';
84 } else {
85 $offset = round( $offset / 60 / 60 );
86 if ( strstr( (string) $offset, '.' ) ) {
87 if ( substr( $offset, - 2, 2 ) == '.5' ) {
88 $offset = str_replace( '.5', ':30', $offset );
89 } elseif ( substr( $offset, - 3, 3 ) == '.75' ) {
90 $offset = str_replace( '.75', ':45', $offset );
91 } elseif ( substr( $offset, - 3, 3 ) == '.25' ) {
92 $offset = str_replace( '.25', ':15', $offset );
93 }
94 }
95 if ( $offset > 0 ) {
96 $utc_offset = '[' . __( 'UTC', 'radio-station' ) . '+' . $offset . ']';
97 } else {
98 $utc_offset = '[' . __( 'UTC', 'radio-station' ) . $offset . ']';
99 }
100 }
101 $code = radio_station_get_timezone_code( $timezone );
102 // 2.3.2: display full timezone location as well
103 // $location = str_replace( '/', ', ', $timezone );
104 $loc = explode( '/', $timezone );
105 $region = str_replace( '_', ' ', $loc[0] );
106 $location = str_replace( '_', ' ', $loc[1] );
107
108 // 2.5.18: display based on specified attributes
109 $timezone_display = '';
110 if ( $atts['code'] ) {
111 $timezone_display .= $code . ' ';
112 }
113 if ( $atts['region'] || $atts['location'] ) {
114 if ( $atts['code'] ) {
115 $timezone_display .= '(';
116 }
117 if ( $atts['location'] ) {
118 $timezone_display .= $location;
119 }
120 if ( $atts['region'] && $atts['location'] ) {
121 $timezone_display .= ', ';
122 }
123 if ( $atts['region'] ) {
124 $timezone_display .= $region;
125 }
126 if ( $atts['code'] ) {
127 $timezone_display .= ')';
128 }
129 }
130 if ( $atts['offset'] ) {
131 $timezone_display .= ' ' . $utc_offset;
132 }
133 }
134
135 return $timezone_display;
136 }
137
138 // ------------------------
139 // Radio Timezone Shortcode
140 // ------------------------
141 add_shortcode( 'radio-timezone', 'radio_station_timezone_shortcode' );
142 function radio_station_timezone_shortcode( $atts = array() ) {
143
144 global $radio_station_data;
145
146 // 2.5.0: added shortcode_atts call for filtering
147 $defaults = array();
148 $atts = shortcode_atts( $defaults, $atts, 'radio-timezone' );
149
150 // --- set shortcode instance ---
151 // 2.5.0: simplified instance data
152 if ( !isset( $radio_station_data['instances']['timezone_shortcode'] ) ) {
153 $radio_station_data['instances']['timezone_shortcode'] = 0;
154 }
155 $radio_station_data['instances']['timezone_shortcode']++;
156 $instance = $radio_station_data['instances']['timezone_shortcode'];
157
158 // 2.5.18: allow for timezone attribute override
159 $timezone = radio_station_get_timezone();
160 $defaults = array(
161 'timezone' => $timezone,
162 'code' => 1,
163 'region' => 1,
164 'location' => 1,
165 'offset' => 1,
166 'channel' => '',
167 );
168 // 2.5.18: added filter for default attributes
169 $defaults = apply_filters( 'radio_station_timezone_default_atts', $defaults );
170 $atts = shortcode_atts( $defaults, $atts, 'radio-timezone' );
171 $timezone = $atts['timezone'];
172
173 // --- set timezone display and format ---
174 // 2.5.18: added for display consistency
175 $timezone_display = radio_station_get_timezone_display( $timezone, $atts );
176 $timezone_format = (string) $atts['code'] . '-' . (string) $atts['region'] . '-' . (string) $atts['location'] . '-' . (string) $atts['offset'];
177
178 // --- set shortcode output ---
179 // 2.5.0: added instance ID to timezone div wrapper
180 $output = '<div id="radio-timezone-' . esc_attr( $instance ) . '" class="radio-timezone-wrapper">' . "\n";
181
182 // --- radio timezone ---
183 $output .= '<div class="radio-timezone-title">' . "\n";
184 $output .= esc_html( __( 'Radio Timezone', 'radio-station' ) ) . "\n";
185 $output .= ':</div> ' . "\n";
186 // 2.5.18: added data-timezone attribute
187 $output .= '<div class="radio-timezone" data-format="' . esc_attr( $timezone_format ) . '" data-timezone="' . esc_attr( $timezone ) . '">' . "\n";
188 $output .= esc_html( $timezone_display ) . "\n";
189 $output .= '</div><br>' . "\n";
190
191 // --- user timezone ---
192 // 2.3.3.9: change span elements to divs
193 $output .= '<div class="radio-user-timezone-title">' . "\n";
194 $output .= esc_html( __( 'Your Timezone', 'radio-station' ) ) . "\n";
195 $output .= ':</div> ' . "\n";
196 $output .= '<div class="radio-user-timezone" data-format="' . esc_attr( $timezone_format ) . '"></div>' . "\n";
197
198 $output .= '</div>' . "\n";
199
200 // --- enqueue shortcode styles ---
201 // 2.3.2: added for timezone shortcode styles
202 radio_station_enqueue_style( 'shortcodes' );
203
204 // --- filter and return ---
205 $output = apply_filters( 'radio_station_timezone_shortcode', $output, $atts, $instance );
206 return $output;
207 }
208
209 // ---------------------
210 // Radio Clock Shortcode
211 // ---------------------
212 add_shortcode( 'radio-clock', 'radio_station_clock_shortcode' );
213 function radio_station_clock_shortcode( $atts = array() ) {
214
215 global $radio_station_data;
216
217 // --- set shortcode instance ---
218 // 2.5.0: simplified instance data
219 if ( !isset( $radio_station_data['instances']['clock_shortcode'] ) ) {
220 $radio_station_data['instances']['clock_shortcode'] = 0;
221 }
222 $radio_station_data['instances']['clock_shortcode']++;
223 $instance = $radio_station_data['instances']['clock_shortcode'];
224
225 // 2.3.3: use plugin setting if time format attribute is empty
226 // 2.5.0: fix to update time attribute to time_format
227 if ( isset( $atts['time'] ) ) {
228 if ( '' != trim( $atts['time'] ) ) {
229 $atts['time_format'] = $atts['time'];
230 }
231 unset( $atts['time'] );
232 }
233
234 // --- merge default attributes ---
235 // 2.3.3: fix to incorrect setting key (clock_format)
236 // 2.5.18: add optional timezone attribute override
237 // 2.5.18: added optional timezone display attributes
238 $time_format = radio_station_get_setting( 'clock_time_format' );
239 $timezone = radio_station_get_timezone();
240 $defaults = array(
241 'time_format' => $time_format,
242 'timezone' => $timezone,
243 'code' => 1,
244 'region' => 1,
245 'location' => 1,
246 'offset' => 1,
247 'day' => 'full', // full / short / none
248 'date' => 1,
249 'month' => 'full', // full / short / none
250 'zone' => 1,
251 'seconds' => 1,
252 'widget' => 0,
253 'channel' => '',
254 );
255 // 2.5.18: added default attributes filter
256 $defaults = apply_filters( 'radio_station_clock_default_atts', $defaults );
257 $atts = shortcode_atts( $defaults, $atts, 'radio-clock' );
258
259 // --- set timezone display and format ---
260 // 2.5.18: added for display consistency
261 $timezone_display = radio_station_get_timezone_display( $timezone, $atts );
262 $timezone_format = (string) $atts['code'] . '-' . (string) $atts['region'] . '-' . (string) $atts['location'] . '-' . (string) $atts['offset'];
263
264 // --- set clock display classes ---
265 $classes = array( 'radio-station-clock' );
266 if ( $atts['widget'] ) {
267 $classes[] = 'radio-station-clock-widget';
268 } else {
269 $classes[] = 'radio-station-clock-shortcode';
270 }
271 if ( 24 == (int) $atts['time_format'] ) {
272 $classes[] = 'format-24';
273 } else {
274 $classes[] = 'format-12';
275 }
276 if ( $atts['seconds'] ) {
277 $classes[] = 'seconds';
278 }
279 if ( $atts['day'] ) {
280 if ( 'full' == $atts['day'] ) {
281 $classes[] = 'day';
282 } elseif ( 'short' == $atts['day'] ) {
283 $classes[] = 'day-short';
284 }
285 }
286 if ( $atts['date'] ) {
287 $classes[] = 'date';
288 }
289 if ( $atts['month'] ) {
290 if ( 'full' == $atts['month'] ) {
291 $classes[] = 'month';
292 } elseif ( 'short' == $atts['month'] ) {
293 $classes[] = 'month-short';
294 }
295 }
296 if ( $atts['zone'] ) {
297 $classes[] = 'zone';
298 }
299
300 // -- open clock div ---
301 $classlist = implode( ' ', $classes );
302 $clock = '<div id="radio-station-clock-' . esc_attr( $instance ) . '" class="' . esc_attr( $classlist ) . '">' . "\n";
303
304 // --- server clock ---
305 $clock .= '<div class="radio-station-server-clock">' . "\n";
306 $clock .= '<div class="radio-clock-title">' . "\n";
307 $clock .= esc_html( __( 'Radio Time', 'radio-station' ) );
308 $clock .= ':</div>' . "\n";
309 $clock .= '<div class="radio-server-time" data-format="' . esc_attr( $atts['time_format'] ) . '"></div>' . "\n";
310 $clock .= '<div class="radio-server-date"></div>' . "\n";
311 // 2.5.18: added data-timezone attribute
312 $clock .= '<div class="radio-server-zone" data-format="' . esc_attr( $timezone_format ) . '" data-timezone="' . esc_attr( $timezone ) . '"></div>' . "\n";
313 $clock .= '</div>' . "\n";
314
315 // --- user clock ---
316 $clock .= '<div class="radio-station-user-clock">' . "\n";
317 $clock .= '<div class="radio-clock-title">' . "\n";
318 $clock .= esc_html( __( 'Your Time', 'radio-station' ) );
319 $clock .= ':</div>' . "\n";
320 $clock .= '<div class="radio-user-time" data-format="' . esc_attr( $atts['time_format'] ) . '"></div>' . "\n";
321 $clock .= '<div class="radio-user-date"></div>' . "\n";
322 $clock .= '<div class="radio-user-zone" data-format="' . esc_attr( $timezone_format ) . '"></div>' . "\n";
323 $clock .= '</div>' . "\n";
324
325 $clock .= '</div>' . "\n";
326
327 // --- enqueue shortcode styles ---
328 radio_station_enqueue_style( 'shortcodes' );
329
330 // --- enqueue clock javascript ---
331 radio_station_enqueue_script( 'radio-station-clock', array(), true );
332
333 // --- filter and return ---
334 $clock = apply_filters( 'radio_station_clock', $clock, $atts, $instance );
335 return $clock;
336 }
337
338
339 // --------------------------
340 // === Archive Shortcodes ===
341 // --------------------------
342
343 // -----------------------------
344 // Archive List Shortcode Router
345 // -----------------------------
346 function radio_station_archive_list( $atts ) {
347
348 if ( 'shows' == $atts['archive_type'] ) {
349 return radio_station_show_archive_list( $atts );
350 } elseif ( 'overrides' == $atts['archive_type'] ) {
351 return radio_station_override_archive_list( $atts );
352 } elseif ( 'playlists' == $atts['archive_type'] ) {
353 return radio_station_playlist_archive_list( $atts );
354 } elseif ( 'genres' == $atts['archive_type'] ) {
355 return radio_station_genre_archive_list( $atts );
356 } elseif ( 'languages' == $atts['archive_type'] ) {
357 return radio_station_language_archive_list( $atts );
358 }
359
360 // --- filter and return ---
361 $output = apply_filters( 'radio_station_archive_list', '', $atts );
362 return $output;
363 }
364
365 // -------------------------------
366 // Archive List Shortcode Abstract
367 // -------------------------------
368 // (handles Shows, Overrides, Playlists etc.)
369 function radio_station_archive_list_shortcode( $post_type, $atts ) {
370
371 global $radio_station_data;
372
373 // --- set type from post type ---
374 $type = str_replace( 'rs-', '', $post_type );
375
376 // --- set shortcode instance ---
377 if ( !isset( $radio_station_data['instances'][$type . '-archive-list'] ) ) {
378 $radio_station_data['instances'][$type . '-archive-list'] = 0;
379 }
380 $radio_station_data['instances'][$type . '-archive-list']++;
381 $instance = $radio_station_data['instances'][$type . '-archive-list'];
382
383 // --- get clock time format ---
384 $time_format = radio_station_get_setting( 'clock_time_format' );
385
386 // 2.5.0: fix for old settings names
387 if ( isset( $atts['time'] ) ) {
388 if ( '' != trim( $atts['time'] ) ) {
389 $atts['time_format'] = $atts['time'];
390 }
391 unset( $atts['time'] );
392 }
393
394 // --- merge defaults with passed attributes ---
395 // 2.3.3.9: add atts for specific posts
396 // 2.4.0.4: added optional view attribute
397 // 2.4.1.8: change default view value to list
398 $defaults = array(
399 // --- shortcode display ----
400 'description' => 'excerpt',
401 'hide_empty' => 0,
402 'time_format' => $time_format,
403 'view' => 'list',
404 // --- taxonomy queries ---
405 'genre' => '',
406 'language' => '',
407 // --- query args ---
408 'orderby' => 'title',
409 'order' => 'ASC',
410 'status' => 'publish',
411 'perpage' => -1,
412 'offset' => 0,
413 'pagination' => 1,
414 // --- shows only ---
415 'with_shifts' => 1,
416 // 'show_shifts' => 0,
417 // --- for overrides only ---
418 'show_dates' => 1,
419 // --- for shows and overrides ---
420 // 'display_genres' => 0,
421 // 'display_languages' => 0,
422 'show_avatars' => 1,
423 'thumbnails' => 0,
424 // --- for playlists ---
425 // 'track_count' => 0,
426 // 'display_tracks' => 0,
427 // --- specific posts ---
428 'show' => false,
429 'override' => false,
430 'playlist' => false,
431 // --- channel ---
432 'channel' => '',
433 );
434
435 // 2.4.1.8: change default description value for grid view
436 if ( isset( $atts['view'] ) && ( 'grid' == $atts['view'] ) ) {
437 $defaults['description'] = 'none';
438 }
439
440 // --- handle possible pagination offset ---
441 // 2.5.0: fix to work by offset
442 if ( isset( $atts['perpage'] ) && ( $atts['perpage'] > 0 ) ) {
443 if ( !isset( $atts['offset'] ) ) {
444 if ( isset( $_REQUEST['offset'] ) ) {
445 $atts['offset'] = absint( $_REQUEST['offset'] );
446 } elseif ( get_query_var( 'page' ) ) {
447 $page = absint( get_query_var( 'page' ) );
448 if ( $page > -1 ) {
449 $atts['offset'] = (int) $atts['perpage'] * $page;
450 }
451 }
452 }
453 }
454
455 // --- process shortcode attributes ---
456 // 2.5.18: added default attributes filter
457 $defaults = apply_filters( 'radio_station_archive_default_atts', $defaults );
458 $atts = shortcode_atts( $defaults, $atts, $post_type . '-archive' );
459 if ( RADIO_STATION_DEBUG ) {
460 echo '<span style="display:none;">' . esc_html( $type ) . ' Archive Shortcode Atts: ' . esc_html( print_r( $atts, true ) ) . '</span>' . "\n";
461 }
462
463 // --- get published shows ---
464 // 2.3.3.9: ignore offset and limit and reapply later
465 $args = array(
466 'post_type' => $post_type,
467 'post_status' => $atts['status'],
468 'numberposts' => -1,
469 // 'numberposts' => $atts['perpage'],
470 // 'offset' => $atts['offset'],
471 'orderby' => $atts['orderby'],
472 'order' => $atts['order'],
473 );
474
475 // --- extra queries for shows ---
476 if ( RADIO_STATION_SHOW_SLUG == $post_type ) {
477
478 if ( $atts['with_shifts'] ) {
479
480 // --- active shows with shifts ---
481 $args['meta_query'] = array(
482 'relation' => 'AND',
483 array(
484 'key' => 'show_sched',
485 'compare' => 'EXISTS',
486 ),
487 array(
488 'key' => 'show_active',
489 'value' => 'on',
490 'compare' => '=',
491 ),
492 );
493
494 } else {
495
496 // --- just active shows ---
497 $args['meta_query'] = array(
498 array(
499 'key' => 'show_active',
500 'value' => 'on',
501 'compare' => '=',
502 ),
503 );
504 }
505 }
506
507 // 2.5.0: added missing override meta query check
508 if ( RADIO_STATION_OVERRIDE_SLUG == $post_type ) {
509 if ( $atts['with_shifts'] ) {
510 $args['meta_query'] = array(
511 array(
512 'key' => 'show_override_sched',
513 'compare' => 'EXISTS',
514 ),
515 );
516 }
517 }
518
519 // --- specific genres taxonomy query ---
520 if ( !empty( $atts['genre'] ) && in_array( $post_type, array( RADIO_STATION_SHOW_SLUG, RADIO_STATION_OVERRIDE_SLUG ) ) ) {
521
522 // --- check for provided genre(s) as slug or ID ---
523 if ( strstr( $atts['genre'], ',' ) ) {
524 $atts['genre'] = explode( ',', $atts['genre'] );
525 }
526 $args['tax_query'] = array(
527 'relation' => 'OR',
528 array(
529 'taxonomy' => RADIO_STATION_GENRES_SLUG,
530 'field' => 'slug',
531 'terms' => $atts['genre'],
532 ),
533 array(
534 'taxonomy' => RADIO_STATION_GENRES_SLUG,
535 'field' => 'ID',
536 'terms' => $atts['genre'],
537 ),
538 );
539 }
540
541 // --- specific languages taxonomy query ---
542 // 2.3.0: added language taxonomy support
543 if ( !empty( $atts['language'] ) && in_array( $post_type, array( RADIO_STATION_SHOW_SLUG, RADIO_STATION_OVERRIDE_SLUG ) ) ) {
544
545 // --- check for provided genre(s) as slug or ID ---
546 if ( strstr( $atts['language'], ',' ) ) {
547 $atts['language'] = explode( ',', $atts['language'] );
548 }
549
550 if ( !isset( $args['tax_query'] ) ) {
551 $args['tax_query'] = array( 'relation' => 'OR' );
552 }
553 $args['tax_query'][] = array(
554 'taxonomy' => RADIO_STATION_LANGUAGES_SLUG,
555 'field' => 'slug',
556 'terms' => $atts['language'],
557 );
558 $args['tax_query'][] = array(
559 'taxonomy' => RADIO_STATION_LANGUAGES_SLUG,
560 'field' => 'ID',
561 'terms' => $atts['language'],
562 );
563 }
564
565 // 2.3.3.9: allow for selective post specifications
566 // 2.4.0: fix selective posts for default (false)
567 if ( ( RADIO_STATION_SHOW_SLUG == $post_type ) && isset( $atts['show'] ) && $atts['show'] ) {
568 $args['include'] = explode( ',', $atts['show'] );
569 } elseif ( ( RADIO_STATION_OVERRIDE_SLUG == $post_type ) && isset( $atts['override'] ) && $atts['override'] ) {
570 $args['include'] = explode( ',', $atts['override'] );
571 } elseif ( ( RADIO_STATION_PLAYLIST_SLUG == $post_type ) && isset( $atts['playlist'] ) && $atts['playlist'] ) {
572 $args['include'] = explode( ',', $atts['playlist'] );
573 }
574
575 // --- get posts via query ---
576 // 2.5.0: added atts as second argument to filters
577 $args = apply_filters( 'radio_station_' . $type . '_archive_post_args', $args, $atts );
578 $archive_posts = get_posts( $args );
579
580 // --- process playlist taxonomy query ---
581 if ( RADIO_STATION_PLAYLIST_SLUG == $post_type ) {
582 // 2.3.3.9: added missing check for matching archive post results
583 if ( $archive_posts && is_array( $archive_posts ) && ( count( $archive_posts ) > 0 ) ) {
584
585 // --- check assigned show has a specified genre term ---
586 if ( !empty( $atts['genre'] ) && $archive_posts && ( count( $archive_posts ) > 0 ) ) {
587 if ( is_array( $atts['genre'] ) ) {
588 $genres = $atts['genre'];
589 } else {
590 $genres = explode( ',', $atts['genre'] );
591 }
592 foreach ( $archive_posts as $i => $archive_post ) {
593 $found_genre = false;
594 $show_id = get_post_meta( $archive_post->ID, 'playlist_show_id', true );
595 if ( $show_id ) {
596 $show_genres = wp_get_post_terms( $show_id, RADIO_STATION_GENRES_SLUG );
597 if ( $show_genres ) {
598 foreach ( $show_genres as $show_genre ) {
599 if ( in_array( $show_genre->term_id, $genres ) || in_array( $show_genre->slug, $genres) ) {
600 $found_genre = true;
601 }
602 }
603 }
604 }
605 if ( !$found_genre ) {
606 unset( $archive_posts[$i] );
607 }
608 }
609 }
610
611 // --- check assigned show has a specified language term ---
612 if ( !empty( $atts['language'] ) && $archive_posts && ( count( $archive_posts ) > 0 ) ) {
613 if ( is_array( $atts['language'] ) ) {$languages = $atts['language'];}
614 else {$languages = explode( ',', $atts['language'] );}
615 foreach ( $archive_posts as $i => $archive_post ) {
616 $found_language = false;
617 $show_id = get_post_meta( $archive_post->ID, 'playlist_show_id', true );
618 if ( $show_id ) {
619 $show_languages = wp_get_post_terms( $show_id, RADIO_STATION_LANGUAGES_SLUG );
620 if ( $show_languages ) {
621 foreach ( $show_languages as $show_language ) {
622 if ( in_array( $show_language->term_id, $languages ) || in_array( $show_language->slug, $languages ) ) {
623 $found_language = true;
624 }
625 }
626 }
627 }
628 if ( !$found_language ) {
629 unset( $archive_posts[$i] );
630 }
631 }
632 }
633
634 }
635 }
636
637 // --- check override dates ---
638 // (overrides without a date set will not be displayed)
639 if ( RADIO_STATION_OVERRIDE_SLUG == $post_type ) {
640 if ( $archive_posts && is_array( $archive_posts ) && ( count( $archive_posts ) > 0 ) ) {
641 foreach( $archive_posts as $i => $archive_post ) {
642 // 2.3.3.9: set singular to false to allow for multiple override times
643 $override_times = get_post_meta( $archive_post->ID, 'show_override_sched', true );
644 // 2.3.3.9: convert possible single override to array
645 if ( $override_times && is_array( $override_times ) && array_key_exists( 'date', $override_times ) ) {
646 $override_times = array( $override_times );
647 }
648 if ( !$override_times || !is_array( $override_times ) || ( count( $override_times ) == 0 ) ) {
649 unset( $archive_posts[$i] );
650 } else {
651 // 2.3.3.9: check if all override times are disabled
652 $enabled = count( $override_times );
653 foreach ( $override_times as $override_time ) {
654 if ( isset( $override_time['disabled'] ) && ( 'yes' == $override_time['disabled'] ) ) {
655 $enabled--;
656 }
657 }
658 // 2.5.8 : fix to double count bug
659 if ( 0 == $enabled ) {
660 unset( $archive_posts[$i] );
661 }
662 }
663 }
664 }
665 }
666
667 // 2.5.0: move archive posts filter to after show taxonomy/override date checks
668 $archive_posts = apply_filters( 'radio_station_' . $type . '_archive_posts', $archive_posts, $atts );
669 if ( RADIO_STATION_DEBUG ) {
670 echo '<span style="display:none;">Archive Shortcode: ' . "\b";
671 echo 'Args: ' . esc_html( print_r( $args, true ) ) . "\n";
672 echo 'Posts: ' . esc_html( print_r( $archive_posts, true ) ) . "\n";
673 echo '</span>' . "\n";
674 }
675
676 // --- set time data formats ---
677 // 2.3.0: added once-off meridiem pre-conversions
678 // 2.3.2: replaced meridiem conversions with data formats
679 // 2.4.0.6: added filter for default time format separator
680 $time_separator = ':';
681 $time_separator = apply_filters( 'radio_station_time_separator', $time_separator, $post_type . '-archive', $atts );
682 if ( 24 == (int) $atts['time_format'] ) {
683 $start_data_format = $end_data_format = 'H' . $time_separator . 'i';
684 } else {
685 $start_data_format = $end_data_format = 'g' . $time_separator . 'i a';
686 }
687 $start_data_format = 'j F, ' . $start_data_format;
688 $start_data_format = apply_filters( 'radio_station_time_format_start', $start_data_format, $post_type . '-archive', $atts );
689 $end_data_format = apply_filters( 'radio_station_time_format_end', $end_data_format, $post_type . '-archive', $atts );
690
691 // --- check for results ---
692 if ( !$archive_posts || !is_array( $archive_posts ) || ( count( $archive_posts ) == 0 ) ) {
693 if ( $atts['hide_empty'] ) {
694 return '';
695 }
696 $post_count = 0;
697 } else {
698
699 // --- count total archive posts ---
700 $post_count = count( $archive_posts );
701
702 // --- manually apply offset and perpage limit ---
703 // 2.3.3.9: added to enable pagination count
704 // 2.5.0: fix by removing post count resets
705 if ( ( $atts['offset'] > 0 ) && ( $atts['perpage'] > 0 ) ) {
706 if ( $post_count > $atts['offset'] ) {
707 $offset_posts = array();
708 foreach ( $archive_posts as $i => $archive_post ) {
709 if ( count( $offset_posts ) < $atts['perpage'] ) {
710 if ( ( $i + 1 ) > $atts['offset'] ) {
711 $offset_posts[] = $archive_post;
712 }
713 }
714 }
715 $archive_posts = $offset_posts;
716 if ( RADIO_STATION_DEBUG ) {
717 echo '<span style="display:none;">Offset Archive Posts: ' . esc_html( print_r( $archive_posts ) ) . '</span>' . "\n";
718 }
719 } else {
720 $archive_posts = array();
721 }
722 } elseif ( ( $atts['perpage'] > 0 ) && ( $post_count > $atts['perpage'] ) ) {
723 // 2.5.0: fix to per page pagination
724 foreach ( $archive_posts as $i => $archive_post ) {
725 if ( ( $i + 1 ) > $atts['perpage'] ) {
726 unset( $archive_posts[$i] );
727 }
728 }
729 }
730 }
731
732 // --- output list or no results message ---
733 // 2.4.0.4: remove rs- prefix from element classes
734 // 2.4.0.4: maybe add view class
735 // 2.5.0: add generic radio-archives class
736 // 2.5.0: always add view class
737 $classes = array( 'radio-archive', $type . '-archives' );
738 $classes[] = $atts['view'];
739 $class_list = implode( ' ', $classes );
740 // 2.5.0: add element ID for archive shortcode instance
741 $list = '<div id="' . esc_attr( $type ) . '-archives-' . esc_attr( $instance ) . '" class="' . esc_attr( $class_list ) . '">';
742 if ( !$archive_posts || !is_array( $archive_posts ) || ( count( $archive_posts ) == 0 ) ) {
743
744 // --- no shows messages ----
745 $message = '';
746 if ( RADIO_STATION_SHOW_SLUG == $post_type ) {
747 // 2.3.3.9: improve messages if genre / language specificed
748 if ( ( !empty( $atts['genre'] ) ) && ( !empty( $atts['genre'] ) ) ) {
749 $message = __( 'No Shows in the requested Genre and Language were found.', 'radio-station' );
750 } elseif ( !empty( $atts['genre'] ) ) {
751 $message = __( 'No Shows in the requested Genre were found.', 'radio-station' );
752 } elseif ( !empty( $atts['language'] ) ) {
753 $message = __( 'No Shows in the requested Language were found.', 'radio-station' );
754 } else {
755 $message = __( 'No Shows were found to display.', 'radio-station' );
756 }
757 } elseif ( RADIO_STATION_PLAYLIST_SLUG == $post_type ) {
758 $message = __( 'No Playlists were found to display.', 'radio-station' );
759 } elseif ( RADIO_STATION_OVERRIDE_SLUG == $post_type ) {
760 $message = __( 'No Overrides were found to display.', 'radio-station' );
761 }
762
763 // 2.3.3.9: filter message to allow for other possible types
764 $message = apply_filters( 'radio_station_archive_shortcode_no_records', $message, $post_type, $atts );
765 $list .= esc_html( $message );
766
767 } else {
768
769 // --- filter excerpt length and more ---
770 $length = apply_filters( 'radio_station_archive_' . $type. '_list_excerpt_length', false );
771 $more = apply_filters( 'radio_station_archive_' . $type . '_list_excerpt_more', '[&hellip;]' );
772
773 // --- archive list ---
774 // 2.5.0: added generic radio-archive-list class
775 $list .= '<ul class="radio-archive-list ' . esc_attr( $type ) . '-archive-list">' . "\n";
776
777 // --- set info keys ---
778 // (note: meta is dates for overrides, shifts for shows, tracks for playlists etc.)
779 $infokeys = array( 'avatar', 'title', 'meta', 'genres', 'languages', 'description', 'custom' );
780 $infokeys = apply_filters( 'radio_station_archive_shortcode_info_order', $infokeys, $post_type, $atts );
781
782 // --- loop post archive ---
783 foreach ( $archive_posts as $i => $archive_post ) {
784
785 $info = array();
786
787 // --- map archive data to variables ---
788 // 2.3.3.9: added to allow overriding by override linked show data
789 $post_id = $image_post_id = $archive_post->ID;
790 $title = $archive_post->post_title;
791 $permalink = get_permalink( $archive_post->ID );
792 $post_content = $archive_post->post_content;
793 $post_excerpt = $archive_post->post_excerpt;
794
795 // --- check linked Show for overrides ---
796 if ( RADIO_STATION_OVERRIDE_SLUG == $post_type ) {
797 $linked_show = get_post_meta( $archive_post->ID, 'linked_show_id', true );
798 if ( $linked_show ) {
799
800 // --- overridc particular fields with linked show data ---
801 $show_post = get_post( $linked_show );
802 $show_fields = get_post_meta( $post_id, 'linked_show_fields', true );
803 if ( !isset( $show_fields['show_title'] ) || !$show_fields['show_title'] ) {
804 $title = $show_post->post_title;
805 }
806 if ( !isset( $show_fields['show_content'] ) || !$show_fields['show_content'] ) {
807 $post_content = $show_post->post_content;
808 $post_excerpt = $show_post->post_excerpt;
809 }
810 if ( !isset( $show_fields['show_avatar'] ) || !$show_fields['show_avatar'] ) {
811 $image_post_id = get_post_meta( $linked_show, 'show_avatar', true );
812 }
813
814 }
815 }
816
817 $list .= '<li class="' . esc_attr( $type ) . '-archive-item">' . "\n";
818
819 // --- show avatar or thumbnail fallback ---
820 $info['avatar'] = '<div class="' . esc_attr( $type ) . '-archive-item-thumbnail">' . "\n";
821 $show_avatar = false;
822 if ( $atts['show_avatars'] && in_array( $post_type, array( RADIO_STATION_SHOW_SLUG, RADIO_STATION_OVERRIDE_SLUG ) ) ) {
823 $attr = array( 'class' => esc_attr( $type ) . '-thumbnail-image' );
824 $show_avatar = radio_station_get_show_avatar( $image_post_id, 'thumbnail', $attr );
825 }
826 if ( $show_avatar ) {
827 $info['avatar'] .= $show_avatar;
828 } elseif ( $atts['thumbnails'] ) {
829 if ( has_post_thumbnail( $image_post_id ) ) {
830 // 2.4.0.4: use attr not atts to prevent possible shortcode variable conflict
831 $attr = array( 'class' => esc_attr( $type ) . '-thumbnail-image' );
832 $thumbnail = get_the_post_thumbnail( $image_post_id, 'thumbnail', $attr );
833 $info['avatar'] .= $thumbnail;
834 }
835 }
836 $info['avatar'] .= "\n" . '</div>' . "\n";
837
838 // --- title ----
839 $info['title'] = '<div class="' . esc_attr( $type ) . '-archive-item-title">' . "\n";
840 $info['title'] .= '<a href="' . esc_url( $permalink ) . '">' . "\n";
841 $info['title'] .= esc_html( $title ) . "\n";
842 $info['title'] .= '</a>' . "\n";
843 $info['title'] .= '</div>' . "\n";
844
845 // 2.5.0: added meta div open wrapper
846 $info['meta'] = '<div class="' . esc_attr( $type ) . '-archive-item-meta">' . "\n";
847
848 // --- display Override date(s) ---
849 if ( ( RADIO_STATION_OVERRIDE_SLUG == $post_type ) && ( $atts['show_dates'] ) ) {
850
851 // 2.3.3.9: set third attribute to false to allow for multiple override times
852 $override_times = get_post_meta( $archive_post->ID, 'show_override_sched', true );
853 // 2.3.3.9: convert possible single value to array
854 if ( $override_times && is_array( $override_times ) && array_key_exists( 'date', $override_times ) ) {
855 $override_times = array( $override_times );
856 }
857
858 // 2.3.1: fix to append not echo override date to archive list
859 $info['meta'] .= '<div class="override-archive-date">' . "\n";
860
861 foreach ( $override_times as $override_time ) {
862
863 // 2.3.3.9: added check if override time/date is disabled
864 if ( !isset( $override_time['disabled'] ) || ( 'yes' != $override_time['disabled'] ) ) {
865
866 // --- convert date info ---
867 // 2.3.2: replace strtotime with to_time for timezones
868 // 2.3.2: fix to convert to 24 hour format first
869 $date_time = radio_station_to_time( $override_time['date'] );
870 // $day = radio_station_get_time( 'day', $date_time );
871 // $display_day = radio_station_translate_weekday( $day );
872 $start = $override_time['start_hour'] . ':' . $override_time['start_min'] . ' ' . $override_time['start_meridian'];
873 $end = $override_time['end_hour'] . ':' . $override_time['end_min'] . ' ' . $override_time['end_meridian'];
874 $start_time = radio_station_convert_shift_time( $start );
875 $end_time = radio_station_convert_shift_time( $end );
876 // 2.5.8: fix to use date instead of day key
877 $shift_start_time = radio_station_to_time( $override_time['date'] . ' ' . $start_time );
878 $shift_end_time = radio_station_to_time( $override_time['date'] . ' ' . $end_time );
879 // 2.3.3.9: added or equals to operator
880 if ( $shift_end_time <= $shift_start_time ) {
881 $shift_end_time = $shift_end_time + ( 24 * 60 * 60 );
882 }
883
884 // --- convert shift times ---
885 // 2.3.2: use time formats with translations
886 $start = radio_station_get_time( $start_data_format, $shift_start_time );
887 $end = radio_station_get_time( $end_data_format, $shift_end_time );
888 $start = radio_station_translate_time( $start );
889 $end = radio_station_translate_time( $end );
890
891 // 2.4.0.6: use filtered shift separator
892 $separator = ' - ';
893 $separator = apply_filters( 'radio_station_show_times_separator', $separator, 'override' );
894
895 // 2.3.1: fix to append not echo override date to archive list
896 $info['meta'] .= '<span class="rs-time rs-start-time" data="' . esc_attr( $shift_start_time ) . '" data-format="' . esc_attr( $start_data_format ) . '">' . esc_html( $start ) . '</span>' . "\n";
897 $info['meta'] .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
898 $info['meta'] .= '<span class="rs-time rs-end-time" data="' . esc_attr( $shift_end_time ) . '" data-format="' . esc_attr( $end_data_format ) . '">' . esc_html( $end ) . '</span>' . "\n";
899 $info['meta'] .= '<br>' . "\n";
900
901 }
902 }
903
904 $info['meta'] .= '</div>' . "\n";
905 }
906
907 // TODO: display Show shifts meta
908 /* if ( ( RADIO_STATION_SHOW_SLUG == $post_type ) && ( $atts['show_shifts'] ) ) {
909 $shifts = radio_station_get_show_schedule( $post_id );
910 if ( $shifts && is_array( $shifts ) && ( count( $shifts ) > 0 ) ) {
911 foreach ( $shifts as $i => $shift ) {
912 $info['meta'] .= '';
913 }
914 }
915 } */
916
917 // TODO: playlist tracks / track count meta
918 /* if ( ( RADIO_STATION_PLAYLIST_SLUG == $post_type ) && $atts['display_tracks'] ) {
919 $tracks = get_post_meta( $post_id, 'playlist', true );
920 if ( $tracks && is_array( $tracks ) && ( count( $tracks ) > 0 ) ) {
921 $track_count = count( $tracks );
922 foreach ( $tracks as $i => $track ) {
923 $info['meta'] = '';
924 }
925 }
926 } */
927
928 // 2.3.3.9: filter meta display for different post types
929 // 2.5.0: added meta div close wrapper
930 $info['meta'] .= '</div>';
931 $info['meta'] = apply_filters( 'radio_station_archive_shortcode_meta', $info['meta'], $post_id, $post_type, $atts );
932
933 // TODO: display genre and language terms ?
934 // if ( in_array( $post_type, array( RADIO_STATION_SHOW_SLUG, RADIO_STATION_OVERRIDE_SLUG ) ) ) {
935 // if ( $atts['show_genres'] ) {
936 // $genres = wp_get_post_terms( $post_id, RADIO_STATION_GENRES_SLUG );
937 // $info['genres'] = '';
938 // }
939 // if ( $atts['show_languages'] ) {
940 // $languages = wp_get_post_terms( $post_id, RADIO_STATION_LANGUAGES_SLUG );
941 // $info['languages'] = '';
942 // }
943 // }
944
945 // --- description ---
946 // 2.4.0.4: remove description for grid view
947 // 2.4.1.8: set different grid default earlier instead
948 if ( 'none' == $atts['description'] ) {
949 $info['description'] = '';
950 } elseif ( 'full' == $atts['description'] ) {
951 $content = apply_filters( 'radio_station_' . $type . '_archive_content', $post_content, $post_id );
952 $info['description'] = '<div class="' . esc_attr( $type ) . '-archive-item-content">' . "\n";
953 $info['description'] .= $content . "\n";
954 $info['description'] .= '</div>' . "\n";
955 } else {
956 if ( !empty( $post_excerpt ) ) {
957 $excerpt = $post_excerpt;
958 $excerpt .= ' <a href="' . esc_url( $permalink ) . '">' . $more . '</a>';
959 } else {
960 $excerpt = radio_station_trim_excerpt( $post_content, $length, $more, $permalink );
961 }
962 $excerpt = apply_filters( 'radio_station_' . $type . '_archive_excerpt', $excerpt, $post_id );
963 $info['description'] = '<div class="' . esc_attr( $type ) . '-archive-item-excerpt">' . "\n";
964 $info['description'] .= $excerpt . "\n";
965 $info['description'] .= '</div>' . "\n";
966 }
967
968 // 2.3.3.9: add filter for custom HTML info
969 $info['custom'] = apply_filters( 'radio_station_archive_shortcode_info_custom', '', $post_id, $post_type, $atts );
970
971 // 2.3.3.9: filter info and loop info keys to add to archive list
972 $info = apply_filters( 'radio_station_archive_shortcode_info', $info, $post_id, $post_type, $atts );
973 foreach ( $infokeys as $infokey ) {
974 if ( isset( $info[$infokey] ) ) {
975 $list .= $info[$infokey];
976 }
977 }
978
979 $list .= '</li>' . "\n";
980 }
981 $list .= '</ul>' . "\n";
982 }
983 $list .= '</div>' . "\n";
984
985 // --- add archive_pagination ---
986 if ( $atts['pagination'] && ( $atts['perpage'] > 0 ) && ( $post_count > 0 ) ) {
987 if ( $post_count > $atts['perpage'] ) {
988 $list .= radio_station_archive_pagination( $instance, $post_type, $atts, $post_count );
989 }
990 }
991
992 // --- enqueue pagination javascript ---
993 add_action( 'wp_footer', 'radio_station_archive_pagination_javascript' );
994
995 // --- enqueue shortcode styles ---
996 radio_station_enqueue_style( 'shortcodes' );
997
998 // --- filter and return ---
999 // 2.4.0.4: added third argument for post type
1000 $list = apply_filters( 'radio_station_' . $type . '_archive_list', $list, $atts, $post_type );
1001
1002 return $list;
1003 }
1004
1005 // ----------------------
1006 // Show Archive Shortcode
1007 // ----------------------
1008 add_shortcode( 'show-archive', 'radio_station_show_archive_list' );
1009 add_shortcode( 'shows-archive', 'radio_station_show_archive_list' );
1010 function radio_station_show_archive_list( $atts ) {
1011 return radio_station_archive_list_shortcode( RADIO_STATION_SHOW_SLUG, $atts );
1012 }
1013
1014 // --------------------------
1015 // Override Archive Shortcode
1016 // --------------------------
1017 add_shortcode( 'override-archive', 'radio_station_override_archive_list' );
1018 add_shortcode( 'overrides-archive', 'radio_station_override_archive_list' );
1019 function radio_station_override_archive_list( $atts ) {
1020 return radio_station_archive_list_shortcode( RADIO_STATION_OVERRIDE_SLUG, $atts );
1021 }
1022
1023 // --------------------------
1024 // Playlist Archive Shortcode
1025 // --------------------------
1026 add_shortcode( 'playlist-archive', 'radio_station_playlist_archive_list' );
1027 add_shortcode( 'playlists-archive', 'radio_station_playlist_archive_list' );
1028 function radio_station_playlist_archive_list( $atts ) {
1029 return radio_station_archive_list_shortcode( RADIO_STATION_PLAYLIST_SLUG, $atts );
1030 }
1031
1032 // -----------------------
1033 // Genre Archive Shortcode
1034 // -----------------------
1035 add_shortcode( 'genre-archive', 'radio_station_genre_archive_list' );
1036 add_shortcode( 'genres-archive', 'radio_station_genre_archive_list' );
1037 function radio_station_genre_archive_list( $atts ) {
1038
1039 global $radio_station_data;
1040
1041 // --- set shortcode instance ---
1042 // 2.5.0: added for consistency
1043 if ( !isset( $radio_station_data['instances']['genre-archive-list'] ) ) {
1044 $radio_station_data['instances']['genre-archive-list'] = 0;
1045 }
1046 $radio_station_data['instances']['genre-archive-list']++;
1047 $instance = $radio_station_data['instances']['genre-archive-list'];
1048
1049 // 2.3.3.9: default show description display to on
1050 // 2.5.0: added view attribute for grid view
1051 $defaults = array(
1052 // --- genre display options ---
1053 'genres' => '',
1054 'link_genres' => 1,
1055 'genre_desc' => 1,
1056 'genre_images' => 1,
1057 'view' => 'list',
1058 'image_width' => 150,
1059 'hide_empty' => 1,
1060 'pagination' => 1,
1061 // --- query args ---
1062 'status' => 'publish',
1063 'perpage' => -1,
1064 'offset' => 0,
1065 'orderby' => 'title',
1066 'order' => 'ASC',
1067 'with_shifts' => 1,
1068 // --- show display options ---
1069 'show_avatars' => 1,
1070 'thumbnails' => 0,
1071 'avatar_width' => 75,
1072 'show_desc' => 1,
1073 // --- channel ---
1074 'channel' => '',
1075 );
1076
1077 // 2.5.0: change show description default for grid view
1078 if ( isset( $atts['view'] ) && ( 'grid' == $atts['view'] ) ) {
1079 $defaults['show_desc'] = 0;
1080 }
1081
1082 // --- handle possible pagination offset ---
1083 // 2.5.0: fix to work by offset
1084 if ( isset( $atts['perpage'] ) && ( $atts['perpage'] > 0 ) ) {
1085 if ( !isset( $atts['offset'] ) ) {
1086 if ( isset( $_REQUEST['offset'] ) ) {
1087 $atts['offset'] = absint( $_REQUEST['offset'] );
1088 } elseif ( get_query_var( 'page' ) ) {
1089 $page = absint( get_query_var( 'page' ) );
1090 if ( $page > -1 ) {
1091 $atts['offset'] = (int) $atts['perpage'] * $page;
1092 }
1093 }
1094 }
1095 }
1096
1097 // --- process shortcode attributes ---
1098 // 2.5.18: added filter for default attributes
1099 $defaults = apply_filters( 'radio_station_genre_archive_default_atts', $defaults );
1100 $atts = shortcode_atts( $defaults, $atts, 'genre-archive' );
1101 if ( RADIO_STATION_DEBUG ) {
1102 echo '<span style="display:none;">Genre Archive Shortcode Atts: ' . esc_html( print_r( $atts, true ) ) . '</span>' . "\n";
1103 }
1104
1105 // --- maybe get specified genre(s) ---
1106 // 2.5.0: also gather genres ID array
1107 $genres = $genre_ids = array();
1108 if ( '' != trim( $atts['genres'] ) ) {
1109 $genre_slugs = explode( ',', $atts['genres'] );
1110 foreach ( $genre_slugs as $genre_slug ) {
1111 $genre_slug = trim( $genre_slug );
1112 // 2.5.6: fix to get genre by genre_slug
1113 $genre = radio_station_get_genre( $genre_slug );
1114 if ( $genre ) {
1115 // 2.5.10: fix to get first array key
1116 // 2.5.18: make backwards compatible
1117 reset( $genre );
1118 $name = key( $genre );
1119 $genres[$name] = $genre[$name];
1120 $genre_ids[] = $genre[$name]['id'];
1121 }
1122 }
1123 } else {
1124 // --- get all genres ---
1125 $args = array();
1126 if ( !$atts['hide_empty'] ) {
1127 $args['hide_empty'] = false;
1128 }
1129 $genres = radio_station_get_genres( $args );
1130 foreach ( $genres as $genre ) {
1131 $genre_ids[] = $genre['id'];
1132 }
1133 }
1134
1135 // --- check if we have genres ---
1136 // 2.5.0: improve logic to allow filtering
1137 if ( 0 === count( $genres ) ) {
1138
1139 if ( $atts['hide_empty'] ) {
1140 $list = '';
1141 } else {
1142 $list = '<div id="genres-archive-' . esc_attr( $instance ) . '" class="genres-archive">' . "\n";
1143 $list .= esc_html( __( 'No Genres were found to display.', 'radio-station' ) ) . "\n";
1144 $list .= '</div>' . "\n";
1145 }
1146 $list = apply_filters( 'radio_station_genre_archive_list', $list, $atts, $instance );
1147 return $list;
1148
1149 }
1150
1151 // --- get published shows ---
1152 // TODO: also display Overrides in Genre archive list ?
1153 $args = array(
1154 'post_type' => RADIO_STATION_SHOW_SLUG,
1155 // 'numberposts' => $atts['perpage'],
1156 // 'offset' => $atts['offset'],
1157 'numberposts' => -1,
1158 'orderby' => $atts['orderby'],
1159 'order' => $atts['order'],
1160 'post_status' => $atts['status'],
1161 );
1162
1163 if ( $atts['with_shifts'] ) {
1164
1165 // --- active shows with shifts ---
1166 $args['meta_query'] = array(
1167 'relation' => 'AND',
1168 array(
1169 'key' => 'show_sched',
1170 'compare' => 'EXISTS',
1171 ),
1172 array(
1173 'key' => 'show_active',
1174 'value' => 'on',
1175 'compare' => '=',
1176 ),
1177 );
1178
1179 } else {
1180
1181 // --- just active shows ---
1182 $args['meta_query'] = array(
1183 array(
1184 'key' => 'show_active',
1185 'value' => 'on',
1186 'compare' => '=',
1187 ),
1188 );
1189 }
1190
1191 // --- set genre taxonomy query ---
1192 // 2.5.0: get all shows with a genre term assigned
1193 $args['tax_query'] = array(
1194 array(
1195 'taxonomy' => RADIO_STATION_GENRES_SLUG,
1196 'field' => 'term_id',
1197 'terms' => $genre_ids,
1198 // 'field' => 'slug',
1199 // 'terms' => $genre['slug'],
1200 ),
1201 );
1202
1203 // --- get shows in genre ---
1204 // 2.5.0: added shortcode atts as second filter argument
1205 $args = apply_filters( 'radio_station_genre_archive_post_args', $args, $atts );
1206 $posts = get_posts( $args );
1207 $posts = apply_filters( 'radio_station_genre_archive_posts', $posts, $atts );
1208 $post_count = count( $posts );
1209 if ( RADIO_STATION_DEBUG ) {
1210 echo '<span style="display:none;">Genre Archive Args: ' . esc_html( print_r( $args, true ) ) . "\n";
1211 echo 'Genre Archive Shows: ' . esc_html( print_r( $posts, true ) ) . '</span>' . "\n";
1212 }
1213
1214 // --- get genre terms for each post ---
1215 $genre_posts = array();
1216 if ( $posts && is_array( $posts ) && ( $post_count > 0 ) ) {
1217 foreach ( $posts as $i => $post ) {
1218 $post_terms[$i] = wp_get_post_terms( $post->ID, RADIO_STATION_GENRES_SLUG );
1219 if ( $post_terms[$i] ) {
1220 foreach ( $genres as $genre ) {
1221 foreach ( $post_terms[$i] as $term ) {
1222 if ( $genre['id'] == $term->term_id ) {
1223 if ( isset( $genre_posts[$genre['id']] ) ) {
1224 if ( !in_array( $post->ID, $genre_posts[$genre['id']] ) ) {
1225 $genre_posts[$genre['id']][] = $post->ID;
1226 }
1227 } else {
1228 $genre_posts[$genre['id']] = array( $post->ID );
1229 }
1230 }
1231 }
1232 }
1233 }
1234 }
1235 if ( RADIO_STATION_DEBUG ) {
1236 echo '<span style="display:none;">Genre Posts: ' . esc_html( print_r( $genre_posts, true ) ) . '</span>' . "\n";
1237 }
1238 } else {
1239
1240 // 2.5.0: added no shows with genres message
1241 $list = '<div id="genres-archive-' . esc_attr( $instance ) . '" class="genres-archive">' . "\n";
1242 $list .= esc_html( __( 'No Shows were found with Genres assigned.', 'radio-station' ) ) . "\n";
1243 $list .= '</div>' . "\n";
1244 $list = apply_filters( 'radio_station_genre_archive_list', $list, $atts, $instance );
1245 return $list;
1246
1247 }
1248
1249 // 2.5.0: added id attribute with instance
1250 // 2.5.0: add view attribute to class list
1251 $list = '<div id="genres-archive-' . esc_attr( $instance ) . '" class="genres-archive ' . esc_attr( $atts['view'] ) . '">' . "\n";
1252
1253 // --- loop genres ---
1254 // 2.5.0: track post display count
1255 $display_count = 1;
1256 $start = ( isset( $atts['offset'] ) && ( $atts['offset'] > 0 ) ) ? ( $atts['offset'] ) : 0;
1257 $end = ( $atts['perpage'] > -1 ) ? ( $start + $atts['perpage'] + 1 ) : 999999;
1258 foreach ( $genres as $name => $genre ) {
1259
1260 $list .= '<div class="genre-archive">' . "\n";
1261
1262 // 2.5.0: modified to check for shows in this genre
1263 $heading = '';
1264 if ( !isset( $genre_posts[$genre['id']] ) ) {
1265
1266 if ( !$atts['hide_empty'] ) {
1267
1268 // --- genre image ---
1269 $genre_image = apply_filters( 'radio_station_genre_image', false, $genre );
1270 if ( $genre_image ) {
1271 $list .= '<div class="genre-image-wrapper"';
1272 if ( absint( $atts['image_width'] ) > 0 ) {
1273 $list .= ' style="width: ' . esc_attr( absint( $atts['image_width'] ) ) . 'px"';
1274 }
1275 $list .= '>' . "\n";
1276 // 2.5.0: added wp_kses on image output
1277 // 2.5.6: fix to add missing allowed variable
1278 $allowed = radio_station_allowed_html( 'media', 'image' );
1279 $list .= wp_kses( $genre_image, $allowed );
1280 $list .= '</div>' . "\n";
1281 }
1282
1283 // --- genre title ---
1284 // 2.5.10: change div class to genre-title-wrapper
1285 $list .= '<div class="genre-title-wrapper"><h3 class="genre-title">' . "\n";
1286 if ( $atts['link_genres'] ) {
1287 // 2.5.10: added genre-link class
1288 $list .= '<a class="genre-link" href="' . esc_url( $genre['url'] ) . '">';
1289 $list .= esc_html( $genre['name'] );
1290 $list .= '</a>' . "\n";
1291 } else {
1292 $list .= esc_html( $genre['name'] ) . "\n";
1293 }
1294 $list .= '</h3></div>' . "\n";
1295
1296 // --- no shows messages ----
1297 $list .= esc_html( __( 'No Shows in this Genre.', 'radio-station' ) ) . "\n";
1298
1299 }
1300
1301 } else {
1302
1303 // --- genre image ---
1304 $genre_image = apply_filters( 'radio_station_genre_image', false, $genre );
1305 if ( $genre_image ) {
1306 $heading = '<div class="genre-image-wrapper"';
1307 if ( absint( $atts['image_width'] ) > 0 ) {
1308 $heading .= ' style="width: ' . esc_attr( absint( $atts['image_width'] ) ) . 'px"';
1309 }
1310 $heading .= '>' . "\n";
1311 // 2.5.0: added wp_kses on image output
1312 // 2.5.6: fix to add missing allowed variable
1313 $allowed = radio_station_allowed_html( 'media', 'image' );
1314 $heading .= wp_kses( $genre_image, $allowed );
1315 $heading .= '</div>' . "\n";
1316 }
1317
1318 // --- genre title ---
1319 // 2.5.10: change div class to genre-title-wrapper
1320 $heading .= '<div class="genre-title-wrapper"><h3 class="genre-title">' . "\n";
1321 if ( $atts['link_genres'] ) {
1322 // 2.5.10: added genre-link class
1323 $heading .= '<a class="genre-link" href="' . esc_url( $genre['url'] ) . '">';
1324 $heading .= esc_html( $genre['name'] );
1325 $heading .= '</a>' . "\n";
1326 } else {
1327 $heading .= esc_html( $genre['name'] ) . "\n";
1328 }
1329 $heading .= '</h3></div>' . "\n";
1330
1331 // --- genre description ---
1332 if ( $atts['genre_desc'] && !empty( $genre['genre_desc'] ) ) {
1333 $heading .= '<div class="genre-description">' . "\n";
1334 // 2.5.0: added wp_kses on description output
1335 $allowed = radio_station_allowed_html( 'content', 'description' );
1336 $heading .= wp_kses( $genre['description'], $allowed ) . "\n";
1337 $heading .= '</div>' . "\n";
1338 }
1339
1340 // --- filter excerpt length and more ---
1341 // 2.3.3.9: added for show description excerpts
1342 $length = apply_filters( 'radio_station_genre_archive_excerpt_length', false );
1343 $more = apply_filters( 'radio_station_genre_archive_excerpt_more', '[&hellip;]' );
1344
1345 $items = array();
1346 foreach ( $posts as $post ) {
1347
1348 if ( in_array( $post->ID, $genre_posts[$genre['id']] ) ) {
1349
1350 // echo $name . ' >>' . $start . ' - ' . $display_count . ' - ' . $end . '<< <br>' . "\n";
1351 if ( ( $display_count > $start ) && ( $display_count < $end ) ) {
1352
1353 $item = '<li class="show-archive-item">' . "\n";
1354
1355 // --- show avatar or thumbnail fallback ---
1356 $item .= '<div class="show-archive-item-thumbnail"';
1357 if ( absint( $atts['avatar_width'] ) > 0 ) {
1358 $item .= ' style="width: ' . esc_attr( absint( $atts['avatar_width'] ) ) . 'px"';
1359 }
1360 $item .= '>' . "\n";
1361 $show_avatar = false;
1362 if ( $atts['show_avatars'] ) {
1363 $attr = array( 'class' => 'show-thumbnail-image' );
1364 $show_avatar = radio_station_get_show_avatar( $post->ID, 'thumbnail', $attr );
1365 }
1366 if ( $show_avatar ) {
1367 // 2.5.0: added wp_kses on show avatar output
1368 $allowed = radio_station_allowed_html( 'media', 'image' );
1369 $item .= wp_kses( $show_avatar, $allowed ). "\n";
1370 } elseif ( $atts['thumbnails'] ) {
1371 if ( has_post_thumbnail( $post->ID ) ) {
1372 $attr = array( 'class' => 'show-thumbnail-image' );
1373 $thumbnail = get_the_post_thumbnail( $post->ID, 'thumbnail', $attr );
1374 // 2.5.0: added wp_kses on thumbnail outputting
1375 $allowed = radio_station_allowed_html( 'media', 'image' );
1376 $item .= wp_kses( $thumbnail, $allowed ) . "\n";
1377 }
1378 }
1379 $item .= '</div>' . "\n";
1380
1381 // --- show title ----
1382 $permalink = get_permalink( $post->ID );
1383 $item .= '<div class="show-archive-item-title">' . "\n";
1384 $item .= '<a href="' . esc_url( $permalink ) . '">' . "\n";
1385 // 2.5.0: replaced esc_attr with esc_html
1386 $item .= esc_html( $post->post_title ) . "\n";
1387 $item .= '</a>' . "\n";
1388 $item .= '</div>' . "\n";
1389
1390 // --- show excerpt ---
1391 // 2.2.3.9: display show description
1392 if ( $atts['show_desc' ] ) {
1393 if ( !empty( $post->post_excerpt ) ) {
1394 $excerpt = $post->post_excerpt;
1395 // 2.5.0: added missing esc_html on more anchor
1396 $excerpt .= ' <a href="' . esc_url( $permalink ) . '">' . esc_html( $more ) . '</a>';
1397 } else {
1398 $excerpt = radio_station_trim_excerpt( $post->post_content, $length, $more, $permalink );
1399 }
1400 $excerpt = apply_filters( 'radio_station_genre_archive_excerpt', $excerpt, $post->ID );
1401
1402 if ( '' != $excerpt ) {
1403 $item .= '<div class="show-archive-item-description">' . "\n";
1404 // 2.5.0: use wp_kses on excerpt output
1405 $allowed = radio_station_allowed_html( 'content', 'excerpt' );
1406 $item .= wp_kses( $excerpt, $allowed ) . "\n";
1407 $item .= '</div>' . "\n";
1408 }
1409 }
1410
1411 $item .= '</li>' . "\n";
1412 $items[] = $item;
1413
1414 }
1415
1416 $display_count++;
1417
1418 }
1419 }
1420
1421 // --- show archive list ---
1422 if ( count( $items ) > 0 ) {
1423 $list .= $heading;
1424 $list .= '<ul class="show-archive-list">' . "\n";
1425 $list .= implode( "\n", $items );
1426 $list .= '</ul>' . "\n";
1427 }
1428 }
1429 $list .= '</div>' . "\n";
1430 }
1431
1432 $list .= '</div>' . "\n";
1433
1434 // --- add archive_pagination ---
1435 // 2.5.0: enable genre archive list pagination
1436 if ( $atts['pagination'] && ( $atts['perpage'] > 0 ) && ( $post_count > 0 ) ) {
1437 if ( $post_count > $atts['perpage'] ) {
1438 $list .= radio_station_archive_pagination( $instance, 'genre', $atts, $post_count );
1439 }
1440 }
1441
1442 // --- enqueue pagination javascript ---
1443 add_action( 'wp_footer', 'radio_station_archive_pagination_javascript' );
1444
1445 // --- enqueue shortcode styles ---
1446 radio_station_enqueue_style( 'shortcodes' );
1447
1448 // --- filter and return ---
1449 $list = apply_filters( 'radio_station_genre_archive_list', $list, $atts, $instance );
1450 return $list;
1451 }
1452
1453 // --------------------------
1454 // Language Archive Shortcode
1455 // --------------------------
1456 // 2.3.3.9: add Languages Archive Shortcode
1457 add_shortcode( 'language-archive', 'radio_station_language_archive_list' );
1458 add_shortcode( 'languages-archive', 'radio_station_language_archive_list' );
1459 function radio_station_language_archive_list( $atts ) {
1460
1461 global $radio_station_data;
1462
1463 // --- set shortcode instance ---
1464 // 2.5.0: set shortcode instance for consistency
1465 if ( !isset( $radio_station_data['instances']['language-archive-list'] ) ) {
1466 $radio_station_data['instances']['language-archive-list'] = 0;
1467 }
1468 $radio_station_data['instances']['language-archive-list']++;
1469 $instance = $radio_station_data['instances']['language-archive-list'];
1470
1471 // TODO: attribute in include/exclude main language term ?
1472 $defaults = array(
1473 // --- language display options ---
1474 'languages' => '',
1475 'link_languages' => 1,
1476 'language_desc' => 1,
1477 'view' => 'list',
1478 'hide_empty' => 1,
1479 'pagination' => 1,
1480 // --- query args ---
1481 'status' => 'publish',
1482 'perpage' => -1,
1483 'offset' => 0,
1484 'orderby' => 'title',
1485 'order' => 'ASC',
1486 'with_shifts' => 1,
1487 // --- show display options ---
1488 'show_avatars' => 1,
1489 'thumbnails' => 0,
1490 'avatar_width' => 75,
1491 'show_desc' => 1,
1492 // --- channel ---
1493 'channel' => '',
1494 );
1495
1496 // 2.5.0: change show description default for grid view
1497 if ( isset( $atts['view'] ) && ( 'grid' == $atts['view'] ) ) {
1498 $defaults['show_desc'] = 0;
1499 }
1500
1501 // --- handle possible pagination offset ---
1502 // 2.5.0: fix to work by offset
1503 if ( isset( $atts['perpage'] ) && ( $atts['perpage'] > 0 ) ) {
1504 if ( !isset( $atts['offset'] ) ) {
1505 if ( isset( $_REQUEST['offset'] ) ) {
1506 $atts['offset'] = absint( $_REQUEST['offset'] );
1507 } elseif ( get_query_var( 'page' ) ) {
1508 $page = absint( get_query_var( 'page' ) );
1509 if ( $page > -1 ) {
1510 $atts['offset'] = (int) $atts['perpage'] * $page;
1511 }
1512 }
1513 }
1514 }
1515
1516 // --- process shortcode attributes ---
1517 // 2.5.18: added filter for default attributes
1518 $defaults = apply_filters( 'radio_station_language_archive_default_atts', $defaults );
1519 $atts = shortcode_atts( $defaults, $atts, 'language-archive' );
1520 if ( RADIO_STATION_DEBUG ) {
1521 echo '<span style="display:none;">Language Archive Shortcode Atts: ' . esc_html( print_r( $atts, true ) ) . '</span>' . "\n";
1522 }
1523
1524 // --- maybe get specified language(s) ---
1525 // 2.5.0: also gather language term IDs
1526 $languages = $language_ids = array();
1527 if ( '' != trim( $atts['languages'] ) ) {
1528 $language_slugs = explode( ',', $atts['languages'] );
1529 foreach ( $language_slugs as $language_slug ) {
1530 $language_slug = trim( $language_slug );
1531 // 2.5.0: convert main language slug to get default
1532 if ( 'main' == $language_slug ) {
1533 $language_slug = false;
1534 }
1535 $language = radio_station_get_language( $language_slug );
1536 if ( $language ) {
1537 // 2.5.10: fix to get first array key
1538 // 2.5.18: make backwards compatible
1539 reset( $language );
1540 $name = key( $language );
1541 $languages[$name] = $language[$name];
1542 $language_ids[] = $language[$name]['id'];
1543 }
1544 }
1545 } else {
1546 // --- get all languages ---
1547 $args = array();
1548 if ( !$atts['hide_empty'] ) {
1549 $args['hide_empty'] = false;
1550 }
1551 $languages = radio_station_get_language_terms( $args );
1552 // 2.5.0: merge in main language
1553 $main_language = radio_station_get_language();
1554 if ( !isset( $languages[$main_language['name']] ) ) {
1555 $languages[$main_language['name']] = $main_language;
1556 }
1557 foreach ( $languages as $language ) {
1558 $language_ids[] = $language['id'];
1559 }
1560 // echo 'Languages IDs: '; print_r( $language_ids, true );
1561 }
1562
1563 // --- check if we have languages ---
1564 // 2.5.0: modified to allow filtering
1565 if ( 0 == count( $languages ) ) {
1566 if ( $atts['hide_empty'] ) {
1567 $list = '';
1568 } else {
1569 $list = '<div id="languages-archive-' . esc_attr( $instance ) . '" class="languages-archive">' . "\n";
1570 $list .= esc_html( __( 'No Languages were found to display.', 'radio-station' ) ) . "\n";
1571 $list .= '</div>' . "\n";
1572 }
1573 $list = apply_filters( 'radio_station_language_archive_list', $list, $atts, $instance );
1574 return $list;
1575 }
1576
1577 // --- get published shows ---
1578 // TODO: also display Overrides in archive list ?
1579 $args = array(
1580 'post_type' => RADIO_STATION_SHOW_SLUG,
1581 // 'numberposts' => $atts['perpage'],
1582 // 'offset' => $atts['offset'],
1583 'numberposts' => -1,
1584 'orderby' => $atts['orderby'],
1585 'order' => $atts['order'],
1586 'post_status' => $atts['status'],
1587 );
1588
1589 if ( $atts['with_shifts'] ) {
1590
1591 // --- active shows with shifts ---
1592 $args['meta_query'] = array(
1593 'relation' => 'AND',
1594 array(
1595 'key' => 'show_sched',
1596 'compare' => 'EXISTS',
1597 ),
1598 array(
1599 'key' => 'show_active',
1600 'value' => 'on',
1601 'compare' => '=',
1602 ),
1603 );
1604
1605 } else {
1606
1607 // --- just active shows ---
1608 $args['meta_query'] = array(
1609 array(
1610 'key' => 'show_active',
1611 'value' => 'on',
1612 'compare' => '=',
1613 ),
1614 );
1615 }
1616
1617 // --- set language taxonomy query ---
1618 // 2.5.0: get all shows with a language term assigned
1619 $args['tax_query'] = array(
1620 array(
1621 'taxonomy' => RADIO_STATION_LANGUAGES_SLUG,
1622 'field' => 'term_id',
1623 'terms' => $language_ids,
1624 // 'field' => 'slug',
1625 // 'terms' => $language['slug'],
1626 ),
1627 );
1628
1629 // --- get shows in language ---
1630 $args = apply_filters( 'radio_station_language_archive_post_args', $args, $atts );
1631 $posts = get_posts( $args );
1632
1633 $posts = apply_filters( 'radio_station_language_archive_posts', $posts, $atts );
1634 $post_count = count( $posts );
1635 if ( RADIO_STATION_DEBUG ) {
1636 echo '<span style="display:none;">Language Archive Args: ' . esc_html( print_r( $args, true ) ) . "\n";
1637 echo 'Language Archive Shows: ' . esc_html( print_r( $posts, true ) ) . '</span>' . "\n";
1638 }
1639
1640 // --- get language terms for each post ---
1641 $language_posts = array();
1642 if ( $posts && is_array( $posts ) && ( $post_count > 0 ) ) {
1643 foreach ( $posts as $i => $post ) {
1644 $post_terms[$i] = wp_get_post_terms( $post->ID, RADIO_STATION_LANGUAGES_SLUG );
1645 if ( $post_terms[$i] ) {
1646 foreach ( $languages as $language ) {
1647 foreach ( $post_terms[$i] as $term ) {
1648 if ( $language['id'] == $term->term_id ) {
1649 if ( isset( $language_posts[$language['id']] ) ) {
1650 if ( !in_array( $post->ID, $language_posts[$language['id']] ) ) {
1651 $language_posts[$language['id']][] = $post->ID;
1652 }
1653 } else {
1654 $language_posts[$language['id']] = array( $post->ID );
1655 }
1656 }
1657 }
1658 }
1659 }
1660 }
1661 if ( RADIO_STATION_DEBUG ) {
1662 echo '<span style="display:none;">Language Posts: ' . esc_html( print_r( $language_posts, true ) ) . '</span>' . "\n";
1663 }
1664 }
1665
1666 // --- maybe merge in main language posts ---
1667 // 2.5.0: added for when no specific language is specified
1668 if ( '' == trim ( $atts['languages'] ) ) {
1669 $main_language = radio_station_get_language();
1670
1671 $args['tax_query'][0]['operator'] = 'NOT IN';
1672 $main_posts = get_posts( $args );
1673 if ( RADIO_STATION_DEBUG ) {
1674 echo '<span style="display:none;">Main Language: ' . esc_html( print_r( $main_language, true ) ) . '</span>' . "\n";
1675 echo '<span style="display:none;">Shows with No Language Terms: ' . esc_html( print_r( $main_posts, true ) ) . '</span>' . "\n";
1676 }
1677
1678 if ( count( $main_posts ) > 0 ) {
1679
1680 // --- loop to set language posts array ---
1681 foreach ( $main_posts as $main_post ) {
1682 if ( isset( $language_posts[$main_language['id']] ) ) {
1683 if ( !in_array( $main_post->ID, $language_posts[$main_language['id']] ) ) {
1684 $language_posts[$main_language['id']][] = $main_post->ID;
1685 }
1686 } else {
1687 $language_posts[$main_language['id']] = array( $main_post->ID );
1688 }
1689 }
1690 if ( RADIO_STATION_DEBUG ) {
1691 echo '<span style="display:none;">Combined Language Posts: ' . esc_html( print_r( $language_posts, true ) ) . '</span>' . "\n";
1692 }
1693
1694 // --- merge and refetch (to reorder) ---
1695 $posts = array_merge( $posts, $main_posts );
1696 $post_ids = array();
1697 foreach ( $posts as $post ) {
1698 $post_ids[] = $post->ID;
1699 }
1700 if ( RADIO_STATION_DEBUG ) {
1701 echo '<span style="display:none;">Combined Shows: ' . esc_html( print_r( $posts, true ) ) . '</span>' . "\n";
1702 echo '<span style="display:none;">Combined Show IDs: ' . esc_html( print_r( $post_ids, true ) ) . '</span>' . "\n";
1703 }
1704
1705 $args = array(
1706 'numberposts' => -1,
1707 'post_type' => RADIO_STATION_SHOW_SLUG,
1708 'orderby' => $atts['orderby'],
1709 'order' => $atts['order'],
1710 'include' => $post_ids,
1711 );
1712 $posts = get_posts( $args );
1713 if ( RADIO_STATION_DEBUG ) {
1714 echo '<span style="display:none;">Sorted Shows: ' . esc_html( print_r( $posts, true ) ) . '</span>' . "\n";
1715 }
1716 }
1717 }
1718
1719 // 2.5.0: added no shows with languages message
1720 $post_count = count( $posts );
1721 if ( !$posts || !is_array( $posts ) || ( 0 == $post_count ) ) {
1722
1723 $list = '<div id="languages-archive-' . esc_attr( $instance ) . '" class="languages-archive">' . "\n";
1724 $list .= esc_html( __( 'No Shows were found with Languages assigned.', 'radio-station' ) ) . "\n";
1725 $list .= '</div>' . "\n";
1726 $list = apply_filters( 'radio_station_language_archive_list', $list, $atts, $instance );
1727 return $list;
1728
1729 }
1730
1731 // 2.5.0: added id attribute with instance
1732 // 2.5.0: add view attribute to class list
1733 $list = '<div id="languages-archive-' . esc_attr( $instance ) . '" class="languages-archive ' . esc_attr( $atts['view'] ) . '">' . "\n";
1734
1735 // --- loop languages ---
1736 // 2.5.0: track post display count
1737 $display_count = 1;
1738 $start = ( isset( $atts['offset'] ) && ( $atts['offset'] > 0 ) ) ? ( $atts['offset'] ) : 0;
1739 $end = ( $atts['perpage'] > -1 ) ? ( $start + $atts['perpage'] + 1 ) : 999999;
1740 foreach ( $languages as $name => $language ) {
1741
1742 $list .= '<div class="language-archive">' . "\n";
1743
1744 // $heading = '';
1745 if ( !isset( $language_posts[$language['id']] ) ) {
1746
1747 if ( !$atts['hide_empty'] ) {
1748
1749 // --- language title ---
1750 $list .= '<div class="language-title"><h3 class="language-title">' . "\n";
1751 if ( $atts['link_languages'] ) {
1752 $list .= '<a href="' . esc_url( $language['url'] ) . '">' . "\n";
1753 $list .= esc_html( $language['name'] ) . "\n";
1754 $list .= '</a>' . "\n";
1755 } else {
1756 $list .= esc_html( $language['name'] ) . "\n";
1757 }
1758 $list .= '</h3></div>' . "\n";
1759
1760 $list .= esc_html( __( 'No Shows in this Language.', 'radio-station' ) );
1761
1762 }
1763
1764 } else {
1765
1766 // --- language title ---
1767 $heading = '<div class="language-title"><h3 class="language-title">' . "\n";
1768 if ( $atts['link_languages'] ) {
1769 $heading .= '<a href="' . esc_url( $language['url'] ) . '">' . "\n";
1770 $heading .= esc_html( $language['name'] ) . "\n";
1771 $heading .= '</a>' . "\n";
1772 } else {
1773 $heading .= esc_html( $language['name'] ) . "\n";
1774 }
1775 $heading .= '</h3></div>' . "\n";
1776
1777 // --- language description ---
1778 if ( $atts['language_desc'] && !empty( $language['language_desc'] ) ) {
1779 $heading .= '<div class="language-description">' . "\n";
1780 // 2.5.0: use wp_kses on description output
1781 $allowed = radio_station_allowed_html( 'content', 'description' );
1782 $heading .= wp_kses( $language['description'], $allowed ) . "\n";
1783 $heading .= '</div>' . "\n";
1784 }
1785
1786 // --- filter excerpt length and more ---
1787 $length = apply_filters( 'radio_station_language_archive_excerpt_length', false );
1788 $more = apply_filters( 'radio_station_language_archive_excerpt_more', '[&hellip;]' );
1789
1790 $items = array();
1791 foreach ( $posts as $post ) {
1792
1793 if ( in_array( $post->ID, $language_posts[$language['id']] ) ) {
1794
1795 // echo $name . ' >>' . $start . ' - ' . $display_count . ' - ' . $end . '<< <br>' . "\n";
1796 if ( ( $display_count > $start ) && ( $display_count < $end ) ) {
1797
1798 $item = '<li class="show-archive-item">' . "\n";
1799
1800 // --- show avatar or thumbnail fallback ---
1801 $item .= '<div class="show-archive-item-thumbnail"';
1802 if ( absint( $atts['avatar_width'] ) > 0 ) {
1803 $item .= ' style="width: ' . esc_attr( absint( $atts['avatar_width'] ) ) . 'px"';
1804 }
1805 $item .= '>' . "\n";
1806 $show_avatar = false;
1807 if ( $atts['show_avatars'] ) {
1808 $attr = array( 'class' => 'show-thumbnail-image' );
1809 $show_avatar = radio_station_get_show_avatar( $post->ID, 'thumbnail', $attr );
1810 }
1811 if ( $show_avatar ) {
1812 // 2.5.0: use wp_kses on show avatar output
1813 $allowed = radio_station_allowed_html( 'media', 'image' );
1814 $item .= wp_kses( $show_avatar, $allowed ) . "\n";
1815 } elseif ( $atts['thumbnails'] ) {
1816 if ( has_post_thumbnail( $post->ID ) ) {
1817 $attr = array( 'class' => 'show-thumbnail-image' );
1818 $thumbnail = get_the_post_thumbnail( $post->ID, 'thumbnail', $attr );
1819 // 2.5.0: use wp_kses on thumbnail output
1820 $allowed = radio_station_allowed_html( 'media', 'image' );
1821 $item .= wp_kses( $thumbnail, $allowed ) . "\n";
1822 }
1823 }
1824 $item .= '</div>';
1825
1826 // --- show title ----
1827 $permalink = get_permalink( $post->ID );
1828 $item .= '<div class="show-archive-item-title">' . "\n";
1829 $item .= '<a href="' . esc_url( $permalink ) . '">' . "\n";
1830 // 2.5.0: change esc_attr to esc_html
1831 $item .= esc_html( $post->post_title );
1832 $item .= '</a>' . "\n";
1833 $item .= '</div>' . "\n";
1834
1835 // --- show excerpt ---
1836 if ( $atts['show_desc' ] ) {
1837 if ( !empty( $post->post_excerpt ) ) {
1838 $excerpt = $post->post_excerpt;
1839 // 2.5.0: use esc_html on more anchor text
1840 $excerpt .= ' <a href="' . esc_url( $permalink ) . '">' . esc_html( $more ) . '</a>' . "\n";
1841 } else {
1842 $excerpt = radio_station_trim_excerpt( $post->post_content, $length, $more, $permalink );
1843 }
1844 // 2.5.0: fix to incorrect filter name radio_station_genre_archive_excerpt
1845 $excerpt = apply_filters( 'radio_station_language_archive_excerpt', $excerpt, $post->ID );
1846
1847 if ( '' != $excerpt ) {
1848 $item .= '<div class="show-archive-item-description">';
1849 // 2.5.0: use wp_kses on excerpt output
1850 $allowed = radio_station_allowed_html( 'content', 'excerpt' );
1851 $item .= wp_kses( $excerpt, $allowed );
1852 $item .= '</div>';
1853 }
1854 }
1855
1856 $item .= '</li>' . "\n";
1857
1858 $items[] = $item;
1859 }
1860
1861 $display_count++;
1862
1863 }
1864 }
1865
1866 if ( count( $items ) > 0 ) {
1867 // --- show archive list ---
1868 $list .= $heading;
1869 $list .= '<ul class="show-archive-list">' . "\n";
1870 $list .= implode( "\n", $items );
1871 $list .= '</ul>' . "\n";
1872
1873 }
1874 }
1875 $list .= '</div>' . "\n";
1876 }
1877 $list .= '</div>' . "\n";
1878
1879 // --- add archive_pagination ---
1880 // 2.5.0: enable language archive list pagination
1881 if ( $atts['pagination'] && ( $atts['perpage'] > 0 ) && ( $post_count > 0 ) ) {
1882 if ( $post_count > $atts['perpage'] ) {
1883 $list .= radio_station_archive_pagination( $instance, 'language', $atts, $post_count );
1884 }
1885 }
1886
1887 // --- enqueue pagination javascript ---
1888 add_action( 'wp_footer', 'radio_station_archive_pagination_javascript' );
1889
1890 // --- enqueue shortcode styles ---
1891 radio_station_enqueue_style( 'shortcodes' );
1892
1893 // --- filter and return ---
1894 $list = apply_filters( 'radio_station_language_archive_list', $list, $atts, $instance );
1895 return $list;
1896 }
1897
1898 // ------------------
1899 // Archive Pagination
1900 // ------------------
1901 function radio_station_archive_pagination( $instance, $type, $atts, $post_count ) {
1902
1903 // 2.5.0: fix to current page, default to 1
1904 // 2.5.0: use offset value instead of page
1905 global $post;
1906 $permalink = get_permalink( $post->ID );
1907 $post_pages = ceil( $post_count / $atts['perpage'] );
1908 $current_page = ( isset( $atts['offset'] ) && ( $atts['offset'] > 0 ) ) ? (int) ( $atts['offset'] / $atts['perpage'] ) + 1 : 1;
1909 $prev_page = $current_page - 1;
1910 $next_page = $current_page + 1;
1911
1912 $pagi = '<br>' . "\n";
1913 $pagi .= '<div class="archive-pagination-buttons archive-' . esc_attr( $type ) . 's-page-buttons">' . "\n";
1914 if ( $prev_page > 0 ) {
1915 $pagi .= '<div class="archive-pagination-button">' . "\n";
1916 // 2.5.6: fix to set permalink as URL for first page
1917 $url = $permalink;
1918 if ( $prev_page > 1 ) {
1919 $url = add_query_arg( 'offset', ( $prev_page * $atts['perpage'] ), $permalink );
1920 }
1921 $onclick = "return radio_archive_page(" . esc_attr( $instance ) . ",'" . esc_attr( $type ) . "'," . esc_attr( $prev_page ) . "');";
1922 $pagi .= '<a href="' . esc_url( $url ) . '" onclick="' . $onclick . '">&larr;</a>' . "\n";
1923 $pagi .= '</div>' . "\n";
1924 }
1925 for ( $page_num = 1; $page_num < ( $post_pages + 1 ); $page_num++ ) {
1926 $active = ( $current_page == $page_num ) ? ' active' : '';
1927 $pagi .= '<div class="archive-' . esc_attr( $type ) . 's-page-button archive-pagination-button' . esc_attr( $active ) . '">' . "\n";
1928 $url = $permalink;
1929 if ( $page_num > 1 ) {
1930 $offset = ( ( $page_num - 1 ) * $atts['perpage'] );
1931 $url = add_query_arg( 'offset', $offset, $permalink );
1932 }
1933 $onclick = "return radio_archive_page(" . esc_attr( $instance ) . ",'" . esc_attr( $type ) . "'," . esc_attr( $page_num ) . "');";
1934 $pagi .= '<a href="' . esc_url( $url ) . '" onclick="' . $onclick .'">' . "\n";
1935 $pagi .= esc_html( $page_num ) . "\n";
1936 $pagi .= '</a>' . "\n";
1937 $pagi .= '</div>' . "\n";
1938 }
1939 if ( $next_page < ( $post_pages + 1 ) ) {
1940 $pagi .= '<div class="archive-pagination-button">' . "\n";
1941 $offset = ( ( $next_page - 1 ) * $atts['perpage'] );
1942 $url = add_query_arg( 'offset', $offset, $permalink );
1943 $onclick = "return radio_archive_page(" . esc_attr( $instance ) . ",'" . esc_attr( $type ) . "'," . esc_attr( $next_page ) . "');";
1944 $pagi .= '<a href="' . esc_url( $url ) . '" onclick="' . $onclick . '">&rarr;</a>' . "\n";
1945 $pagi .= '</div>' . "\n";
1946 }
1947
1948 $pagi .= '</div>' . "\n";
1949 $pagi .= '<br>' . "\n";
1950
1951 return $pagi;
1952 }
1953
1954 // -----------------------------
1955 // Archive Pagination Javascript
1956 // -----------------------------
1957 // 2.3.3.9: renamed function to distinguish from list pagination
1958 function radio_station_archive_pagination_javascript() {
1959
1960 // --- fade out current page and fade in selected page ---
1961 $js = "function radio_archive_page(id, types, pagenum) {
1962 return; /* TEMP */
1963 currentpage = document.getElementById('archive-'+id+'-'+types+'-current-page').value;
1964 if (pagenum == 'next') {
1965 pagenum = parseInt(currentpage) + 1;
1966 pagecount = document.getElementById('archive-'+id+'-'+types+'-page-count').value;
1967 if (pagenum > pagecount) {return;}
1968 }
1969 if (pagenum == 'prev') {
1970 pagenum = parseInt(currentpage) - 1;
1971 if (pagenum < 1) {return;}
1972 }
1973
1974
1975 return false;
1976 }";
1977
1978 // --- enqueue script inline ---
1979 // 2.5.0: use radio_station_add_inline_script
1980 radio_station_add_inline_script( 'radio-station', $js );
1981 }
1982
1983
1984 // -------------------------------
1985 // === Show Related Shortcodes ===
1986 // -------------------------------
1987
1988 // ----------------------------
1989 // Show List Shortcode Abstract
1990 // ----------------------------
1991 function radio_station_show_list_shortcode( $type, $atts ) {
1992
1993 global $radio_station_data;
1994
1995 // --- set shortcode instance ---
1996 // 2.5.0: added for consistency
1997 if ( !isset( $radio_station_data['instances']['show-' . $type . '-list'] ) ) {
1998 $radio_station_data['instances']['show-' . $type . '-list'] = 0;
1999 }
2000 $radio_station_data['instances']['show-' . $type . '-list']++;
2001 $instance = $radio_station_data['instances']['show-' . $type . '-list'];
2002
2003 // --- get time and date formats ---
2004 $timeformat = get_option( 'time_format' );
2005 $dateformat = get_option( 'date_format' );
2006
2007 // 2.5.0: fix for latest type argument
2008 if ( 'latest' == $type ) {
2009 $type = 'post';
2010 if ( !isset( $atts['limit'] ) ) {
2011 $atts['limit'] = 3;
2012 }
2013 }
2014
2015 // --- get shortcode attributes ---
2016 $defaults = array(
2017 'show' => false,
2018 'per_page' => 15,
2019 'limit' => 0,
2020 'content' => 'excerpt',
2021 'thumbnails' => 1,
2022 'pagination' => 1,
2023 // 2.5.6: add ordering defaults
2024 'orderby' => 'date',
2025 'order' => 'DESC',
2026 'channel' => '',
2027 );
2028 // 2.5.6: add filter for default attributes
2029 $defaults = apply_filters( 'radio_station_show_list_defaults_atts', $defaults, $type );
2030 $atts = shortcode_atts( $defaults, $atts, 'show-' . $type . '-list' );
2031
2032 // --- maybe get stored post data ---
2033 if ( isset( $radio_station_data['show-' . $type . 's'] ) ) {
2034
2035 // --- use data stored from template ---
2036 $posts = $radio_station_data['show-' . $type . 's'];
2037 unset( $radio_station_data['show-' . $type . 's'] );
2038 $show_id = $radio_station_data['show-id'];
2039
2040 if ( RADIO_STATION_DEBUG ) {
2041 echo '<span style="display:none;">Stored Show Posts (' . esc_html( $type ) . '):' . esc_html( print_r( $posts, true ) ) . '</span>';
2042 }
2043
2044 } else {
2045 // --- check for show ID (required at minimum) ---
2046 if ( !$atts['show'] ) {
2047 return '';
2048 }
2049 $show_id = $atts['show'];
2050
2051 // --- attempt to get show ID via slug ---
2052 if ( intval( $show_id ) != $show_id ) {
2053 global $wpdb;
2054 $query = "SELECT ID FROM " . $wpdb->prefix . "posts WHERE post_name = %s";
2055 $query = $wpdb->prepare( $query, $show_id );
2056 $show_id = $wpdb->get_var( $query );
2057 if ( !$show_id ) {
2058 return '';
2059 }
2060 }
2061
2062 // --- get related to show posts ---
2063 // 2.3.3.9: also handle host or producer lists
2064 $args = array();
2065 if ( isset( $atts['limit'] ) ) {
2066 $args['limit'] = $atts['limit'];
2067 }
2068
2069 if ( 'post' == $type ) {
2070 // 2.5.5: added filter for show posts
2071 $posts = radio_station_get_show_posts( $show_id, $args );
2072 $posts = apply_filters( 'radio_station_get_show_posts', $posts, $show_id, $args, $atts );
2073 } elseif ( RADIO_STATION_OVERRIDE_SLUG == $type ) {
2074 // 2.5.18: added for linked overrides
2075 $overrides = radio_station_get_linked_override_times( $show_id );
2076 echo '<span style="display:none;">OVERRIDES: ' . print_r( $overrides, true ) . '</span>' . "\n";
2077 if ( !$overrides || !is_array( $overrides ) || count( $overrides ) == 0 ) {
2078 return '';
2079 }
2080 $override_ids = $posts = array();
2081 foreach ( $overrides as $override ) {
2082 if ( !in_array( $override['override_id'], $override_ids ) ) {
2083 $posts[] = get_post( $override['override_id'], ARRAY_A );
2084 $override_ids[] = $override['override_id'];
2085 }
2086 }
2087 $posts = apply_filters( 'radio_station_get_show_overrides', $posts, $show_id, $args, $atts );
2088 $type = 'override';
2089 } elseif ( RADIO_STATION_PLAYLIST_SLUG == $type ) {
2090 // 2.5.5: added filter for show playlists
2091 $posts = radio_station_get_show_playlists( $show_id, $args );
2092 $posts = apply_filters( 'radio_station_get_show_playlists', $posts, $show_id, $args, $atts );
2093 $type = 'playlist';
2094 } elseif ( RADIO_STATION_HOST_SLUG == $type ) {
2095 // 2.5.0: added shortcode atts as fourth argument
2096 $posts = apply_filters( 'radio_station_get_show_hosts', false, $show_id, $args, $atts );
2097 $type = 'host';
2098 } elseif ( RADIO_STATION_PRODUCER_SLUG == $type ) {
2099 // 2.5.0: added shortcode atts as fourth argument
2100 $posts = apply_filters( 'radio_station_get_show_producers', false, $show_id, $args, $atts );
2101 $type = 'producer';
2102 } elseif ( defined( 'RADIO_STATION_EPISODE_SLUG' ) && ( RADIO_STATION_EPISODE_SLUG == $type ) ) {
2103 // 2.5.0: added shortcode atts as fourth argument
2104 $posts = apply_filters( 'radio_station_get_show_episodes', false, $show_id, $args, $atts );
2105 $type = 'episode';
2106 }
2107 if ( RADIO_STATION_DEBUG ) {
2108 echo '<span style="display:none;">Show Posts (' . esc_html( $type ) . '):' . esc_html( print_r( $posts, true ) ) . '</span>';
2109 }
2110 }
2111 if ( !isset( $posts ) || !$posts || !is_array( $posts ) || ( count( $posts ) == 0 ) ) {
2112 return '';
2113 }
2114
2115 // --- filter excerpt length and more ---
2116 $length = apply_filters( 'radio_station_show_' . $type . '_list_excerpt_length', false );
2117 $more = apply_filters( 'radio_station_show_' . $type . '_list_excerpt_more', '[&hellip;]' );
2118
2119 // --- show list div ---
2120 $list = '<div id="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-list" class="show-' . esc_attr( $type ) . 's-list">' . "\n";
2121
2122 // 2.5.18: date/time formatting (for override meta)
2123 if ( isset( $overrides ) ) {
2124 $date_format = apply_filters( 'radio_station_override_date_format', 'j F' );
2125 $time_format = (int) radio_station_get_setting( 'clock_time_format', $show_id );
2126 $start_data_format = $end_data_format = ( 24 == (int) $time_format ) ? 'H:i' : 'g:i a';
2127 $start_data_format = apply_filters( 'radio_station_time_format_start', $start_data_format, 'show-template', $show_id );
2128 $end_data_format = apply_filters( 'radio_station_time_format_end', $end_data_format, 'show-template', $show_id );
2129 $show_post = get_post( $show_id, ARRAY_A );
2130 }
2131
2132 // --- loop show posts ---
2133 $post_pages = 1;
2134 $j = 0;
2135 foreach ( $posts as $post ) {
2136
2137 $meta = '';
2138
2139 if ( is_object( $post ) && is_a( $post, 'WP_Post' ) ) {
2140 $post = get_post( $post->ID, ARRAY_A );
2141 } elseif ( is_int( $post ) || is_string( $post ) ) {
2142 $post = get_post( $post, ARRAY_A );
2143 }
2144
2145 // 2.5.18: handle special overrides
2146 if ( isset( $overrides ) ) {
2147
2148 // --- maybe use linked show data ---
2149 $linked_fields = get_post_meta( $post['ID'], 'linked_show_fields', true );
2150 // echo '<span style="display:none;">LINKED FIELDS: ' . print_r( $linked_fields, true ) . '</span>' . "\n";
2151
2152 if ( is_array( $linked_fields ) ) {
2153 if ( isset( $linked_fields['show_title'] ) && !$linked_fields['show_title'] ) {
2154 $post['post_title'] = $show_post['post_title'];
2155 }
2156 if ( isset( $linked_fields['show_content'] ) && !$linked_fields['show_content'] ) {
2157 $post['post_content'] = $show_post['post_content'];
2158 }
2159 if ( isset( $linked_fields['show_excerpt'] ) && !$linked_fields['show_excerpt'] ) {
2160 $post['post_excerpt'] = $show_post['post_excerpt'];
2161 }
2162 }
2163
2164 // 2.5.18: meta display of date/time for overrides
2165 foreach ( $overrides as $override ) {
2166
2167 if ( $override['override_id'] == $post['ID'] ) {
2168
2169 $start = $override['date'] . ' ' . $override['start_hour'] . ':' . $override['start_min'] . ' ' . $override['start_meridian'];
2170 $end = $override['date'] . ' ' . $override['end_hour'] . ':' . $override['end_min'] . ' ' . $override['end_meridian'];
2171 $override_start_time = radio_station_to_time( $start );
2172 $override_end_time = radio_station_to_time( $end );
2173 if ( $override_end_time <= $override_start_time ) {
2174 $override_end_time = $override_end_time + ( 24 * 60 * 60 );
2175 }
2176
2177 $start_display = radio_station_get_time( $start_data_format, $override_start_time );
2178 $end_display = radio_station_get_time( $end_data_format, $override_end_time );
2179 $start_display = radio_station_translate_time( $start_display );
2180 $end_display = radio_station_translate_time( $end_display );
2181 $date_time = radio_station_to_time( $override['date'] . ' 00:00' );
2182 $date = radio_station_get_time( $date_format, $date_time );
2183
2184 $separator = ' - ';
2185 $separator = apply_filters( 'radio_station_show_times_separator', $separator, 'override-content' );
2186
2187 $meta .= '<div class="override-time">' . "\n";
2188 $meta .= '<span class="rs-date rs-start-date" data-format="' . esc_attr( $date_format ) . '" data="' . esc_attr( $date_time ) . '">' . esc_html( $date ) . '</span>' . "\n";
2189 $meta .= '<span class="rs-time rs-start-time" data-format="' . esc_attr( $start_data_format ) . '" data="' . esc_attr( $override_start_time ) . '">' . esc_html( $start_display ) . '</span>' . "\n";
2190 $meta .= '<span class="rs-sep">' . esc_html( $separator ) . '</span>' . "\n";
2191 $meta .= '<span class="rs-time rs-end-time" data-format="' . esc_attr( $end_data_format ) . '" data="' . esc_attr( $override_end_time ) . '">' . esc_html( $end_display ) . '</span>' . "\n";
2192 $meta .= '</div>' . "\n";
2193
2194 $meta .= '<div class="show-user-time">' . "\n";
2195 $meta .= '[<span class="rs-date rs-start-date"></span>' . "\n";
2196 $meta .= '<span class="rs-time rs-start-time"></span>' . "\n";
2197 $meta .= '<span class="rs-sep">' . esc_html( $separator ) . '</span>' . "\n";
2198 $meta .= '<span class="rs-time rs-end-time"></span>]' . "\n";
2199 $meta .= '</div>' . "\n";
2200
2201 // echo '<span style="display:none;">META: ' . $meta . '</span>' . "\n";
2202
2203 }
2204 }
2205 }
2206
2207 $newpage = $firstpage = false;
2208 if ( 0 == $j ) {
2209 $newpage = $firstpage = true;
2210 } elseif ( $j == $atts['per_page'] ) {
2211 // --- close page div ---
2212 $list .= '</div>' . "\n";
2213 $newpage = true;
2214 $post_pages++;
2215 $j = 0;
2216 }
2217 if ( $newpage ) {
2218 // --- new page div ---
2219 $hide = !$firstpage ? ' style="display:none;"' : '';
2220 $list .= '<div id="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-page-' . esc_attr( $post_pages ) . '" class="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-page"' . $hide . '>' . "\n";
2221 }
2222
2223 // --- new item div ---
2224 $classes = array( 'show-' . $type );
2225 if ( $newpage ) {
2226 $classes[] = 'first-item';
2227 }
2228 $class = implode( ' ', $classes );
2229 $list .= '<div class="' . esc_attr( $class ) . '">' . "\n";
2230
2231 // 2.3.3.9: check if this object is instance of WP_User class
2232 if ( is_a( $post, 'WP_User' ) ) {
2233
2234 // --- this is a user without a profile post ---
2235 $user = $post;
2236 $user_id = $user->data->ID;
2237
2238 // TODO: add check for user avatar ?
2239
2240 $list .= '<div class="show-' . esc_attr( $type ) . '-info">' . "\n";
2241
2242 // --- link to author page ---
2243 $permalink = get_author_posts_url( $user_id );
2244 $title = __( 'View all posts by %s', 'radio-station' );
2245 $title = sprintf( $title, $user->display_name ) . "\n";
2246 $list .= '<div class="show-' . esc_attr( $type ) . '-title">' . "\n";
2247 $list .= '<a href="' . esc_url( $permalink ) . '" title="' . esc_attr( $title ) . '">' . "\n";
2248 $list .= esc_attr( $user->display_name ) . "\n";
2249 $list .= '</a>' . "\n";
2250 $list .= '</div>' . "\n";
2251
2252 // --- author bio/excerpt ---
2253 $userdata = get_user_meta( $user_id );
2254 $bio_content = $userdata->description[0];
2255 if ( 'none' == $atts['content'] ) {
2256 $list .= '';
2257 } elseif ( 'full' == $atts['content'] ) {
2258 // 2.5.6: fix to filter variable assignment content
2259 $bio_content = apply_filters( 'radio_station_show_' . $type . '_content', $bio_content, $user_id );
2260 $list .= '<div class="show-' . esc_attr( $type ) . '-content">' . "\n";
2261 // 2.5.0: use wp_kses on bio content output
2262 $allowed = radio_station_allowed_html( 'content', 'bio' );
2263 $list .= wp_kses( $bio_content, $allowed ) . "\n";
2264 $list .= '</div>' . "\n";
2265 } else {
2266 $permalink = get_author_posts_url( $user_id );
2267 $excerpt = radio_station_trim_excerpt( $bio_content, $length, $more, $permalink );
2268 $excerpt = apply_filters( 'radio_station_show_' . $type . '_excerpt', $excerpt, $user_id );
2269 $list .= '<div class="show-' . esc_attr( $type ) . '-excerpt">' . "\n";
2270 // 2.5.0: use wp_kses on excerpt output
2271 $allowed = radio_station_allowed_html( 'content', 'excerpt' );
2272 $list .= wp_kses( $excerpt, $allowed ) . "\n";
2273 $list .= '</div>' . "\n";
2274 }
2275
2276 $list .= '</div>' . "\n";
2277
2278 } else {
2279
2280 // 2.5.0: fix to maybe get post object
2281 // 2.5.18: fix for different data types
2282 /* if ( is_object( $post ) && is_a( $post, 'WP_Post' ) ) {
2283 $post = get_post( $post->ID, ARRAY_A );
2284 } elseif ( is_int( $post ) || is_string( $post ) ) {
2285 $post = get_post( $post, ARRAY_A );
2286 } */
2287
2288 // --- post thumbnail ---
2289 if ( $atts['thumbnails'] ) {
2290 $thumbnail = false;
2291 $thumbnail_source = $post['ID'];
2292 // if ( isset( $overrides ) && !in_array( 'show_avatar', $linked_fields ) ) {
2293 // $thumbnail_source = $show_post['ID'];
2294 // }
2295 $has_thumbnail = has_post_thumbnail( $thumbnail_source );
2296 if ( $has_thumbnail ) {
2297 $attr = array( 'class' => 'show-' . esc_attr( $type ) . '-thumbnail-image' );
2298 $thumbnail = get_the_post_thumbnail( $thumbnail_source, 'thumbnail', $attr );
2299 }
2300 $thumbnail = apply_filters( 'radio_station_show_list_archive_avatar', $thumbnail, $thumbnail_source, $type );
2301 if ( $thumbnail ) {
2302 $list .= '<div class="show-' . esc_attr( $type ) . '-thumbnail">' . "\n";
2303 // 2.5.0: use wp_kses on thumbnail output
2304 $allowed = radio_station_allowed_html( 'media', 'image' );
2305 $list .= wp_kses( $thumbnail, $allowed ) . "\n";
2306 $list .= '</div>' . "\n";
2307 }
2308 }
2309
2310 $list .= '<div class="show-' . esc_attr( $type ) . '-info">' . "\n";
2311
2312 // --- link to post ---
2313 $permalink = get_permalink( $post['ID'] );
2314 $publish_time = mysql2date( $dateformat . ' ' . $timeformat, $post['post_date'], false );
2315 $title = __( 'Published on ', 'radio-station' ) . $publish_time;
2316 $list .= '<div class="show-' . esc_attr( $type ) . '-title">' . "\n";
2317 $list .= '<a href="' . esc_url( $permalink ) . '" title="' . esc_attr( $title ) . '">' . "\n";
2318 // 2.5.0: use esc_html instead of esc_attr
2319 $list .= esc_html( $post['post_title'] ) . "\n";
2320 $list .= '</a>' . "\n";
2321 $list .= '</div>' . "\n";
2322
2323 // --- post meta ---
2324 // 2.5.6: add filtered post meta
2325 $meta = apply_filters( 'radio_station_show_' . $type . '_shortcode_meta', $meta, $post, $type, $atts );
2326 if ( '' != $meta ) {
2327 // 2.5.18: added meta wrapper
2328 $list .= '<div class="show-' . esc_attr( $type ) . '-meta">' . "\n";
2329 $allowed = radio_station_allowed_html( 'content', 'meta' );
2330 $list .= wp_kses( $meta, $allowed ) . "\n";
2331 $list .= '</div>';
2332 }
2333
2334 // --- post excerpt ---
2335 $post_content = $post['post_content'];
2336 $post_id = $post['ID'];
2337 if ( 'none' == $atts['content'] ) {
2338 $list .= '';
2339 } elseif ( 'full' == $atts['content'] ) {
2340 $content = apply_filters( 'radio_station_show_' . $type . '_content', $post_content, $post_id );
2341 $list .= '<div class="show-' . esc_attr( $type ) . '-content">' . "\n";
2342 // 2.5.0: use wp_kses on content output
2343 $allowed = radio_station_allowed_html( 'content', 'full' );
2344 $list .= wp_kses( $content, $allowed ) . "\n";
2345 $list .= '</div>' . "\n";
2346 } else {
2347 $permalink = get_permalink( $post['ID'] );
2348 if ( !empty( $post['post_excerpt'] ) ) {
2349 $excerpt = $post['post_excerpt'];
2350 // 2.5.0: use esc_html on more anchor text
2351 $excerpt .= ' <a href="' . esc_url( $permalink ) . '">' . esc_html( $more ) . '</a>' . "\n";
2352 } else {
2353 $excerpt = radio_station_trim_excerpt( $post_content, $length, $more, $permalink );
2354 }
2355 $excerpt = apply_filters( 'radio_station_show_' . $type . '_excerpt', $excerpt, $post_id );
2356
2357 // 2.5.0: added check excerpt is not empty
2358 if ( '' != $excerpt ) {
2359 $list .= '<div class="show-' . esc_attr( $type ) . '-excerpt">' . "\n";
2360 // 2.5.0: use wp_kses on excerpt output
2361 $allowed = radio_station_allowed_html( 'content', 'excerpt' );
2362 $list .= wp_kses( $excerpt, $allowed ) . "\n";
2363 $list .= '</div>' . "\n";
2364 }
2365 }
2366 $list .= '</div>' . "\n";
2367 }
2368
2369 // --- close item div ---
2370 $list .= '</div>' . "\n";
2371 $j ++;
2372 }
2373
2374 // --- close last page div ---
2375 $list .= '</div>' . "\n";
2376
2377 // --- list pagination ---
2378 // 2.3.3.9: fix to hide left arrow display on load
2379 if ( $atts['pagination'] && ( $post_pages > 1 ) ) {
2380 $list .= '<br>' . "\n";
2381 $list .= '<div id="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-page-buttons" class="show-pagination-buttons show-' . esc_attr( $type ) . 's-page-buttons">' . "\n";
2382 $list .= '<div id="show-' . esc_attr( $type ) . 's-pagination-button-left" class="show-pagination-button arrow-button-left arrow-button" onclick="radio_list_page(\'show\', ' . esc_js( $show_id ) . ', \'' . esc_js( $type ) . 's\', \'prev\');" style="display:none;">' . "\n";
2383 $list .= '<a href="javascript:void(0);">&larr;</a>' . "\n";
2384 $list .= '</div>' . "\n";
2385 for ( $pagenum = 1; $pagenum < ( $post_pages + 1 ); $pagenum++ ) {
2386 if ( 1 == $pagenum ) {
2387 $active = ' active';
2388 } else {
2389 $active = '';
2390 }
2391 $onclick = 'radio_list_page(\'show\', ' . esc_js( $show_id ) . ', \'' . esc_js( $type ) . 's\', ' . esc_js( $pagenum ) . ');';
2392 $list .= '<div id="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ). 's-page-button-' . esc_attr( $pagenum ) . '" class="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-page-button show-pagination-button' . esc_attr( $active ) . '" onclick="' . $onclick . '">' . "\n";
2393 $list .= '<a href="javascript:void(0);">' . "\n";
2394 $list .= esc_html( $pagenum ) . "\n";
2395 $list .= '</a>' . "\n";
2396 $list .= '</div>' . "\n";
2397 }
2398 $list .= '<div id="show-' . esc_attr( $type ) . 's-pagination-button-right" class="show-pagination-button arrow-button" onclick="radio_list_page(\'show\', ' . esc_js( $show_id ) . ', \'' . esc_js( $type ). 's\', \'next\');">' . "\n";
2399 $list .= '<a href="javascript:void(0);">&rarr;</a>' . "\n";
2400 $list .= '</div>' . "\n";
2401 $list .= '<input type="hidden" id="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-current-page" value="1">' . "\n";
2402 $list .= '<input type="hidden" id="show-' . esc_attr( $show_id ) . '-' . esc_attr( $type ) . 's-page-count" value="' . esc_attr( $post_pages ) . '">' . "\n";
2403 $list .= '</div>' . "\n";
2404 }
2405
2406 // --- close list div ---
2407 $list .= '</div>' . "\n";
2408
2409 // --- enqueue shortcode styles ---
2410 radio_station_enqueue_style( 'shortcodes' );
2411
2412 // --- enqueue pagination javascript ---
2413 add_action( 'wp_footer', 'radio_station_list_pagination_javascript' );
2414
2415 // --- filter and return ---
2416 $list = apply_filters( 'radio_station_show_' . $type . '_list', $list, $atts, $instance );
2417 return $list;
2418 }
2419
2420 // ----------------------------
2421 // Show Posts Archive Shortcode
2422 // ----------------------------
2423 // requires: show shortcode attribute, eg. [show-posts-list show="1"]
2424 add_shortcode( 'show-posts-archive', 'radio_station_show_posts_archive' );
2425 add_shortcode( 'show-post-archive', 'radio_station_show_posts_archive' );
2426 function radio_station_show_posts_archive( $atts ) {
2427 $output = radio_station_show_list_shortcode( 'post', $atts );
2428 return $output;
2429 }
2430
2431 // -----------------------------------
2432 // Show Latest Posts Archive Shortcode
2433 // -----------------------------------
2434 add_shortcode( 'show-latests-archive', 'radio_station_show_latest_archive' );
2435 add_shortcode( 'show-latest-archive', 'radio_station_show_latest_archive' );
2436 function radio_station_show_latest_archive( $atts ) {
2437 $output = radio_station_show_list_shortcode( 'latest', $atts );
2438 return $output;
2439 }
2440
2441 // --------------------------------
2442 // Show Overrides Archive Shortcode
2443 // --------------------------------
2444 // 2.5.18: added for displaying linked overrides on show page
2445 add_shortcode( 'show-overrides-archive', 'radio_station_show_overrides_archive' );
2446 add_shortcode( 'show-override-archive', 'radio_station_show_overrides_archive' );
2447 function radio_station_show_overrides_archive( $atts ) {
2448 $output = radio_station_show_list_shortcode( RADIO_STATION_OVERRIDE_SLUG, $atts );
2449 return $output;
2450 }
2451
2452 // --------------------------------
2453 // Show Playlists Archive Shortcode
2454 // --------------------------------
2455 // requires: show shortcode attribute, eg. [show-playlists-list show="1"]
2456 add_shortcode( 'show-playlists-archive', 'radio_station_show_playlists_archive' );
2457 add_shortcode( 'show-playlist-archive', 'radio_station_show_playlists_archive' );
2458 function radio_station_show_playlists_archive( $atts ) {
2459 $output = radio_station_show_list_shortcode( RADIO_STATION_PLAYLIST_SLUG, $atts );
2460 return $output;
2461 }
2462
2463 // --------------------------------
2464 // Show Lists Pagination Javascript
2465 // --------------------------------
2466 // 2.3.3.9: renamed function to distinguish from archive pagination
2467 function radio_station_list_pagination_javascript() {
2468
2469 // --- fade out current page and fade in selected page ---
2470 // 2.3.3.9: added selector prefix as argument
2471 // 2.3.3.9: fix to conditional arrow displays
2472 $js = "function radio_list_page(prefix, id, types, pagenum) {
2473 currentpage = document.getElementById(prefix+'-'+id+'-'+types+'-current-page').value;
2474 pagecount = document.getElementById(prefix+'-'+id+'-'+types+'-page-count').value;
2475 if (pagenum == 'next') {
2476 pagenum = parseInt(currentpage) + 1;
2477 if (pagenum > pagecount) {return;}
2478 }
2479 if (pagenum == 'prev') {
2480 pagenum = parseInt(currentpage) - 1;
2481 if (pagenum < 1) {return;}
2482 }
2483 if (typeof jQuery == 'function') {
2484 jQuery('.'+prefix+'-'+id+'-'+types+'-page').fadeOut(500);
2485 jQuery('#'+prefix+'-'+id+'-'+types+'-page-'+pagenum).fadeIn(1000);
2486 jQuery('.'+prefix+'-'+id+'-'+types+'-page-button').removeClass('active');
2487 jQuery('#'+prefix+'-'+id+'-'+types+'-page-button-'+pagenum).addClass('active');
2488 jQuery('#'+prefix+'-'+id+'-'+types+'-current-page').val(pagenum);
2489 } else {
2490 pages = document.getElementsByClassName(prefix+'-'+id+'-'+types+'-page');
2491 for (i = 0; i < pages.length; i++) {pages[i].style.display = 'none';}
2492 document.getElementById(prefix+'-'+id+'-'+types+'-page-'+pagenum).style.display = '';
2493 buttons = document.getElementsByClassName(prefix+'-'+id+'-'+types+'-page-button');
2494 for (i = 0; i < buttons.length; i++) {buttons[i].classList.remove('active');}
2495 document.getElementById(prefix+'-'+id+'-'+types+'-page-button-'+pagenum).classList.add('active');
2496 document.getElementById(prefix+'-'+id+'-'+types+'-current-page').value = pagenum;
2497 }
2498 larrow = document.getElementById(prefix+'-'+types+'-pagination-button-left');
2499 rarrow = document.getElementById(prefix+'-'+types+'-pagination-button-right');
2500 larrow.style.display = ''; rarrow.style.display = '';
2501 if (pagenum == 1) {larrow.style.display = 'none';}
2502 else if (pagenum == pagecount) {rarrow.style.display = 'none';}
2503 console.log(pagenum+' - '+pagecount);
2504 }";
2505
2506 // --- enqueue script inline ---
2507 // 2.3.0: enqueue instead of echoing
2508 // 2.5.0: use radio_station_add_inline_script
2509 radio_station_add_inline_script( 'radio-station', $js );
2510 }
2511
2512
2513 // -------------------------
2514 // === Widget Shortcodes ===
2515 // -------------------------
2516
2517 // ----------------------
2518 // Current Show Shortcode
2519 // ----------------------
2520 // [current-show] / [dj-widget]
2521 // 2.0.9: shortcode function for current DJ on-air
2522 // 2.3.0: added missing output sanitization
2523 // 2.3.0: added current-show shortcode alias
2524 add_shortcode( 'dj-widget', 'radio_station_current_show_shortcode' );
2525 add_shortcode( 'current-show', 'radio_station_current_show_shortcode' );
2526 function radio_station_current_show_shortcode( $atts ) {
2527
2528 global $radio_station_data;
2529
2530 // --- set widget instance ID ---
2531 // 2.3.2: added for AJAX loading
2532 if ( !isset( $radio_station_data['instances']['current_show'] ) ) {
2533 $radio_station_data['instances']['current_show'] = 0;
2534 }
2535 $radio_station_data['instances']['current_show']++;
2536 $instance = $radio_station_data['instances']['current_show'];
2537
2538 $output = '';
2539
2540 // --- set default time format ---
2541 $time_format = radio_station_get_setting( 'clock_time_format' );
2542
2543 // 2.3.2: get default AJAX load settings
2544 // 2.5.0: unset empty AJAX attribute to use default
2545 $ajax = radio_station_get_setting( 'ajax_widgets', false );
2546 $ajax = ( 'yes' == $ajax ) ? 'on' : 'off';
2547 if ( isset( $atts['ajax'] ) && ( '' == $atts['ajax'] ) ) {
2548 unset( $atts['ajax'] );
2549 }
2550
2551 // --- apply filters for dynamic reload value ---
2552 // 2.5.0: added instance as third filter argument
2553 $dynamic = apply_filters( 'radio_station_current_show_dynamic', false, $atts, $instance );
2554 $dynamic = $dynamic ? 1 : 0;
2555
2556 // 2.3.3: use plugin setting if time format attribute is empty
2557 // 2.5.0: fix to update time attribute to time_format
2558 if ( isset( $atts['time'] ) ) {
2559 if ( '' != trim( $atts['time'] ) ) {
2560 $atts['time_format'] = $atts['time'];
2561 }
2562 unset( $atts['time'] );
2563 }
2564
2565 // 2.5.0: change to default_name attribute key
2566 if ( isset( $atts['default_name'] ) ) {
2567 $atts['no_shows'] = $atts['default_name'];
2568 unset( $atts['default_name'] );
2569 }
2570
2571 // --- get shortcode attributes ---
2572 // 2.3.0: set default default_name text
2573 // 2.3.0: set default time format to plugin setting
2574 // 2.3.2: added AJAX load attribute
2575 // 2.3.2: added for_time attribute
2576 // 2.3.3.8: added show_encore attribute (default 1)
2577 // 2.3.3.9: added avatar_size attribute (default thumbnail)
2578 // 2.3.3.9: added show_title attribute (default 1)
2579 // 2.5.0: removed show_title attribute (as always needed)
2580 // 2.5.0: change default_name key to no_shows text
2581 $defaults = array(
2582 // --- legacy options ---
2583 'title' => '',
2584 'ajax' => $ajax,
2585 'dynamic' => $dynamic,
2586 'no_shows' => '',
2587 'hide_empty' => 0,
2588 // --- show display options ---
2589 'show_link' => 1,
2590 'title_position' => 'right',
2591 'show_avatar' => 1,
2592 'avatar_width' => '',
2593 'avatar_size' => 'thumbnail',
2594 // --- show time display options ---
2595 'show_sched' => 1,
2596 'show_all_sched' => 0,
2597 'countdown' => 0,
2598 'time_format' => $time_format,
2599 // --- extra display options ---
2600 'display_hosts' => 0,
2601 'link_hosts' => 0,
2602 // 'display_producers' => 0,
2603 // 'link_producers' => 0,
2604 'show_desc' => 0,
2605 'show_playlist' => 1,
2606 'show_encore' => 1,
2607 // --- widget data ---
2608 'widget' => 0,
2609 'block' => 0,
2610 'id' => '',
2611 'for_time' => 0,
2612 // --- channel ---
2613 'channel' => '',
2614 );
2615 // 2.3.0: convert old attributes for DJs to hosts
2616 if ( isset( $atts['display_djs'] ) && !isset( $atts['display_hosts'] ) ) {
2617 $atts['display_hosts'] = $atts['display_djs'];
2618 unset( $atts['display_djs'] );
2619 }
2620 if ( isset( $atts['link_djs'] ) && !isset( $atts['link_hosts'] ) ) {
2621 $atts['link_hosts'] = $atts['link_djs'];
2622 unset( $atts['link_djs'] );
2623 }
2624 // 2.3.0: renamed shortcode identifier to current-show
2625 // 2.5.18: added filter for default Attributes
2626 $defaults = apply_filters( 'radio_station_current_show_default_atts', $defaults );
2627 $atts = shortcode_atts( $defaults, $atts, 'current-show' );
2628
2629 // 2.3.2: enqueue countdown script earlier
2630 // 2.5.10: enqueue countdown for dynamic reloading
2631 if ( $atts['countdown'] || $atts['dynamic'] ) {
2632 do_action( 'radio_station_countdown_enqueue' );
2633 }
2634
2635 // 2.3.3: add current time override for manual testing
2636 if ( isset( $_GET['date'] ) && isset( $_GET['time'] ) ) {
2637 $date = trim( sanitize_text_field( $_GET['date'] ) );
2638 $time = trim( sanitize_text_field( $_GET['time'] ) );
2639 if ( isset( $_GET['month'] ) ) {
2640 $month = absint( trim( $_GET['month'] ) );
2641 } else {
2642 $month = radio_station_get_time( 'm' );
2643 }
2644 if ( isset( $_GET['year'] ) ) {
2645 $year = absint( trim( $_GET['year'] ) );
2646 } else {
2647 $year = radio_station_get_time( 'Y' );
2648 }
2649 if ( strstr( $time, ':' ) && ( $month > 0 ) && ( $month < 13 ) ) {
2650 $parts = explode( ':', $time );
2651 $time = absint( $parts[0] ) . ':' . absint( $parts[1] );
2652 $for_time = radio_station_to_time( $year . '-' . $month . '-' . $date . ' ' . $time );
2653 $atts['for_time'] = $for_time;
2654 echo "<script>console.log('Override Current Time: " . esc_js( $for_time ) . "');</script>";
2655 }
2656 }
2657
2658 // --- maybe do AJAX load ---
2659 // 2.3.2 added widget AJAX loading
2660 $ajax = $atts['ajax'];
2661 $widget = $atts['widget'];
2662 $ajax = apply_filters( 'radio_station_widgets_ajax_override', $ajax, 'current-show', $widget );
2663 if ( 'on' === (string) $ajax ) {
2664 if ( !defined( 'DOING_AJAX' ) || !DOING_AJAX ) {
2665
2666 // --- AJAX load via iframe ---
2667 $ajax_url = admin_url( 'admin-ajax.php' );
2668 $html = '<div id="rs-current-show-' . esc_attr( $instance ) . '" class="ajax-widget"></div>' . "\n";
2669 $html .= '<iframe id="rs-current-show-' . esc_attr( $instance ) . '-loader" src="javascript:void(0);" style="display:none;"></iframe>' . "\n";
2670
2671 // --- shortcode loader script ---
2672 $html .= "<script>" . "\n";
2673 $html .= "timestamp = Math.floor( (new Date()).getTime() / 1000 );" . "\n";
2674 $html .= "url = '" . esc_url( $ajax_url ) . "?action=radio_station_current_show';" . "\n";
2675 $html .= "url += '&instance=" . esc_js( $instance ) . "';" . "\n";
2676 if ( RADIO_STATION_DEBUG ) {
2677 $html .= "url += '&rs-debug=1';";
2678 }
2679 $html .= "url += '";
2680 foreach ( $atts as $key => $value ) {
2681 // 2.5.7: fix to ensure for_time is used for timestamp
2682 if ( ( 'for_time' == $key ) && ( 0 == $value ) ) {
2683 $html .= "&for_time='+timestamp+'";
2684 } else {
2685 $value = radio_station_encode_uri_component( $value );
2686 $html .= "&" . esc_js( $key ) . "=" . esc_js( $value );
2687 }
2688 }
2689 $html .= "';" . "\n";
2690 $html .= "document.getElementById('rs-current-show-" . esc_js( $instance ) ."-loader').src = url;" . "\n";
2691 $html .= "</script>" . "\n";
2692
2693 // --- enqueue shortcode styles ---
2694 radio_station_enqueue_style( 'shortcodes' );
2695
2696 // 2.6.7: filter to enqueue= reloader script in current window
2697 if ( $atts['dynamic'] ) {
2698 $dynamic = apply_filters( 'radio_station_countdown_dynamic', false, 'current-show', $atts, false );
2699 }
2700
2701 return $html;
2702 }
2703 }
2704
2705 // 2.3.0: maybe set float class and avatar width style
2706 // 2.5.0: use absint and above zero check on avatart_width
2707 $widthstyle = $floatclass = '';
2708 if ( absint( $atts['avatar_width'] ) > 0 ) {
2709 $widthstyle = 'style="width:' . esc_attr( $atts['avatar_width'] ) . 'px;"';
2710 }
2711 if ( 'right' == $atts['title_position'] ) {
2712 $floatclass = ' float-left';
2713 } elseif ( 'left' == $atts['title_position'] ) {
2714 $floatclass = ' float-right';
2715 }
2716
2717 // --- maybe filter excerpt values ---
2718 // 2.3.0: added context specific excerpt value filtering
2719 if ( $atts['show_desc'] ) {
2720 if ( $atts['widget'] ) {
2721 $length = apply_filters( 'radio_station_current_show_widget_excerpt_length', false );
2722 $more = apply_filters( 'radio_station_current_show_widget_excerpt_more', '[&hellip;]' );
2723 } else {
2724 $length = apply_filters( 'radio_station_current_show_shortcode_excerpt_length', false );
2725 $more = apply_filters( 'radio_station_current_show_shortcode_excerpt_more', '[&hellip;]' );
2726 }
2727 }
2728
2729 // --- get current show ---
2730 // note: current show is not split shift
2731 // 2.3.0: use new get current show function
2732 // 2.3.2: added attribute to pass time argument
2733 if ( $atts['for_time'] ) {
2734 $current_shift = radio_station_get_current_show( $atts['for_time'] );
2735 $time = radio_station_get_time( 'datetime', $atts['for_time'] );
2736 if ( RADIO_STATION_DEBUG ) {
2737 echo '<span style="display:none;">' . "\n";
2738 echo 'Current Shift For Time: ' . esc_html( $atts['for_time'] ) . ' : ' . esc_html( $time ) . "\n";
2739 echo esc_html( print_r( $current_shift, true ) ) . "\n";
2740 echo '</span>' . "\n";
2741 }
2742 } else {
2743 $current_shift = radio_station_get_current_show();
2744 }
2745
2746 // --- open shortcode div wrapper ---
2747 if ( !$atts['widget'] ) {
2748
2749 // 2.3.0: add unique id to widget shortcode
2750 // 2.3.2: add shortcode wrap class
2751 // 2.5.0: change id key to shortcode NOT widget
2752 // 2.5.0: simplified to use existing instance count
2753 $id = 'current-show-shortcode-' . $instance;
2754 $output .= '<div id="' . esc_attr( $id ) . '" class="current-show-wrap current-show-embedded on-air-embedded dj-on-air-embedded">' . "\n";
2755
2756 }
2757
2758 // --- shortcode title ---
2759 // 2.5.0: also display title for non-shortcodes if set
2760 // 2.5.7: but do not display for widgets (duplication)
2761 if ( ( '' != $atts['title'] ) && ( 0 != $atts['title'] ) && !$atts['widget'] ) {
2762 // 2.3.3.9: fix class to not conflict with actual show title
2763 $output .= '<h3 class="current-show-shortcode-title">' . "\n";
2764 $output .= esc_html( $atts['title'] ) . "\n";
2765 $output .= '</h3>' . "\n";
2766 }
2767
2768 // --- open current show list ---
2769 // 2.5.0: add countdown class for countdown script targeting
2770 // 2.5.10: add countdown class for dynamic reloading
2771 $classes = array( 'current-show-list', 'on-air-list' );
2772 if ( $atts['countdown'] || $atts['dynamic'] ) {
2773 $classes[] = 'countdown';
2774 }
2775 $class_list = implode( ' ', $classes );
2776 $output .= '<ul class="' . esc_attr( $class_list ) . '">' . "\n";
2777
2778 // --- current shift display ---
2779 if ( $current_shift ) {
2780
2781 // --- get time formats ---
2782 // 2.3.2: moved out to get once
2783 // 2.4.0.6: added filter for default time format separator
2784 $time_separator = ':';
2785 $time_separator = apply_filters( 'radio_station_time_separator', $time_separator, 'current-show' );
2786 if ( 24 == (int) $atts['time_format'] ) {
2787 $start_data_format = $end_data_format = 'H' . $time_separator . 'i';
2788 } else {
2789 $start_data_format = $end_data_format = 'g' . $time_separator . 'i a';
2790 }
2791 $start_data_format = 'l, ' . $start_data_format;
2792 $start_data_format = apply_filters( 'radio_station_time_format_start', $start_data_format, 'current-show', $atts );
2793 $end_data_format = apply_filters( 'radio_station_time_format_end', $end_data_format, 'current-show', $atts );
2794
2795 // --- set html output ---
2796 // 2.3.1: store all HTML to allow section re-ordering
2797 $html = array( 'title' => '' );
2798
2799 // --- set current show data ---
2800 $show = $current_shift['show'];
2801 $show_id = $show['id'];
2802
2803 // --- get show link ---
2804 $show_link = false;
2805 if ( $atts['show_link'] ) {
2806 $show_link = get_permalink( $show_id );
2807 $show_link = apply_filters( 'radio_station_current_show_link', $show_link, $show_id, $atts );
2808 }
2809
2810 // --- check show schedule ---
2811 // 2.3.1: check early for later display
2812 // 2.5.17: remove condition so reloading/countdown always have current show start/end data
2813 // if ( $atts['show_sched'] || $atts['show_all_sched'] ) {
2814
2815 // --- show times subheading ---
2816 // 2.3.0: added for all shift display
2817 if ( $atts['show_all_sched'] ) {
2818 $shift_display = '<div class="current-show-schedule on-air-dj-schedule">' . "\n";
2819 $shift_display = '<div class="current-show-schedule-title on-air-dj-schedule-title">' . "\n";
2820 $shift_display .= esc_html( __( 'Show Times', 'radio-station' ) ) . "\n";
2821 $shift_display .= '</div>' . "\n";
2822 }
2823
2824 // --- maybe show all shifts ---
2825 // (only if not a schedule override)
2826 // 2.3.2: fix to override variable key check
2827 if ( !isset( $current_shift['override'] ) && $atts['show_all_sched'] ) {
2828 $shifts = radio_station_get_show_schedule( $show_id );
2829 } else {
2830 $shifts = array( $current_shift );
2831 }
2832
2833 // --- get weekdates ---
2834 // 2.3.0: use dates for reliability
2835 if ( $atts['for_time'] ) {
2836 $now = $atts['for_time'];
2837 } else {
2838 $now = radio_station_get_now();
2839 }
2840 $today = radio_station_get_time( 'l', $now );
2841 $yesterday = radio_station_get_previous_day( $today );
2842 $weekdays = radio_station_get_schedule_weekdays( $yesterday );
2843 $weekdates = radio_station_get_schedule_weekdates( $weekdays, $now );
2844
2845 foreach ( $shifts as $i => $shift ) {
2846
2847 // --- set shift start and end ---
2848 if ( isset( $shift['real_start'] ) ) {
2849 $start = $shift['real_start'];
2850 } elseif ( isset( $shift['start'] ) ) {
2851 $start = $shift['start'];
2852 } else {
2853 $start = $shift['start_hour'] . ':' . $shift['start_min'] . ' ' . $shift['start_meridian'];
2854 }
2855 if ( isset( $shift['real_end'] ) ) {
2856 $end = $shift['real_end'];
2857 } elseif ( isset( $shift['end'] ) ) {
2858 $end = $shift['end'];
2859 } else {
2860 $end = $shift['end_hour'] . ':' . $shift['end_min'] . ' ' . $shift['end_meridian'];
2861 }
2862
2863 // --- convert shift info ---
2864 // 2.2.2: translate weekday for display
2865 // 2.3.0: use dates for reliability
2866 // 2.3.2: replace strtotime with to_time for timezones
2867 // 2.3.2: fix to conver to 24 hour format first
2868 $start_time = radio_station_convert_shift_time( $start );
2869 $end_time = radio_station_convert_shift_time( $end );
2870 if ( isset( $shift['real_start'] ) ) {
2871 $prevday = radio_station_get_previous_day( $shift['day'] );
2872 $shift_start_time = radio_station_to_time( $weekdates[$prevday] . ' ' . $start_time );
2873 } else {
2874 $shift_start_time = radio_station_to_time( $weekdates[$shift['day']] . ' ' . $start_time );
2875 }
2876 $shift_end_time = radio_station_to_time( $weekdates[$shift['day']] . ' ' . $end_time );
2877 // 2.3.3.9: added or equals to operator
2878 if ( $shift_end_time <= $shift_start_time ) {
2879 $shift_end_time = $shift_end_time + ( 24 * 60 * 60 );
2880 }
2881
2882 // --- get shift display times ---
2883 // 2.3.2: use time formats with translations
2884 // $display_day = radio_station_translate_weekday( $shift['day'] );
2885 $start = radio_station_get_time( $start_data_format, $shift_start_time );
2886 $end = radio_station_get_time( $end_data_format, $shift_end_time );
2887 $start = radio_station_translate_time( $start );
2888 $end = radio_station_translate_time( $end );
2889
2890 // 2.4.0.6: use filtered shift separator
2891 $separator = ' - ';
2892 $separator = apply_filters( 'radio_station_show_times_separator', $separator, 'current-show' );
2893
2894 // --- set shift classes ---
2895 // 2.4.0.6: fix for exact current time as start time
2896 $classes = array( 'current-show-shifts', 'on-air-dj-sched' );
2897 if ( ( $now >= $shift_start_time ) && ( $now < $shift_end_time ) ) {
2898 $current_shift_start = $shift_start_time;
2899 $current_shift_end = $shift_end_time;
2900 $classes[] = 'current-shift';
2901 $classlist = implode( ' ', $classes );
2902
2903 $current_shift_display = '<div class="' . esc_attr( $classlist ) . '">' . "\n";
2904 $current_shift_display .= '<span class="rs-time rs-start-time" data="' . esc_attr( $shift_start_time ) . '" data-format="' . esc_attr( $start_data_format ) . '">' . esc_html( $start ) . '</span>' . "\n";
2905 $current_shift_display .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
2906 $current_shift_display .= '<span class="rs-time rs-end-time" data="' . esc_attr( $shift_end_time ) . '" data-format="' . esc_attr( $end_data_format ) . '">' . esc_html( $end ) . '</span>' . "\n";
2907 $current_shift_display .= '</div>' . "\n";
2908
2909 // 2.3.3.9: add show user time div
2910 $current_shift_display .= '<div class="show-user-time">' . "\n";
2911 $current_shift_display .= '[<span class="rs-user-time rs-start-time"></span>' . "\n";
2912 $current_shift_display .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
2913 $current_shift_display .= '<span class="rs-user-time rs-end-time"></span>]' . "\n";
2914 $current_shift_display .= '</div>' . "\n";
2915
2916 }
2917 $classlist = implode( ' ', $classes );
2918
2919 // --- shift display output ---
2920 if ( $atts['show_all_sched'] ) {
2921 $shift_display .= '<div class="' . esc_attr( $classlist ) . '">' . "\n";
2922 if ( in_array( 'current-shift', $classes ) ) {
2923 // (this highlights the current shift item in the full schedule list)
2924 $shift_display .= '<ul class="current-shift-list"><li class="current-shift-list-item">' . "\n";
2925 }
2926 $shift_display .= '<span class="rs-time rs-start-time" data="' . esc_attr( $shift_start_time ) . '" data-format="' . esc_attr( $start_data_format ) . '">' . esc_html( $start ) . '</span>' . "\n";
2927 $shift_display .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
2928 $shift_display .= '<span class="rs-time rs-end-time" data="' . esc_attr( $shift_end_time ) . '" data-format="' . esc_attr( $end_data_format ) . '">' . esc_html( $end ) . '</span>' . "\n";
2929
2930 // 2.3.3.9: add show user time div
2931 $shift_display .= '<div class="show-user-time">' . "\n";
2932 $shift_display .= '[<span class="rs-user-time rs-start-time"></span>' . "\n";
2933 $shift_display .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
2934 $shift_display .= '<span class="rs-user-time rs-end-time"></span>]' . "\n";
2935 $shift_display .= '</div>';
2936
2937 if ( in_array( 'current-shift', $classes ) ) {
2938 $shift_display .= '</li></ul>' . "\n";
2939 }
2940 $shift_display .= '</div>' . "\n";
2941 }
2942 }
2943
2944 if ( $atts['show_all_sched'] ) {
2945 $shift_display .= '</div>' . "\n";
2946 }
2947 // }
2948
2949 // --- set clear div ---
2950 $html['clear'] = '<span class="radio-clear"></span>' . "\n";
2951
2952 // --- set show title output ---
2953 // 2.3.3.9: adding show title attribute
2954 // 2.5.0: remove show_title attribute (as always needed)
2955 $title = '<div class="current-show-title on-air-dj-title">' . "\n";
2956 if ( $show_link ) {
2957 $title .= '<a href="' . esc_url( $show_link ) . '">' . "\n";
2958 }
2959 $title .= esc_html( $show['name'] ) . "\n";
2960 if ( $show_link ) {
2961 $title .= '</a>' . "\n";
2962 }
2963 $title .= '</div>' . "\n";
2964 // 2.3.3.8: added current show title filter
2965 $title = apply_filters( 'radio_station_current_show_title_display', $title, $show_id, $atts );
2966 if ( ( '' != $title ) && is_string( $title ) ) {
2967 $html['title'] = $title;
2968 }
2969
2970 // --- show avatar ---
2971 if ( $atts['show_avatar'] ) {
2972
2973 // 2.3.0: get show avatar (with thumbnail fallback)
2974 // 2.3.0: filter show avatar via display context
2975 // 2.3.0: maybe add link from avatar to show
2976 // 2.3.3.9: allow for possible avatar size attribute/filter
2977 $avatar = '';
2978 $avatar_size = apply_filters( 'radio_station_current_show_avatar_size', $atts['avatar_size'], $show_id );
2979 $show_avatar = radio_station_get_show_avatar( $show_id, $avatar_size );
2980 $show_avatar = apply_filters( 'radio_station_current_show_avatar', $show_avatar, $show_id, $atts );
2981 if ( $show_avatar ) {
2982 $avatar = '<div class="current-show-avatar on-air-dj-avatar' . esc_attr( $floatclass ) . '" ' . $widthstyle . '>' . "\n";
2983 if ( $show_link ) {
2984 $avatar .= '<a href="' . esc_url( $show_link ) . '">' . "\n";
2985 }
2986 // 2.5.0: use wp_kses on show avatar output
2987 $allowed = radio_station_allowed_html( 'media', 'image' );
2988 $avatar .= wp_kses( $show_avatar, $allowed ) . "\n";
2989 if ( $show_link ) {
2990 $avatar .= '</a>' . "\n";
2991 }
2992 $avatar .= '</div>' . "\n";
2993 }
2994 // 2.3.3.8: added avatar display filter
2995 // 2.3.3.9: moved filter outside of conditional
2996 $avatar = apply_filters( 'radio_station_current_show_avatar_display', $avatar, $show_id, $atts );
2997 if ( ( '' != $avatar ) && is_string( $avatar ) ) {
2998 $html['avatar'] = $avatar;
2999 }
3000 }
3001
3002 // --- show DJs / hosts ---
3003 if ( $atts['display_hosts'] ) {
3004
3005 $hosts = '';
3006 $show_hosts = get_post_meta( $show_id, 'show_user_list', true );
3007 if ( $show_hosts ) {
3008 // 2.4.0.4: convert possible (old) non-array value
3009 if ( !is_array( $show_hosts ) ) {
3010 $show_hosts = array( $show_hosts );
3011 }
3012 if ( is_array( $show_hosts ) && ( count( $show_hosts ) > 0 ) ) {
3013
3014 $hosts = '<div class="current-show-hosts on-air-dj-names">' . "\n";
3015 $hosts .= esc_html( __( 'with', 'radio-station' ) ) . ' ';
3016
3017 $count = 0;
3018 // 2.3.3.9: fix to host count
3019 $host_count = count( $show_hosts );
3020 foreach ( $show_hosts as $host ) {
3021
3022 $count ++;
3023
3024 // 2.3.0: maybe get stored user data
3025 // $user = get_userdata( $host );
3026 if ( isset( $radio_station_data['user-' . $host] ) ) {
3027 $user = $radio_station_data['user-' . $host];
3028 } else {
3029 $user = get_user_by( 'ID', $host );
3030 $radio_station_data['user-' . $host] = $user;
3031 }
3032
3033 if ( $atts['link_hosts'] ) {
3034 // 2.3.0: use new get host URL function
3035 $host_link = radio_station_get_host_url( $host );
3036 $host_link = apply_filters( 'radio_station_dj_link', $host_link, $host );
3037
3038 // 2.3.3.5: only wrap with tags if there is a link
3039 if ( $host_link ) {
3040 $hosts .= '<a href="' . esc_url( $host_link ) . '">';
3041 }
3042 $hosts .= esc_html( $user->display_name );
3043 if ( $host_link ) {
3044 $hosts .= '</a>';
3045 }
3046 } else {
3047 $hosts .= esc_html( $user->display_name );
3048 }
3049
3050 if ( ( ( 1 == $count ) && ( 2 == $host_count ) )
3051 || ( ( $host_count > 2 ) && ( ( $host_count - 1 ) == $count ) ) ) {
3052 $hosts .= ' ' . esc_html( __( 'and', 'radio-station' ) ) . ' ';
3053 } elseif ( ( $count < $host_count ) && ( $host_count > 2 ) ) {
3054 $hosts .= ', ';
3055 }
3056 }
3057 $hosts .= '</div>';
3058 }
3059 $hosts = apply_filters( 'radio_station_current_show_hosts_display', $hosts, $show_id, $atts );
3060 if ( ( '' != $hosts ) && is_string( $hosts ) ) {
3061 $html['hosts'] = $hosts;
3062 }
3063 }
3064 }
3065
3066 // --- output current shift display ---
3067 if ( $atts['show_sched'] && isset( $current_shift_display ) ) {
3068 $html['shift'] = $current_shift_display;
3069 }
3070
3071 // --- encore presentation ---
3072 // 2.3.0: added encore presentation display
3073 // 2.3.3.8: added shortcode attribute check (with default 1)
3074 if ( $atts['show_encore'] ) {
3075 $encore = '';
3076 // note: this is set via the current show shift
3077 if ( isset( $show['encore'] ) && ( $show['encore'] ) ) {
3078 $encore = '<div class="current-show-encore on-air-dj-encore">' . "\n";
3079 $encore .= esc_html( __( 'Encore Presentation', 'radio-station' ) ) . "\n";
3080 $encore .= '</div>' . "\n";
3081 }
3082 // 2.3.3.8: added encore display filter
3083 $encore = apply_filters( 'radio_station_current_show_encore_display', $encore, $show_id, $atts );
3084 if ( ( '' != $encore ) && is_string( $encore ) ) {
3085 $html['encore'] = $encore;
3086 }
3087 }
3088
3089 // --- current show playlist ---
3090 // 2.3.0: convert span to div tags for consistency
3091 if ( $atts['show_playlist'] ) {
3092 // 2.3.0: use new function to get current playlist
3093 $current_playlist = radio_station_get_now_playing();
3094 if ( RADIO_STATION_DEBUG ) {
3095 $output .= '<span style="display:none;">Current Playlist: ' . esc_html( print_r( $current_playlist, true ) ) . '</span>';
3096 }
3097 // 2.5.0: set empty playlist for undefined variable warning
3098 $playlist = '';
3099 if ( $current_playlist && isset( $current_playlist['playlist_url'] ) ) {
3100 $playlist = '<div class="current-show-playlist on-air-dj-playlist">' . "\n";
3101 $playlist .= '<a href="' . esc_url( $current_playlist['playlist_url'] ) . '">' . "\n";
3102 $playlist .= esc_html( __( 'View Playlist', 'radio-station' ) ) . "\n";
3103 $playlist .= '</a>' . "\n";
3104 $playlist .= '</div>' . "\n";
3105 }
3106 // 2.3.3.8: added playlist diplay filter
3107 $playlist = apply_filters( 'radio_station_current_show_playlist_display', $playlist, $show_id, $atts );
3108 if ( ( '' != $playlist ) && is_string( $playlist ) ) {
3109 $html['playlist'] = $playlist;
3110 }
3111 }
3112
3113 // --- countdown timer display ---
3114 // 2.5.10: add countdown for dynamic reloading
3115 if ( isset( $current_shift_end ) && ( $atts['countdown'] || $atts['dynamic'] ) ) {
3116 $html['countdown'] = '<div class="current-show-countdown rs-countdown"';
3117 // 2.5.10: hide countdown display if disabled but dynamic enabled
3118 if ( $atts['dynamic'] && !$atts['countdown'] ) {
3119 $html['countdown'] .= ' style="display:none;"';
3120 }
3121 $html['countdown'] .= '></div>' . "\n";
3122 }
3123
3124 // --- show description ---
3125 // 2.3.0: convert span to div tags for consistency
3126 if ( $atts['show_desc'] ) {
3127
3128 // --- get show post ---
3129 $show_post = get_post( $show_id );
3130 $permalink = get_permalink( $show_id );
3131
3132 // --- get show excerpt ---
3133 if ( !empty( $show_post->post_excerpt ) ) {
3134 $excerpt = $show_post->post_excerpt;
3135 // 2.5.0: added esc_html to more anchor text
3136 $excerpt .= ' <a href="' . esc_url( $permalink ) . '">' . esc_html( $more ) . '</a>';
3137 // $excerpt .= "<!-- Post Excerpt -->";
3138 } else {
3139 $excerpt = radio_station_trim_excerpt( $show_post->post_content, $length, $more, $permalink );
3140 // $excerpt . = "<!-- Trimmed Excerpt -->";
3141 // $excerpt .= "<!-- Post ID: " . $show_post->ID . " -->";
3142 // $excerpt .= "<!-- Post Content: " . $show_post->post_content . " -->";
3143 }
3144
3145 // --- filter excerpt by context ---
3146 // 2.3.0: added contextual filtering
3147 if ( $atts['widget'] ) {
3148 $excerpt = apply_filters( 'radio_station_current_show_widget_excerpt', $excerpt, $show_id, $atts );
3149 } else {
3150 $excerpt = apply_filters( 'radio_station_current_show_shortcode_excerpt', $excerpt, $show_id, $atts );
3151 }
3152
3153 // --- set description ---
3154 $description = '';
3155 if ( ( '' != $excerpt ) && is_string( $excerpt ) ) {
3156 $description = '<div class="current-show-desc on-air-show-desc">' . "\n";
3157 // 2.5.0: use wp_kses on excerpt output
3158 $allowed = radio_station_allowed_html( 'content', 'excerpt' );
3159 $description .= wp_kses( $excerpt, $allowed ) . "\n";
3160 $description .= '</div>' . "\n";
3161 }
3162 $description = apply_filters( 'radio_station_current_show_description_display', $description, $show_id, $atts );
3163 if ( ( '' != $description ) && is_string( $description ) ) {
3164 $html['description'] = $description;
3165 }
3166 }
3167
3168 // --- output full show schedule ---
3169 // 2.3.2: do not display all shifts for overrides
3170 if ( $atts['show_all_sched'] && !isset( $current_shift['override'] ) ) {
3171 $schedule = apply_filters( 'radio_station_current_show_shifts_display', $shift_display, $show_id, $atts );
3172 if ( ( '' != $schedule ) && is_string( $schedule ) ) {
3173 $html['schedule'] = $schedule;
3174 }
3175 }
3176
3177 // --- custom HTML section ---
3178 // 2.3.3.8: added custom HTML section
3179 $html['custom'] = apply_filters( 'radio_station_current_show_custom_display', '', $show_id, $atts );
3180
3181 // --- open current show list item ---
3182 $output .= '<li class="current-show on-air-dj">' . "\n";
3183
3184 // --- filter display section order ---
3185 // 2.3.1: added filter for section order display
3186 if ( 'above' == $atts['title_position'] ) {
3187 $order = array( 'title', 'avatar', 'hosts', 'shift', 'encore', 'clear', 'playlist', 'countdown', 'description', 'clear', 'schedule', 'custom' );
3188 } else {
3189 $order = array( 'avatar', 'title', 'hosts', 'shift', 'encore', 'clear', 'playlist', 'countdown', 'description', 'clear', 'schedule', 'custom' );
3190 }
3191 $order = apply_filters( 'radio_station_current_show_section_order', $order, $atts );
3192 foreach ( $order as $section ) {
3193 if ( isset( $html[$section] ) && ( '' != $html[$section] ) ) {
3194 $output .= $html[$section];
3195 }
3196 }
3197
3198 // --- close current show list item ---
3199 $output .= '</li>' . "\n";
3200
3201 } else {
3202
3203 // 2.5.0: allow for hiding when empty (with filter override)
3204 if ( $atts['hide_empty'] ) {
3205 $output = apply_filters( 'radio_station_current_show_shortcode', '', $atts, $instance );
3206 return $output;
3207 }
3208
3209 // --- no current show shift display ---
3210 // 2.5.0: change attribute key from default_name
3211 // 2.5.0: remove unneeded esc_html from no shows text
3212 // 2.5.0: allow for zero value for no text
3213 if ( '0' != $atts['no_shows'] ) {
3214 if ( '' != $atts['no_shows'] ) {
3215 $no_current_show = $atts['no_shows'];
3216 } else {
3217 $no_current_show = __( 'No Show currently scheduled.', 'radio-station' );
3218 }
3219 // 2.3.1: add filter for no current shows text
3220 $no_current_show = apply_filters( 'radio_station_no_current_show_text', $no_current_show, $atts );
3221
3222 $output .= '<li class="current-show on-air-dj default-dj">' . "\n";
3223 // 2.5.0: use wp_kses on message output
3224 $allowed = radio_station_allowed_html( 'message', 'no-shows' );
3225 $output .= wp_kses( $no_current_show, $allowed ) . "\n";
3226 $output .= '</li>' . "\n";
3227 }
3228
3229 // --- countdown timer display ---
3230 // 2.3.3.8: add countdown timer div regardless of no current show
3231 // (so timer can update when a current show starts)
3232 // 2.5.10: add countdown for dynamic reloading
3233 if ( $atts['countdown'] || $atts['dynamic'] ) {
3234 $output .= '<li><div class="current-show-countdown rs-countdown"';
3235 // 2.5.10: hide countdown if disabled but dynamic enabled
3236 if ( $atts['dynamic'] && !$atts['countdown'] ) {
3237 $output .= ' style="display:none;"';
3238 }
3239 $output .= '></div></li>' . "\n";
3240 }
3241
3242 }
3243
3244 // --- countdown timers ---
3245 if ( isset( $current_shift_end ) && ( $atts['countdown'] || $atts['dynamic'] ) ) {
3246
3247 // 2.5.0: wrap countdown/dynamic data in list item
3248 $output .= '<li style="display:none;">' . "\n";
3249
3250 // 2.3.3.9: output current time override
3251 if ( isset( $atts['for_time'] ) ) {
3252 $output .= '<input type="hidden" class="current-time-override" value="' . esc_attr( $atts['for_time'] ) . '">' . "\n";
3253 }
3254
3255 // --- hidden inputs for current shift time ---
3256 $output .= '<input type="hidden" class="current-show-end" value="' . esc_attr( $current_shift_end ) . '">' . "\n";
3257
3258 if ( RADIO_STATION_DEBUG ) {
3259 $output .= '<span style="display:none;">';
3260 $output .= 'Now: ' . radio_station_get_time( 'Y-m-d H:i:s', $now ) . ' (' . esc_attr( $now ) . ')' . "\n";
3261 $output .= 'Shift Start Time: ' . radio_station_get_time( 'Y-m-d H:i:s', $current_shift_start ) . ' (' . esc_attr( $current_shift_start ) . ')' . "\n";
3262 $output .= 'Shift End Time: ' . radio_station_get_time( 'Y-m-d H:i:s', $current_shift_end ) . ' (' . esc_attr( $current_shift_end ) . ')' . "\n";
3263 $output .= 'Remaining: ' . ( $current_shift_end - $now ) . "\n";
3264 $output .= '</span>';
3265 }
3266
3267 // --- for dynamic reloading ---
3268 if ( $atts['dynamic'] ) {
3269 $dynamic = apply_filters( 'radio_station_countdown_dynamic', false, 'current-show', $atts, $current_shift_end );
3270 if ( $dynamic ) {
3271 $output .= $dynamic;
3272 }
3273 }
3274
3275 $output .= '</li>' . "\n";
3276 }
3277
3278 // --- close current show list ---
3279 $output .= '</ul>' . "\n";
3280
3281 // --- close shortcode div wrapper ---
3282 if ( !$atts['widget'] ) {
3283 $output .= '</div>' . "\n";
3284 }
3285
3286 // --- enqueue shortcode styles ---
3287 radio_station_enqueue_style( 'shortcodes' );
3288
3289 // --- filter and return ---
3290 // 2.5.0: added missing shortcode output filter
3291 $output = apply_filters( 'radio_station_current_show_shortcode', $output, $atts, $instance );
3292 return $output;
3293 }
3294
3295 // ------------------------
3296 // AJAX Current Show Loader
3297 // ------------------------
3298 // 2.3.2: added AJAX current show loader
3299 // 2.3.3: remove current show transient
3300 add_action( 'wp_ajax_radio_station_current_show', 'radio_station_current_show' );
3301 add_action( 'wp_ajax_nopriv_radio_station_current_show', 'radio_station_current_show' );
3302 function radio_station_current_show() {
3303
3304 // --- sanitize shortcode attributes ---
3305 $atts = radio_station_sanitize_shortcode_values( 'current-show' );
3306 if ( RADIO_STATION_DEBUG ) {
3307 echo '<span style="display:none;">Current Show Shortcode Attributes: ' . esc_html( print_r( $atts, true ) ) . '</span>' . "\n";
3308 }
3309
3310 // --- output widget contents ---
3311 $output = radio_station_current_show_shortcode( $atts );
3312 echo '<div id="widget-contents">' . "\n";
3313 // phpcs:ignore WordPress.Security.OutputNotEscaped
3314 echo $output;
3315 echo '</div>' . "\n";
3316
3317 $js = '';
3318 if ( isset( $atts['instance'] ) ) {
3319
3320 // 2.5.6: maybe hide entire parent widget if empty
3321 if ( $atts['hide_empty'] && ( '' == trim( $output ) ) ) {
3322
3323 // 2.5.7: added check that widget element exists
3324 $js .= "instance = parent.document.getElementById('current-show-widget-" . esc_js( $atts['instance'] ) . "');" . "\n";
3325 $js .= "if (instance) {instance.style.display = 'none';}" . "\n";
3326
3327 } else {
3328
3329 // --- send to parent window ---
3330 // 2.5.6: ensure parent widget is displayed
3331 // 2.5.7: added check that widget element exists
3332 $js .= "instance = parent.document.getElementById('current-show-widget-" . esc_js( $atts['instance'] ) . "');" . "\n";
3333 $js .= "if (instance) {instance.style.display = '';}" . "\n";
3334 $js .= "widget = document.getElementById('widget-contents').innerHTML;" . "\n";
3335 $js .= "parent.document.getElementById('rs-current-show-" . esc_js( $atts['instance'] ) . "').innerHTML = widget;" . PHP_EOL;
3336
3337 // --- maybe restart countdowns ---
3338 // 2.5.10: also restart when dynamic enabled
3339 if ( $atts['countdown'] || $atts['dynamic'] ) {
3340 // 2.5.0: replace timeout with interval and function check
3341 // $js .= "setTimeout(function() {parent.radio_countdown();}, 2000);" . "\n";
3342 $js .= "countdown = setInterval(function() {" . "\n";
3343 $js .= "if (typeof parent.radio_countdown == 'function') {" . "\n";
3344 $js .= "parent.radio_countdown();" . "\n";
3345 $js .= "clearInterval(countdown);" . "\n";
3346 $js .= "}" . "\n";
3347 $js .= "}, 1000);" . "\n";
3348 }
3349 }
3350
3351 }
3352
3353 // --- filter load script ---
3354 $js = apply_filters( 'radio_station_current_show_load_script', $js, $atts );
3355
3356 // --- output javascript
3357 if ( '' != $js ) {
3358 echo "<script>" . $js . "</script>";
3359 }
3360
3361 exit;
3362 }
3363
3364 // ------------------------
3365 // Upcoming Shows Shortcode
3366 // ------------------------
3367 // [upcoming-shows] / [dj-coming-up-widget]
3368 // 2.0.9: shortcode for displaying upcoming DJs/shows
3369 // 2.3.0: added missing output sanitization
3370 // 2.3.0: added new upcoming-shows shortcode alias
3371 add_shortcode( 'dj-coming-up-widget', 'radio_station_upcoming_shows_shortcode' );
3372 add_shortcode( 'upcoming-shows', 'radio_station_upcoming_shows_shortcode' );
3373 function radio_station_upcoming_shows_shortcode( $atts ) {
3374
3375 global $radio_station_data;
3376
3377 // --- set widget instance ID ---
3378 // 2.3.2: added for AJAX loading
3379 if ( !isset( $radio_station_data['instances']['upcoming_shows'] ) ) {
3380 $radio_station_data['instances']['upcoming_shows'] = 0;
3381 }
3382 $radio_station_data['instances']['upcoming_shows']++;
3383 $instance = $radio_station_data['instances']['upcoming_shows'];
3384
3385 $output = '';
3386
3387 // --- set default time format ---
3388 $time_format = radio_station_get_setting( 'clock_time_format' );
3389
3390 // 2.3.2: get default AJAX load settings
3391 // 2.5.0: unset empty AJAX attribute to use default
3392 $ajax = radio_station_get_setting( 'ajax_widgets', false );
3393 $ajax = ( 'yes' == $ajax ) ? 'on' : 'off';
3394 if ( isset( $atts['ajax'] ) && ( '' == $atts['ajax'] ) ) {
3395 unset( $atts['ajax'] );
3396 }
3397
3398 // --- check for dynamic setting ---
3399 // 2.5.0: fix typo in filter name (radio_station_upcomins_shows_dynamic)
3400 // 2.5.0: added instance as third filter argument
3401 $dynamic = apply_filters( 'radio_station_upcoming_shows_dynamic', false, $atts, $instance );
3402 $dynamic = $dynamic ? 1 : 0;
3403
3404 // 2.3.3: use plugin setting if time format attribute is empty
3405 // 2.5.0: fix to update time attribute to time_format
3406 if ( isset( $atts['time'] ) ) {
3407 if ( '' != trim( $atts['time'] ) ) {
3408 $atts['time_format'] = $atts['time'];
3409 }
3410 unset( $atts['time'] );
3411 }
3412
3413 // 2.3.0: convert old attributes for DJs to hosts
3414 if ( isset( $atts['display_djs'] ) && !isset( $atts['display_hosts'] ) ) {
3415 $atts['display_hosts'] = $atts['display_djs'];
3416 unset( $atts['display_djs'] );
3417 }
3418 if ( isset( $atts['link_djs'] ) && !isset( $atts['link_hosts'] ) ) {
3419 $atts['link_hosts'] = $atts['link_djs'];
3420 unset( $atts['link_djs'] );
3421 }
3422
3423 // 2.5.0: change to default_name attribute key
3424 if ( isset( $atts['default_name'] ) ) {
3425 $atts['no_shows'] = $atts['default_name'];
3426 unset( $atts['default_name'] );
3427 }
3428
3429 // 2.3.0: set default time format to plugin setting
3430 // 2.3.2: added AJAX load attribute
3431 // 2.3.2: added for_time attribute
3432 // 2.3.3.8: added show_encore attribute (default 1)
3433 // 2.3.3.9: added show_title attribute (default 1)
3434 // 2.5.0: change default_name key to no_shows
3435 $defaults = array(
3436 // --- widget display options ---
3437 'title' => '',
3438 'limit' => 1,
3439 'ajax' => $ajax,
3440 'dynamic' => $dynamic,
3441 'no_shows' => '',
3442 'hide_empty' => 0,
3443 // --- show display options ---
3444 'show_link' => 0,
3445 'title_position' => 'right',
3446 'show_avatar' => 0,
3447 'avatar_size' => 'thumbnail',
3448 'avatar_width' => '',
3449 // --- show time display ---
3450 'show_sched' => 1,
3451 'countdown' => 0,
3452 'time_format' => $time_format,
3453 // --- extra display options ---
3454 'display_hosts' => 0,
3455 'link_hosts' => 0,
3456 // 'display_producers' => 0,
3457 // 'list_producers' => 0,
3458 'show_encore' => 1,
3459 // --- instance data ---
3460 'widget' => 0,
3461 'block' => 0,
3462 'id' => '',
3463 'for_time' => 0,
3464 // --- channel ---
3465 'channel' => '',
3466 );
3467 // 2.3.0: renamed shortcode identifier to upcoming-shows
3468 $defaults = apply_filters( 'radio_station_upcomings_shows_default_atts', $defaults );
3469 $atts = shortcode_atts( $defaults, $atts, 'upcoming-shows' );
3470
3471 // 2.3.2: enqueue countdown script earlier
3472 // 2.5.10: enqueue when dynamic is enabled
3473 if ( $atts['countdown'] || $atts['dynamic'] ) {
3474 do_action( 'radio_station_countdown_enqueue' );
3475 }
3476
3477 // 2.3.3: added current time override for manual testing
3478 if ( isset( $_GET['date'] ) && isset( $_GET['time'] ) ) {
3479 $date = sanitize_text_field( trim( $_GET['date'] ) );
3480 $time = sanitize_text_field( trim( $_GET['time'] ) );
3481 if ( isset( $_GET['month'] ) ) {
3482 $month = absint( trim( $_GET['month'] ) );
3483 } else {
3484 $month = radio_station_get_time( 'm' );
3485 }
3486 if ( isset( $_GET['year'] ) ) {
3487 $year = absint( trim( $_GET['year'] ) );
3488 } else {
3489 $year = radio_station_get_time( 'Y' );
3490 }
3491 if ( strstr( $time, ':' ) && ( $month > 0 ) && ( $month < 13 ) ) {
3492 $parts = explode( ':', $time );
3493 $time = absint( $parts[0] ) . ':' . absint( $parts[1] );
3494 $for_time = radio_station_to_time( $year . '-' . $month . '-' . $date . ' ' . $time );
3495 $atts['for_time'] = $for_time;
3496 echo "<script>console.log('Override Current Time: " . esc_js( $for_time ) . "');</script>";
3497 }
3498 }
3499
3500 // --- maybe do AJAX load ---
3501 // 2.3.2 added widget AJAX loading
3502 $ajax = $atts['ajax'];
3503 $widget = $atts['widget'];
3504 $ajax = apply_filters( 'radio_station_widgets_ajax_override', $ajax, 'upcoming-shows', $widget );
3505 if ( 'on' == $ajax ) {
3506 if ( !defined( 'DOING_AJAX' ) || !DOING_AJAX ) {
3507
3508 // --- AJAX load via iframe ---
3509 $ajax_url = admin_url( 'admin-ajax.php' );
3510 $html = '<div id="rs-upcoming-shows-' . esc_attr( $instance ) . '" class="ajax-widget"></div>' . "\n";
3511 $html .= '<iframe id="rs-upcoming-shows-' . esc_attr( $instance ) . '-loader" src="javascript:void(0);" style="display:none;"></iframe>' . "\n";
3512
3513 // --- shortcode loader script ---
3514 $html .= "<script>" . "\n";
3515 $html .= "timestamp = Math.floor( (new Date()).getTime() / 1000 );" . "\n";
3516 $html .= "url = '" . esc_url( $ajax_url ) . "?action=radio_station_upcoming_shows';" . "\n";
3517 $html .= "url += '&instance=" . esc_js( $instance ) . "';" . "\n";
3518 if ( RADIO_STATION_DEBUG ) {
3519 $html .= "url += '&rs-debug=1';" . "\n";
3520 }
3521 $html .= "url += '";
3522 foreach ( $atts as $key => $value ) {
3523 // 2.5.7: fix to ensure for_time is used for timestamp
3524 if ( ( 'for_time' == $key ) && ( 0 == $value ) ) {
3525 $html .= "&for_time='+timestamp+'";
3526 } else {
3527 $value = radio_station_encode_uri_component( $value );
3528 $html .= "&" . esc_js( $key ) . "=" . esc_js( $value );
3529 }
3530 }
3531 $html .= "';" . "\n";
3532 $html .= "document.getElementById('rs-upcoming-shows-" . esc_js( $instance ) . "-loader').src = url;" . "\n";
3533 $html .= "</script>" . "\n";
3534
3535 // --- enqueue shortcode styles ---
3536 radio_station_enqueue_style( 'shortcodes' );
3537
3538 // 2.6.7: filter to enqueue reloader script in current window
3539 if ( $atts['dynamic'] ) {
3540 $dynamic = apply_filters( 'radio_station_countdown_dynamic', false, 'upcoming-shows', $atts, false );
3541 }
3542
3543 // --- filter and return ---
3544 $html = apply_filters( 'radio_station_upcoming_shows_shortcode_ajax', $html, $atts, $instance );
3545 return $html;
3546 }
3547 }
3548
3549 // 2.2.4: maybe set float class and avatar width style
3550 // 2.3.0: moved here from upcoming widget class
3551 $width_style = $float_class = '';
3552 if ( !empty( $atts['avatar_width'] ) ) {
3553 $width_style = 'style="width:' . esc_attr( $atts['avatar_width'] ) . 'px;"';
3554 }
3555 if ( 'right' == $atts['title_position'] ) {
3556 $float_class = ' float-left';
3557 } elseif ( 'left' == $atts['title_position'] ) {
3558 $float_class = ' float-right';
3559 }
3560
3561 // --- get the upcoming shows ---
3562 // note: upcoming shows are not split shift
3563 // 2.3.0: use new get next shows function
3564 if ( $atts['for_time'] ) {
3565 $shows = radio_station_get_next_shows( $atts['limit'], false, $atts['for_time'] );
3566 } else {
3567 $shows = radio_station_get_next_shows( $atts['limit'] );
3568 }
3569 if ( RADIO_STATION_DEBUG ) {
3570 $output .= '<span style="display:none;">Upcoming Shows: ' . esc_html( print_r( $shows, true ) ) . '</span>';
3571 }
3572
3573 // --- open shortcode only wrapper ---
3574 if ( !$atts['widget'] ) {
3575
3576 // 2.3.0: add unique id to widget shortcode
3577 // 2.3.2: add shortcode wrap class
3578 // 2.5.0: change id key to shortcodes NOT widget
3579 // 2.5.0: simplified to use existing instance count
3580 $id = 'upcoming-shows-shortcode-' . $instance;
3581 $output .= '<div id="' . esc_attr( $id ) . '" class="upcoming-shows-wrap upcoming-shows-embedded on-air-embedded dj-coming-up-embedded">' . "\n";
3582
3583 }
3584
3585 // --- shortcode title ---
3586 // 2.5.0: also maybe output for non-shortcodes
3587 // 2.5.7: but do not display for widgets (duplication)
3588 if ( ( '' != $atts['title'] ) && ( 0 != $atts['title'] ) && !$atts['widget'] ) {
3589 $output .= '<h3 class="upcoming-shows-title dj-coming-up-title">' . "\n";
3590 $output .= esc_html( $atts['title'] ) . "\n";
3591 $output .= '</h3>' . "\n";
3592 }
3593
3594 // --- open upcoming show list ---
3595 // 2.5.0: added countdown class for countdown script targeting
3596 $classes = array( 'upcoming-shows-list', 'on-air-upcoming-list' );
3597 // 2.5.10: also add class when dynamic is enabled
3598 if ( $atts['countdown'] || $atts['dynamic'] ) {
3599 $classes[] = 'countdown';
3600 }
3601 $class_list = implode( ' ', $classes );
3602 $output .= '<ul class="' . esc_attr( $class_list ) . '">' . "\n";
3603
3604 // --- shows upcoming output ---
3605 if ( $shows ) {
3606
3607 // --- filter display section order ---
3608 // 2.3.1: added filter for section order display
3609 // 2.3.3.8: moved section order filter outside of show shift loop
3610 if ( 'above' == $atts['title_position'] ) {
3611 $order = array( 'title', 'avatar', 'hosts', 'shift', 'clear', 'countdown', 'encore', 'custom' );
3612 } else {
3613 $order = array( 'avatar', 'title', 'hosts', 'shift', 'clear', 'countdown', 'encore', 'custom' );
3614 }
3615 $order = apply_filters( 'radio_station_upcoming_shows_section_order', $order, $atts );
3616
3617 // --- set shift display data formats ---
3618 // 2.2.7: fix to convert time to integer
3619 // 2.3.2: moved outside shift loop
3620 // 2.4.0.6: added filter for default time format separator
3621 $time_separator = ':';
3622 $time_separator = apply_filters( 'radio_station_time_separator', $time_separator, 'upcoming-shows' );
3623 if ( 24 == (int) $atts['time_format'] ) {
3624 $start_data_format = $end_data_format = 'H' . $time_separator . 'i';
3625 } else {
3626 $start_data_format = $end_data_format = 'g' . $time_separator . 'i a';
3627 }
3628 $start_data_format = 'l, ' . $start_data_format;
3629 $start_data_format = apply_filters( 'radio_station_time_format_start', $start_data_format, 'upcoming-shows', $atts );
3630 $end_data_format = apply_filters( 'radio_station_time_format_end', $end_data_format, 'upcoming-shows', $atts );
3631
3632 // --- convert dates ---
3633 // 2.3.0: use weekdates for reliability
3634 if ( $atts['for_time'] ) {
3635 $now = $atts['for_time'];
3636 } else {
3637 $now = radio_station_get_now();
3638 }
3639 $today = radio_station_get_time( 'l', $now );
3640 $yesterday = radio_station_get_previous_day( $today );
3641 $weekdays = radio_station_get_schedule_weekdays( $yesterday );
3642 $weekdates = radio_station_get_schedule_weekdates( $weekdays, $now );
3643
3644 // --- loop upcoming shows ---
3645 foreach ( $shows as $i => $shift ) {
3646
3647 // --- reset output ---
3648 // 2.3.1: store all HTML to allow section re-ordering
3649 $html = array( 'title' => '' );
3650
3651 // --- get show data ---
3652 $show = $shift['show'];
3653 $show_id = $show['id'];
3654
3655 // --- set show link ---
3656 $show_link = false;
3657 if ( $atts['show_link'] ) {
3658 $show_link = get_permalink( $show_id );
3659 $show_link = apply_filters( 'radio_station_upcoming_show_link', $show_link, $show_id, $atts );
3660 }
3661
3662 // --- check show schedule ---
3663 // 2.3.1: check earlier for later display
3664 if ( $atts['show_sched'] || $atts['countdown'] || $atts['dynamic'] ) {
3665
3666 // --- set shift start and end ---
3667 if ( isset( $shift['real_start'] ) ) {
3668 $start = $shift['real_start'];
3669 } elseif ( isset( $shift['start'] ) ) {
3670 $start = $shift['start'];
3671 } else {
3672 $start = $shift['start_hour'] . ':' . $shift['start_min'] . ' ' . $shift['start_meridian'];
3673 }
3674 if ( isset( $shift['real_end'] ) ) {
3675 $end = $shift['real_end'];
3676 } elseif ( isset( $shift['end'] ) ) {
3677 $end = $shift['end'];
3678 } else {
3679 $end = $shift['end_hour'] . ':' . $shift['end_min'] . ' ' . $shift['end_meridian'];
3680 }
3681
3682 // --- convert shift info ---
3683 // 2.2.2: fix to weekday value to be translated
3684 // 2.3.2: replace strtotime with to_time for timezones
3685 // 2.3.2: use exact shift date in time calculations
3686 // 2.3.2: fix to convert to 24 hour format first
3687 // $display_day = radio_station_translate_weekday( $shift['day'] );
3688 $shift_start = radio_station_convert_shift_time( $start );
3689 $shift_end = radio_station_convert_shift_time( $end );
3690 if ( isset( $shift['real_start'] ) ) {
3691 $prevday = radio_station_get_previous_day( $shift['day'] );
3692 $shift_start_time = radio_station_to_time( $weekdates[$prevday] . ' ' . $shift_start );
3693 } else {
3694 $shift_start_time = radio_station_to_time( $weekdates[$shift['day']] . ' ' . $shift_start );
3695 }
3696 $shift_end_time = radio_station_to_time( $weekdates[$shift['day']] . ' ' . $shift_end );
3697 // 2.3.3.9: added or equals to operator
3698 if ( $shift_end_time <= $shift_start_time ) {
3699 $shift_end_time = $shift_end_time + ( 24 * 60 * 60 );
3700 }
3701
3702 // --- maybe set next show shift times ---
3703 if ( !isset( $next_start_time ) ) {
3704 $next_start_time = $shift_start_time;
3705 $next_end_time = $shift_end_time;
3706 }
3707
3708 // --- set shift classes ---
3709 $classes = array( 'upcoming-show-shift', 'on-air-dj-sched' );
3710 if ( ( $now > $shift_start_time ) && ( $now < $shift_end_time ) ) {
3711 $classes[] = 'current-shift';
3712 }
3713 $class = implode( ' ', $classes );
3714
3715 // --- get shift display times ---
3716 // 2.3.2: use time formats with translations
3717 $start = radio_station_get_time( $start_data_format, $shift_start_time );
3718 $end = radio_station_get_time( $end_data_format, $shift_end_time );
3719 $start = radio_station_translate_time( $start );
3720 $end = radio_station_translate_time( $end );
3721
3722 // 2.4.0.6: use filtered shift separator
3723 $separator = ' - ';
3724 $separator = apply_filters( 'radio_station_show_times_separator', $separator, 'upcoming-shows' );
3725
3726 // --- set shift display output ---
3727 $shift_display = '<div class="upcoming-show-schedule on-air-dj-schedule">';
3728 $shift_display .= '<div class="' . esc_attr( $class ) . '">' . "\n";
3729 $shift_display .= '<span class="rs-time rs-start-time" data="' . esc_attr( $shift_start_time ) . '" data-format="' . esc_attr( $start_data_format ) . '">' . esc_html( $start ) . '</span>' . "\n";
3730 $shift_display .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
3731 $shift_display .= '<span class="rs-time rs-end-time" data="' . esc_attr( $shift_end_time ) . '" data-format="' . esc_attr( $end_data_format ) . '">' . esc_html( $end ) . '</span>' . "\n";
3732 $shift_display .= '</div>';
3733 // 2.3.3.9: add empty user time div
3734 $shift_display .= '<div class="show-user-time">' . "\n";
3735 $shift_display .= '[<span class="rs-time rs-start-time"></span>' . "\n";
3736 $shift_display .= '<span class="rs-sep rs-shift-sep">' . esc_html( $separator ) . '</span>' . "\n";
3737 $shift_display .= '<span class="rs-time rs-end-time"></span>]' . "\n";
3738 $shift_display .= '</div>' . "\n";
3739 $shift_display .= '</div>' . "\n";
3740 if ( RADIO_STATION_DEBUG ) {
3741 $shift_display .= '<span style="display:none;">Upcoming Shift: ' . esc_html( print_r( $shift, true ) ) . '</span>';
3742 }
3743 }
3744
3745 // --- set clear div ---
3746 $html['clear'] = '<span class="radio-clear"></span>' . "\n";
3747
3748 // --- set show title ---
3749 // 2.3.3.9: added attribute for show title display
3750 // 2.5.0: removed show_title attribute as always needed
3751 $title = '<div class="upcoming-show-title on-air-dj-title">' . "\n";
3752 if ( $show_link ) {
3753 $title .= '<a href="' . esc_url( $show_link ) . '">' . "\n";
3754 }
3755 $title .= esc_html( $show['name'] ) . "\n";
3756 if ( $show_link ) {
3757 $title .= '</a>' . "\n";
3758 }
3759 $title .= '</div>' . "\n";
3760 $title = apply_filters( 'radio_station_upcoming_show_title_display', $title, $show_id, $atts );
3761 if ( ( '' != $title ) && is_string( $title ) ) {
3762 $html['title'] = $title;
3763 }
3764
3765 // --- set show avatar ---
3766 if ( $atts['show_avatar'] ) {
3767
3768 // 2.3.0: get show avatar (with thumbnail fallback)
3769 // 2.3.0: filter show avatar by context
3770 // 2.3.0: maybe link avatar to show
3771 // 2.3.3.9: add filter for avatar image display size
3772 $avatar = '';
3773 $avatar_size = apply_filters( 'radio_station_upcoming_show_avatar_size', $atts['avatar_size'], $show_id );
3774 $show_avatar = radio_station_get_show_avatar( $show_id, $avatar_size );
3775 $show_avatar = apply_filters( 'radio_station_upcoming_show_avatar', $show_avatar, $show_id, $atts );
3776 if ( $show_avatar ) {
3777 $avatar = '<div class="upcoming-show-avatar on-air-dj-avatar' . esc_attr( $float_class ) . '" ' . $width_style . '>' . "\n";
3778 if ( $atts['show_link'] ) {
3779 $avatar .= '<a href="' . esc_url( $show_link ) . '">' . "\n";
3780 }
3781 // 2.5.0: added wp_kses to avatar output
3782 $allowed = radio_station_allowed_html( 'media', 'image' );
3783 $avatar .= wp_kses( $show_avatar, $allowed ) . "\n";
3784 if ( $atts['show_link'] ) {
3785 $avatar .= '</a>' . "\n";
3786 }
3787 $avatar .= '</div>' . "\n";
3788 }
3789 $avatar = apply_filters( 'radio_station_upcoming_show_avatar_display', $avatar, $show_id, $atts );
3790 if ( ( '' != $avatar ) && is_string( $avatar ) ) {
3791 $html['avatar'] = $avatar;
3792 }
3793 }
3794
3795 // --- set DJ / Host names ---
3796 if ( $atts['display_hosts'] ) {
3797
3798 $hosts = '';
3799 $show_hosts = get_post_meta( $show_id, 'show_user_list', true );
3800 if ( $show_hosts ) {
3801 // 2.4.0.4: convert possible (old) non-array value
3802 if ( !is_array( $show_hosts ) ) {
3803 $show_hosts = array( $show_hosts );
3804 }
3805 if ( is_array( $show_hosts ) && ( count( $show_hosts ) > 0 ) ) {
3806
3807 $hosts = '<div class="upcoming-show-hosts on-air-dj-names">' . "\n";
3808 $hosts .= esc_html( __( 'with', 'radio-station' ) ) . ' ';
3809
3810 $count = 0;
3811 // 2.3.3.9: fix to host count
3812 $host_count = count( $show_hosts );
3813 foreach ( $show_hosts as $host ) {
3814
3815 $count ++;
3816
3817 // 2.3.0: maybe get stored user data
3818 // $user = get_userdata( $host );
3819 if ( isset( $radio_station_data['user-' . $host] ) ) {
3820 $user = $radio_station_data['user-' . $host];
3821 } else {
3822 $user = get_user_by( 'ID', $host );
3823 $radio_station_data['user-' . $host] = $user;
3824 }
3825
3826 if ( $atts['link_hosts'] ) {
3827 // 2.3.0: use new get host URL function
3828 $host_link = radio_station_get_host_url( $host );
3829 $host_link = apply_filters( 'radio_station_dj_link', $host_link, $host );
3830
3831 // 2.3.3.5: only wrap with tags if there is a link
3832 if ( $host_link ) {
3833 $hosts .= '<a href="' . esc_url( $host_link ) . '">';
3834 }
3835 $hosts .= esc_html( $user->display_name );
3836 if ( $host_link ) {
3837 $hosts .= '</a>';
3838 }
3839 } else {
3840 $hosts .= esc_html( $user->display_name );
3841 }
3842
3843 if ( ( ( 1 == $count ) && ( 2 == $host_count ) )
3844 || ( ( $host_count > 2 ) && ( $count == ( $host_count - 1 ) ) ) ) {
3845 $hosts .= ' ' . esc_html( __( 'and', 'radio-station' ) ) . ' ';
3846 } elseif ( ( $count < $host_count ) && ( $host_count > 2 ) ) {
3847 $hosts .= ', ';
3848 }
3849 }
3850 $hosts .= '</div>' . "\n";
3851 }
3852 $hosts = apply_filters( 'radio_station_upcoming_show_hosts_display', $hosts, $show_id, $atts );
3853 if ( ( '' != $hosts ) && is_string( $hosts ) ) {
3854 // 2.5.0: added wp_kses to hosts display output
3855 $allowed = radio_station_allowed_html( 'content', 'hosts' );
3856 $html['hosts'] = wp_kses( $hosts, $allowed );
3857 }
3858 }
3859 }
3860
3861 // --- set encore presentation ---
3862 // 2.2.4: added encore presentation display
3863 // 2.3.3.8: added shortcode attribute for encore display (default 1)
3864 if ( $atts['show_encore'] ) {
3865 $encore = '';
3866 if ( isset( $show['encore'] ) && ( 'on' == $show['encore'] ) ) {
3867 $encore = '<div class="upcoming-show-encore on-air-dj-encore">' . "\n";
3868 $encore .= esc_html( __( 'Encore Presentation', 'radio-station' ) ) . "\n";
3869 $encore .= '</div>' . "\n";
3870 }
3871 $encore = apply_filters( 'radio_station_upcoming_show_encore_display', $encore, $show_id, $atts );
3872 if ( ( '' != $encore ) && is_string( $encore ) ) {
3873 // 2.5.0: added wp_kses to encore display output
3874 $allowed = radio_station_allowed_html( 'content', 'encore' );
3875 $html['encore'] = wp_kses( $encore, $allowed );
3876 }
3877 }
3878
3879 // --- set countdown timer ---
3880 // 2.5.10: add counter when dynamic is enabled
3881 if ( ( 0 == $i ) && isset( $next_start_time ) && ( $atts['countdown'] || $atts['dynamic'] ) ) {
3882 $html['countdown'] = '<div class="upcoming-show-countdown rs-countdown"';
3883 // 2.5.10: hide countdown if disabled but dynamic enabled
3884 if ( $atts['dynamic'] && !$atts['countdown'] ) {
3885 $html['countdown'] .= ' style="display:none;"';
3886 }
3887 $html['countdown'] .= '></div>' . "\n";
3888 }
3889
3890 // --- set show schedule ---
3891 if ( $atts['show_sched'] ) {
3892 $schedule = apply_filters( 'radio_station_upcoming_show_shifts_display', $shift_display, $show_id, $atts );
3893 if ( ( '' != $schedule ) && is_string( $schedule ) ) {
3894 $html['shift'] = $schedule;
3895 }
3896 }
3897
3898 // --- custom HTML section ---
3899 // 2.3.3.8: added custom HTML section
3900 $html['custom'] = apply_filters( 'radio_station_upcoming_shows_custom_display', '', $show_id, $atts );
3901
3902 // --- open upcoming show list item ---
3903 $output .= '<li class="upcoming-show on-air-dj">' . "\n";
3904
3905 // --- add output according to section order ---
3906 // 2.3.3.8: moved section order filter out of show shift loop
3907 foreach ( $order as $section ) {
3908 if ( isset( $html[$section] ) && ( '' != $html[$section] ) ) {
3909 $output .= $html[$section];
3910 }
3911 }
3912
3913 // --- close upcoming show list item ---
3914 $output .= '</li>' . "\n";
3915 }
3916
3917 } else {
3918
3919 // 2.5.0: allow for hiding when empty (with filter override)
3920 if ( $atts['hide_empty'] ) {
3921 $output = apply_filters( 'radio_station_upcoming_shows_shortcode', '', $atts, $instance );
3922 return $output;
3923 }
3924
3925 // --- no shows upcoming ---
3926 // note: no countdown display added as no upcoming shows found
3927 // 2.5.0: change default_name key to no_shows_text
3928 // 2.5.0: move esc_html to output line
3929 // 2.5.0: allow for zero value for no text
3930 if ( '0' != $atts['no_shows'] ) {
3931 if ( '' != $atts['no_shows'] ) {
3932 $no_upcoming_shows = $atts['no_shows'];
3933 } else {
3934 $no_upcoming_shows = __( 'No Upcoming Shows Scheduled.', 'radio-station' );
3935 }
3936 // 2.3.1: add filter for no current shows text
3937 $no_upcoming_shows = apply_filters( 'radio_station_no_upcoming_shows_text', $no_upcoming_shows, $atts );
3938
3939 $output .= '<li class="upcoming-show-none on-air-dj default-dj">' . "\n";
3940 // 2.5.0: use wp_kses on message output
3941 $allowed = radio_station_allowed_html( 'message', 'no-shows' );
3942 $output .= wp_kses( $no_upcoming_shows, $allowed );
3943 $output .= '</li>' . "\n";
3944 }
3945 }
3946
3947 // --- countdown timer inputs ---
3948 // 2.3.0: added for countdowns
3949 if ( isset( $next_start_time ) && ( $atts['countdown'] || $atts['dynamic'] ) ) {
3950
3951 // 2.5.0: wrap data in hidden list item for script
3952 $output .= '<li style="display:none;">' . "\n";
3953
3954 // 2.3.3.9: output current time override
3955 if ( isset( $atts['for_time'] ) ) {
3956 $output .= '<input type="hidden" class="current-time-override" value="' . esc_attr( $atts['for_time'] ) . '">';
3957 }
3958
3959 // --- hidden input for next start time ---
3960 $output .= '<input type="hidden" class="upcoming-show-times" value="' . esc_attr( $next_start_time ) . '-' . esc_attr( $next_end_time ) . '">' . "\n";
3961 if ( RADIO_STATION_DEBUG ) {
3962 $output .= '<span style="display:none;">';
3963 $output .= 'Now: ' . esc_html( radio_station_get_time( 'Y-m-d H:i:s', $now ) ) . ' (' . esc_html( $now ) . ')' . "\n";
3964 $output .= 'Next Start Time: ' . esc_html( radio_station_get_time('y-m-d H:i:s', $next_start_time ) ) . ' (' . esc_html( $next_start_time ) . ')' . "\n";
3965 $output .= 'Next End Time: ' . esc_html( radio_station_get_time( 'y-m-d H:i:s', $next_end_time ) ) . ' (' . esc_html( $next_end_time ) . ')' . "\n";
3966 $output .= 'Starting in: ' . esc_html( $next_start_time - $now ) . "\n";
3967 $output .= '</span>';
3968 }
3969
3970 // --- for dynamic reloading ---
3971 if ( $atts['dynamic'] ) {
3972 $dynamic = apply_filters( 'radio_station_countdown_dynamic', false, 'upcoming-shows', $atts, $next_start_time );
3973 if ( $dynamic ) {
3974 $output .= $dynamic;
3975 }
3976 }
3977
3978 $output .= '</li>' . "\n";
3979 }
3980
3981 // --- close upcoming shows list ---
3982 $output .= '</ul>' . "\n";
3983
3984 // --- close shortcode only wrapper ---
3985 if ( !$atts['widget'] ) {
3986 $output .= '</div>' . "\n";
3987 }
3988
3989 // --- enqueue shortcode styles ---
3990 radio_station_enqueue_style( 'shortcodes' );
3991
3992 // 2.5.0: added missing output filter
3993 $output = apply_filters( 'radio_station_upcoming_shows_shortcode', $output, $atts, $instance );
3994 return $output;
3995 }
3996
3997 // --------------------------
3998 // AJAX Upcoming Shows Loader
3999 // --------------------------
4000 // 2.3.2: added AJAX upcoming shows loader
4001 add_action( 'wp_ajax_radio_station_upcoming_shows', 'radio_station_upcoming_shows' );
4002 add_action( 'wp_ajax_nopriv_radio_station_upcoming_shows', 'radio_station_upcoming_shows' );
4003 function radio_station_upcoming_shows() {
4004
4005 // --- sanitize shortcode attributes ---
4006 $atts = radio_station_sanitize_shortcode_values( 'upcoming-shows' );
4007 if ( RADIO_STATION_DEBUG ) {
4008 echo '<span style="display:none">Upcoming Shows Shortcode Attributes: ' . esc_html( print_r( $atts, true ) ) . '</span>' . "\n";
4009 }
4010
4011 // --- output widget contents ---
4012 $output = radio_station_upcoming_shows_shortcode( $atts );
4013 echo '<div id="widget-contents">' . "\n";
4014 // phpcs:ignore WordPress.Security.OutputNotEscaped
4015 echo $output;
4016 echo '</div>' . "\n";
4017
4018 $js = '';
4019 if ( isset( $atts['instance'] ) ) {
4020
4021 // 2.6.5: maybe hide entire parent widget area if empty
4022 if ( $atts['hide_empty'] && ( '' == trim( $output ) ) ) {
4023
4024 $js .= "instance = parent.document.getElementById('upcoming-shows-widget-" . esc_js( $atts['instance'] ) . "');" . "\n";
4025 $js .= "instance.style.display = 'none';" . "\n";
4026
4027 } else {
4028
4029 // --- send to parent window ---
4030 // 2.5.6: ensure parent widget is displayed
4031 // 2.5.7: added check that widget element exists
4032 $js .= "instance = parent.document.getElementById('upcoming-shows-widget-" . esc_js( $atts['instance'] ) . "');" . "\n";
4033 $js .= "if (instance) {instance.style.display = '';}" . "\n";
4034 $js .= "widget = document.getElementById('widget-contents').innerHTML;" . "\n";
4035 $js .= "parent.document.getElementById('rs-upcoming-shows-" . esc_js( $atts['instance'] ) . "').innerHTML = widget;" . "\n";
4036
4037 // --- restart countdowns ---
4038 // 2.5.10: restart countdown if dynamic is enabled
4039 if ( $atts['countdown'] || $atts['dynamic'] ) {
4040 // 2.5.0: replace timeout with interval and function check
4041 // $js .= "setTimeout(function() {parent.radio_countdown();}, 2000);" . "\n";
4042 $js .= "countdown = setInterval(function() {" . "\n";
4043 $js .= "if (typeof parent.radio_countdown == 'function') {" . "\n";
4044 $js .= "parent.radio_countdown();" . "\n";
4045 $js .= "clearInterval(countdown);" . "\n";
4046 $js .= "}" . "\n";
4047 $js .= "}, 1000);" . "\n";
4048 }
4049 }
4050 }
4051
4052 // --- filter load script ---
4053 $js = apply_filters( 'radio_station_upcoming_shows_load_script', $js, $atts );
4054
4055 // --- output javascript
4056 if ( '' != $js ) {
4057 echo "<script>" . $js . "</script>" . "\n";
4058 }
4059
4060 exit;
4061 }
4062
4063 // --------------------------
4064 // Current Playlist Shortcode
4065 // --------------------------
4066 // [current-playlist] / [now-playing]
4067 // 2.3.0: added missing output sanitization
4068 add_shortcode( 'current-playlist', 'radio_station_current_playlist_shortcode' );
4069 add_shortcode( 'now-playing', 'radio_station_current_playlist_shortcode' );
4070 function radio_station_current_playlist_shortcode( $atts ) {
4071
4072 global $radio_station_data;
4073
4074 // --- set widget instance ID ---
4075 // 2.3.2: added for AJAX loading
4076 if ( !isset( $radio_station_data['instances']['current_playlist'] ) ) {
4077 $radio_station_data['instances']['current_playlist'] = 0;
4078 }
4079 $radio_station_data['instances']['current_playlist']++;
4080 $instance = $radio_station_data['instances']['current_playlist'];
4081
4082 $output = '';
4083
4084 // 2.3.2: get default AJAX load settings
4085 // 2.5.0: unset empty AJAX attribute to use default
4086 $ajax = radio_station_get_setting( 'ajax_widgets', false );
4087 $ajax = ( 'yes' == $ajax ) ? 'on' : 'off';
4088 if ( isset( $atts['ajax'] ) && ( '' == $atts['ajax'] ) ) {
4089 unset( $atts['ajax'] );
4090 }
4091
4092 // --- check for dynamic setting ---
4093 // 2.5.0: added instance as third filter argument
4094 $dynamic = apply_filters( 'radio_station_current_playlist_dynamic', false, $atts, $instance );
4095 $dynamic = $dynamic ? 1 : 0;
4096
4097 // --- get shortcode attributes ---
4098 // 2.3.2: added AJAX load attribute
4099 // 2.3.2: added for_time attribute
4100 // 2.5.0: added no_playlist text attribute
4101 // 2.5.0: added playlist_title switch attribute
4102 $defaults = array(
4103 // --- widget display options ---
4104 'title' => '',
4105 'ajax' => $ajax,
4106 'dynamic' => $dynamic,
4107 'hide_empty' => 0,
4108 // --- playlist display options ---
4109 'playlist_title' => 0,
4110 'link' => 1,
4111 'no_playlist' => '',
4112 'countdown' => 0,
4113 // --- track display options ---
4114 'song' => 1,
4115 'artist' => 1,
4116 'album' => 0,
4117 'label' => 0,
4118 'comments' => 0,
4119 // --- widget data ---
4120 'widget' => 0,
4121 'block' => 0,
4122 'id' => '',
4123 'for_time' => 0,
4124 // --- channel ---
4125 'channel' => '',
4126 );
4127
4128 // 2.3.0: renamed shortcode identifier to current-playlist
4129 // 2.5.18: added filter for default attributes
4130 $defaults = apply_filters( 'radio_station_current_playlist_atts', $defaults );
4131 $atts = shortcode_atts( $defaults, $atts, 'current-playlist' );
4132
4133 // 2.3.2: enqueue countdown script earlier
4134 // 2.5.10: enqueue countdown if dynamic is enabled
4135 if ( $atts['countdown'] || $atts['dynamic'] ) {
4136 do_action( 'radio_station_countdown_enqueue' );
4137 }
4138
4139 // 2.3.3: added current time override for manual testing
4140 if ( isset( $_GET['date'] ) && isset( $_GET['time'] ) ) {
4141 // 2.5.0: added sanitize_text_field to date/time
4142 $date = trim( sanitize_text_field( $_GET['date'] ) );
4143 $time = trim( sanitize_text_field( $_GET['time'] ) );
4144 if ( isset( $_GET['month'] ) ) {
4145 $month = absint( trim( $_GET['month'] ) );
4146 } else {
4147 $month = radio_station_get_time( 'm' );
4148 }
4149 if ( isset( $_GET['year'] ) ) {
4150 $year = absint( trim( $_GET['year'] ) );
4151 } else {
4152 $year = radio_station_get_time( 'Y' );
4153 }
4154 if ( strstr( $time, ':' ) && ( $month > 0 ) && ( $month < 13 ) ) {
4155 $parts = explode( ':', $time );
4156 $time = absint( $parts[0] ) . ':' . absint( $parts[1] );
4157 $for_time = radio_station_to_time( $year . '-' . $month . '-' . $date . ' ' . $time );
4158 $atts['for_time'] = $for_time;
4159 echo "<script>console.log('Override Current Time: " . esc_js( $for_time ) . "');</script>";
4160 }
4161 }
4162
4163 // --- maybe do AJAX load ---
4164 // 2.3.2 added widget AJAX loading
4165 $ajax = $atts['ajax'];
4166 $widget = $atts['widget'];
4167 $ajax = apply_filters( 'radio_station_widgets_ajax_override', $ajax, 'current-playlist', $widget );
4168 if ( 'on' == $ajax ) {
4169 if ( !defined( 'DOING_AJAX' ) || !DOING_AJAX ) {
4170
4171 // --- AJAX load via iframe ---
4172 $ajax_url = admin_url( 'admin-ajax.php' );
4173 $html = '<div id="rs-current-playlist-' . esc_attr( $instance ) . '" class="ajax-widget"></div>' . "\n";
4174 $html .= '<iframe id="rs-current-playlist-' . esc_attr( $instance ) . '-loader" src="javascript:void(0);" style="display:none;"></iframe>' . "\n";
4175
4176 // --- shortcode script loader ---
4177 $html .= "<script>timestamp = Math.floor( (new Date()).getTime() / 1000 );" . "\n";
4178 $html .= "url = '" . esc_url( $ajax_url ) . "?action=radio_station_current_playlist';" . "\n";
4179 $html .= "url += '&instance=" . esc_attr( $instance ) . "';" . "\n";
4180 if ( RADIO_STATION_DEBUG ) {
4181 $html .= "url += '&rs-debug=1';" . "\n";
4182 }
4183 $html .= "url += '";
4184 foreach ( $atts as $key => $value ) {
4185 // 2.5.7: fix to ensure for_time is used for timestamp
4186 if ( ( 'for_time' == $key ) && ( 0 == $value ) ) {
4187 $html .= "&for_time='+timestamp+'";
4188 } else {
4189 $value = radio_station_encode_uri_component( $value );
4190 $html .= "&" . esc_js( $key ) . "=" . esc_js( $value );
4191 }
4192 }
4193 $html .= "';" . "\n";
4194 $html .= "document.getElementById('rs-current-playlist-" . esc_attr( $instance ) ."-loader').src = url;" . "\n";
4195 $html .= "</script>" . "\n";
4196
4197 // --- enqueue shortcode styles ---
4198 radio_station_enqueue_style( 'shortcodes' );
4199
4200 // 2.6.7: filter to enqueue= reloader script in current window
4201 if ( $atts['dynamic'] ) {
4202 $dynamic = apply_filters( 'radio_station_countdown_dynamic', false, 'current-playlist', $atts, false );
4203 }
4204
4205 // 2.5.0: added filter for shortcode output
4206 $html = apply_filters( 'radio_station_current_playlist_shortcode_ajax', $html, $atts, $instance );
4207 return $html;
4208 }
4209 }
4210
4211 // --- fetch the current playlist ---
4212 if ( $atts['for_time'] ) {
4213 $playlist = radio_station_get_now_playing( $atts['for_time'] );
4214 $time = radio_station_get_time( 'datetime', $atts['for_time'] );
4215 if ( RADIO_STATION_DEBUG ) {
4216 echo '<span style="display:none;">';
4217 echo 'Current Playlist For Time: ' . esc_html( $atts['for_time'] ) . ' : ' . esc_html( $time ) . "\n";;
4218 echo esc_html( print_r( $playlist, true ) );
4219 echo '</span>';
4220 }
4221 } else {
4222 $playlist = radio_station_get_now_playing();
4223 }
4224
4225 // --- shortcode only wrapper ---
4226 if ( !$atts['widget'] ) {
4227
4228 // 2.3.0: add unique id to widget shortcode
4229 // 2.3.2: fix to shortcode classes
4230 // 2.3.2: add shortcode wrap class
4231 // 2.5.0: change data key to shortcodes NOT widget
4232 // 2.5.0: simplify instances to start at 1
4233 if ( !isset( $radio_station_data['shortcodes']['current-playlist'] ) ) {
4234 $radio_station_data['shortcodes']['current-playlist'] = 0;
4235 }
4236 $radio_station_data['shortcodes']['current-playlist']++;
4237 $id = 'show-playlist-shortcode-' . $radio_station_data['widgets']['current-playlist'];
4238 $output .= '<div id="' . esc_attr( $id ) . '" class="current-playlist-wrap current-playlist-embedded now-playing-embedded">' . "\n";
4239
4240 }
4241
4242 // --- shortcode title ---
4243 // 2.5.0: also maybe display for non-shortcodes
4244 // 2.5.7: but do not display for widgets (duplication)
4245 if ( ( '' == $atts['title'] ) && ( 0 != $atts['title'] ) && !$atts['widget'] ) {
4246 // 2.3.0: added title class for shortcode
4247 $output .= '<h3 class="show-playlist-title myplaylist-title">' . "\n";
4248 // 2.5.0: fixed to use esc_html instead of esc_attr
4249 $output .= esc_html( $atts['title'] ) . "\n";
4250 $output .= '</h3>' . "\n";
4251 }
4252
4253 // --- set empty HTML array ---
4254 $html = array();
4255
4256 // --- countdown timer ---
4257 // 2.3.0: added for countdown changeovers
4258 // 2.3.3.8: moved outside of current playlist check
4259 if ( $atts['countdown'] || $atts['dynamic'] ) {
4260
4261 $html['countdown'] = '';
4262 if ( RADIO_STATION_DEBUG ) {
4263 echo '<span style="display:none;">Playlist: ' . esc_html( print_r( $playlist, true ) ) . '</span>' . "\n";
4264 }
4265
4266 // 2.3.1: added check for playlist shifts value
4267 if ( isset( $playlist['shifts'] ) && is_array( $playlist['shifts'] ) && ( count( $playlist['shifts'] ) > 0 ) ) {
4268
4269 // --- convert dates ---
4270 // 2.3.0: use weekdates for reliability
4271 $now = $atts['for_time'] ? $atts['for_time'] : radio_station_get_now();
4272 $today = radio_station_get_time( 'l', $now );
4273 $yesterday = radio_station_get_previous_day( $today );
4274 $weekdays = radio_station_get_schedule_weekdays( $yesterday );
4275 $weekdates = radio_station_get_schedule_weekdates( $weekdays, $now );
4276
4277 // --- loop shifts ---
4278 foreach ( $playlist['shifts'] as $shift_id => $shift ) {
4279
4280 // 2.3.3.9: added check that shift day is set
4281 if ( isset( $shift['day'] ) && ( '' != $shift['day'] ) ) {
4282
4283 // --- set shift start and end ---
4284 if ( isset( $shift['real_start'] ) ) {
4285 $start = $shift['real_start'];
4286 } elseif ( isset( $shift['start'] ) ) {
4287 $start = $shift['start'];
4288 } else {
4289 $start = $shift['start_hour'] . ':' . $shift['start_min'] . ' ' . $shift['start_meridian'];
4290 }
4291 if ( isset( $shift['real_end'] ) ) {
4292 $end = $shift['real_end'];
4293 } elseif ( isset( $shift['end'] ) ) {
4294 $end = $shift['end'];
4295 } else {
4296 $end = $shift['end_hour'] . ':' . $shift['end_min'] . ' ' . $shift['end_meridian'];
4297 }
4298
4299 // --- convert shift info ---
4300 // 2.3.2: replace strtotime with to_time for timezones
4301 // 2.3.2: fix to convert to 24 hour format first
4302 // TODO: check/test possible undefined index for $shift['day'] ?
4303 $start_time = radio_station_convert_shift_time( $start );
4304 $end_time = radio_station_convert_shift_time( $end );
4305 if ( isset( $shift['real_start'] ) ) {
4306 $prevday = radio_station_get_previous_day( $shift['day'] );
4307 $shift_start_time = radio_station_to_time( $weekdates[$prevday] . ' ' . $start_time );
4308 } else {
4309 $shift_start_time = radio_station_to_time( $weekdates[$shift['day']] . ' ' . $start_time );
4310 }
4311 $shift_end_time = radio_station_to_time( $weekdates[$shift['day']] . ' ' . $end_time );
4312 // 2.3.3.9: fix to overnight check variables
4313 // 2.3.3.9: added or equals to operator
4314 if ( $shift_end_time <= $shift_start_time ) {
4315 $shift_end_time = $shift_end_time + ( 24 * 60 * 60 );
4316 }
4317
4318 // --- check currently playing show time ---
4319 // 2.5.0: removed duplicate now declarations
4320 if ( $atts['for_time'] ) {
4321 // $now = $atts['for_time'];
4322 $html['countdown'] .= '<input type="hidden" class="current-time-override" value="' . esc_attr( $atts['for_time'] ) . '">' . "\n";
4323 }
4324 // echo 'Shift Start: ' . $shift_start_time . '(' . radio_station_get_time( 'datetime', $shift_start_time ) . ')<br>';
4325 // echo 'Shift End: ' . $shift_end_time . '(' . radio_station_get_time( 'datetime', $shift_end_time ) . ')<br>';
4326
4327 if ( ( ( $now > $shift_start_time ) || ( $now == $shift_start_time ) ) && ( $now < $shift_end_time ) ) {
4328
4329 // print_r( $shift );
4330 // echo "^^^ NOW PLAYING ^^^";
4331
4332 // --- hidden input for playlist end time ---
4333 $html['countdown'] .= '<input type="hidden" class="current-playlist-end" value="' . esc_attr( $shift_end_time ) . '">' . "\n";
4334
4335 // --- for countdown timer display ---
4336 // 2.5.10: also output if dynamic enabled
4337 if ( $atts['countdown'] || $atts['dynamic'] ) {
4338 $html['countdown'] .= '<div class="show-playlist-countdown rs-countdown"';
4339 // 2.5.10: hide if countdown disabled but dynamic enabled
4340 if ( $atts['dynamic'] && !$atts['countdown'] ) {
4341 $html['countdown'] .= ' style="display:none;"';
4342 }
4343 $html['countdown'] .= '></div>' . "\n";
4344 }
4345
4346 // --- for dynamic reloading ---
4347 if ( $atts['dynamic'] ) {
4348 $dynamic = apply_filters( 'radio_station_countdown_dynamic', false, 'current-playlist', $atts, $shift_end_time );
4349 if ( $dynamic ) {
4350 $html['countdown'] .= $dynamic;
4351 }
4352 }
4353 }
4354 }
4355 }
4356 }
4357 }
4358
4359 // 2.3.0: use updated code from now playing widget
4360 // 2.3.3.9: move check for playlist tracks here
4361 $tracks = '';
4362 if ( $playlist && isset( $playlist['tracks'] ) && is_array( $playlist['tracks'] ) && ( count( $playlist['tracks'] ) > 0 ) ) {
4363
4364 // 2.3.0: split div wrapper from track wrapper
4365 $tracks .= '<div class="show-playlist-tracks myplaylist-nowplaying">' . "\n";
4366
4367 // --- loop playlist tracks ---
4368 // 2.3.0: loop all instead of just latest
4369 // 2.3.1: added check for playlist tracks
4370 // 2.3.3.9: moved up check for playlist tracks
4371 foreach ( $playlist['tracks'] as $track ) {
4372
4373 $class = '';
4374 if ( isset( $track['playlist_entry_new'] ) && ( 'on' === $track['playlist_entry_new'] ) ) {
4375 $class .= ' new';
4376 }
4377 // 2.3.0: added check for latest track since looping
4378 if ( $track == $playlist['latest'] ) {
4379 $class .= ' latest';
4380 } else {
4381 $class .= ' played';
4382 }
4383
4384 $tracks .= '<div class="show-playlist-track myplaylist-track' . esc_attr( $class ) . '">' . "\n";
4385
4386 // 2.2.3: convert span tags to div tags
4387 // 2.2.4: check value keys are set before outputting
4388 if ( $atts['song'] && isset( $track['playlist_entry_song'] ) ) {
4389 $tracks .= '<div class="show-playlist-song myplaylist-song">' . "\n";
4390 $tracks .= '<span class="playlist-label">' . esc_html( __( 'Song', 'radio-station' ) ) . '</span>';
4391 $tracks .= ': <span class="playlist-info">' . esc_html( $track['playlist_entry_song'] ) . '</span>' . "\n";
4392 $tracks .= '</div>' . "\n";
4393 }
4394
4395 // 2.2.7: add label prefixes to now playing data
4396 if ( $atts['artist'] && isset( $track['playlist_entry_artist'] ) ) {
4397 $tracks .= '<div class="show-playlist-artist myplaylist-artist">' . "\n";
4398 $tracks .= '<span class="playlist-label">' . esc_html( __( 'Artist', 'radio-station' ) ) . '</span>';
4399 $tracks .= ': <span class="playlist-info">' . esc_html( $track['playlist_entry_artist'] ) . '</span>' . "\n";
4400 $tracks .= '</div>' . "\n";
4401 }
4402
4403 if ( $atts['album'] && !empty( $track['playlist_entry_album'] ) ) {
4404 $tracks .= '<div class="show-playlist-album myplaylist-album">' . "\n";
4405 $tracks .= '<span class="playlist-label">' . esc_html( __( 'Album', 'radio-station' ) ) . '</span>';
4406 $tracks .= ': <span class="playlist-info">' . esc_html( $track['playlist_entry_album'] ) . '</span>' . "\n";
4407 $tracks .= '</div>' . "\n";
4408 }
4409
4410 if ( $atts['label'] && !empty( $track['playlist_entry_label'] ) ) {
4411 $tracks .= '<div class="show-playlist-label myplaylist-label">' . "\n";
4412 $tracks .= '<span class="playlist-label">' . esc_html( __( 'Label', 'radio-station' ) ) . '</span>';
4413 $tracks .= ': <span class="playlist-info">' . esc_html( $track['playlist_entry_label'] ) . '</span>' . "\n";
4414 $tracks .= '</div>' . "\n";
4415 }
4416
4417 if ( $atts['comments'] && !empty( $track['playlist_entry_comments'] ) ) {
4418 $tracks .= '<div class="show-playlist-comments myplaylist-comments">' . "\n";
4419 $tracks .= '<span class="playlist-label">' . esc_html( __( 'Comments', 'radio-station' ) ) . '</span>';
4420 $tracks .= ': <span class="playlist-info">' . esc_html( $track['playlist_entry_comments'] ) . '</span>' . "\n";
4421 $tracks .= '</div>' . "\n";
4422 }
4423
4424 $tracks .= '</div>' . "\n";
4425 }
4426 $tracks .= '</div>' . "\n";
4427
4428 // --- playlist permalink ---
4429 // 2.3.3.8 added playlist_link shortcode attribute (default 1)
4430 if ( $atts['link'] ) {
4431 $link = '';
4432 // 2.5.0: fix to playlist_permalink key
4433 if ( isset( $playlist['playlist_url'] ) ) {
4434 $link = '<div class="show-playlist-link myplaylist-link">' . "\n";
4435 $link .= '<a href="' . esc_url( $playlist['playlist_url'] ) . '">';
4436 // 2.5.0: maybe show playlist title
4437 if ( $atts['playlist_title'] ) {
4438 $link .= esc_html( $playlist['title'] );
4439 } else {
4440 $link .= esc_html( __( 'View Playlist', 'radio-station' ) );
4441 }
4442 $link .= '</a>' . "\n";
4443 $link .= '</div>' . "\n";
4444 }
4445 // 2.3.3.8: added playlist link display filter
4446 $link = apply_filters( 'radio_station_current_playlist_link_display', $link, $playlist, $atts );
4447 if ( ( '' != $link ) && is_string( $link ) ) {
4448 $html['link'] = $link;
4449 }
4450 } elseif ( $atts['playlist_title'] ) {
4451 // 2.5.0: maybe show playlist title
4452 $html['link'] = esc_html( $playlist['title'] );
4453 }
4454
4455 } else {
4456
4457 // 2.5.0: allow for hiding when empty (with filter override)
4458 if ( $atts['hide_empty'] ) {
4459 $output = apply_filters( 'radio_station_current_playlist_shortcode', '', $atts, $instance );
4460 return $output;
4461 }
4462
4463 // 2.2.3: added missing translation wrapper
4464 // 2.3.0: added no playlist class
4465 // 2.3.1: add filter for no playlist text
4466 // 2.3.3.8: fix to unclosed double quote on class attribute
4467 // 2.5.0: add shortcode attribute for no playlist text
4468 // 2.5.0: allow for zero value for no text
4469 if ( '0' != $atts['no_playlist'] ) {
4470 if ( '' != $atts['no_playlist'] ) {
4471 $no_current_playlist = $atts['no_playlist'];
4472 } else {
4473 $no_current_playlist = __( 'No Current Playlist available.', 'radio-station' );
4474 }
4475 $no_current_playlist = apply_filters( 'radio_station_no_current_playlist_text', $no_current_playlist, $atts );
4476
4477 $no_playlist = '<div class="show-playlist-noplaylist myplaylist-noplaylist">' . "\n";
4478 // 2.5.0: use wp_kses on message output
4479 $allowed = radio_station_allowed_html( 'message', 'no-playlist' );
4480 $no_playlist .= wp_kses( $no_current_playlist, $allowed ) . "\n";
4481 $no_playlist .= '</div>' . "\n";
4482
4483 // 2.3.3.8: added no playlist display filter
4484 // 2.3.3.9: assign to tracks key for possible output re-ordering
4485 $no_playlist = apply_filters( 'radio_station_current_playlist_no_playlist_display', $no_playlist, $atts );
4486 if ( ( '' != $no_playlist ) && is_string( $no_playlist ) ) {
4487 $html['tracks'] = $no_playlist;
4488 }
4489 }
4490 }
4491
4492 // 2.3.3.8: added track display filter
4493 // 2.3.3.9: moved outside of playlist check
4494 $tracks = apply_filters( 'radio_station_current_playlist_tracks_display', $tracks, $playlist, $atts );
4495 if ( ( '' != $tracks ) && is_string( $tracks ) ) {
4496 $html['tracks'] = $tracks;
4497 }
4498
4499 // --- custom HTML section ---
4500 // 2.3.3.8: added custom HTML section
4501 // 2.3.3.9: move outside of playlist check
4502 $html['custom'] = apply_filters( 'radio_station_current_playlist_custom_display', '', $playlist, $atts );
4503
4504 // --- filter display section order ---
4505 // 2.3.1: added filter for section order display
4506 // 2.3.3.9: moved outside of check for current playlist
4507 $order = array( 'tracks', 'link', 'countdown', 'custom' );
4508 $order = apply_filters( 'radio_station_current_playlist_section_order', $order, $atts );
4509 // $output .= print_r( array_keys( $html ), true );
4510
4511 // 2.5.0: added wrapper and countdown class for countdown script targeting
4512 $classes = array( 'current-playlist show-playlist' );
4513 // 2.5.10: also add class when dynamic is enabled
4514 if ( $atts['countdown'] || $atts['dynamic'] ) {
4515 $classes[] = 'countdown';
4516 }
4517 $class_list = implode( ' ', $classes );
4518 $output .= '<div class="' . esc_attr( $class_list ) . '">' . "\n";
4519
4520 // --- loop sections to add to output ---
4521 foreach ( $order as $section ) {
4522 if ( isset( $html[$section] ) && ( '' != $html[$section] ) ) {
4523 $output .= $html[$section];
4524 }
4525 }
4526
4527 $output .= '</div>' . "\n";
4528
4529 // --- close shortcode only wrapper ---
4530 if ( !$atts['widget'] ) {
4531 $output .= '</div>' . "\n";
4532 }
4533
4534 // --- enqueue shortcode styles ---
4535 radio_station_enqueue_style( 'shortcodes' );
4536
4537 // --- filter and return ---
4538 // 2.5.0: added missing output override filter
4539 $output = apply_filters( 'radio_station_current_playlist_shortcode', $output, $atts, $instance );
4540 return $output;
4541 }
4542
4543 // ----------------------------
4544 // AJAX Current Playlist Loader
4545 // ----------------------------
4546 // 2.3.2: added AJAX current playlist loader
4547 add_action( 'wp_ajax_radio_station_current_playlist', 'radio_station_current_playlist' );
4548 add_action( 'wp_ajax_nopriv_radio_station_current_playlist', 'radio_station_current_playlist' );
4549 function radio_station_current_playlist() {
4550
4551 // --- sanitize shortcode attributes ---
4552 $atts = radio_station_sanitize_shortcode_values( 'current-playlist' );
4553 if ( RADIO_STATION_DEBUG ) {
4554 echo '<span style="display:none;">Current Playlist Shortcode Attributes: ' . esc_html( print_r( $atts, true ) ) . '</span>' . "\n";
4555 }
4556
4557 // --- output widget contents ---
4558 $output = radio_station_current_playlist_shortcode( $atts );
4559 echo '<div id="widget-contents">' . "\n";
4560 // phpcs:ignore WordPress.Security.OutputNotEscaped
4561 echo $output;
4562 echo '</div>' . "\n";
4563
4564 $js = '';
4565 if ( isset( $atts['instance'] ) ) {
4566
4567 // 2.6.5: maybe hide entire parent widget area if empty
4568 if ( $atts['hide_empty'] && ( '' == trim( $output ) ) ) {
4569
4570 // 2.5.7: added check that widget element exists
4571 $js .= "instance = parent.document.getElementById('current-playlist-widget-" . esc_js( $atts['instance'] ) . "');" . "\n";
4572 $js .= "if (instance) {instance.style.display = 'none';}" . "\n";
4573
4574 } else {
4575
4576 // --- send to parent window ---
4577 // 2.5.6: ensure parent widget is displayed
4578 // 2.5.7: added check that widget element exists
4579 $js .= "instance = parent.document.getElementById('current-playlist-widget-" . esc_js( $atts['instance'] ) . "');" . "\n";
4580 $js .= "if (instance) {instance.style.display = '';}" . "\n";
4581 $js .= "widget = document.getElementById('widget-contents').innerHTML;" . "\n";
4582 $js .= "parent.document.getElementById('rs-current-playlist-" . esc_js( $atts['instance'] ) . "').innerHTML = widget;" . "\n";
4583
4584 // --- restart countdowns ---
4585 // 2,5,10: also restart if dynamic is enabled
4586 if ( $atts['countdown'] || $atts['dynamic'] ) {
4587 // 2.5.0: replace timeout with interval and function check
4588 // $js .= "setTimeout(function() {parent.radio_countdown();}, 2000);" . "\n";
4589 $js .= "countdown = setInterval(function() {" . "\n";
4590 $js .= "if (typeof parent.radio_countdown == 'function') {" . "\n";
4591 $js .= "parent.radio_countdown();" . "\n";
4592 $js .= "clearInterval(countdown);" . "\n";
4593 $js .= "}" . "\n";
4594 $js .= "}, 1000);" . "\n";
4595 }
4596 }
4597
4598 }
4599
4600 // --- filter load script ---
4601 $js = apply_filters( 'radio_station_current_playlist_load_script', $js, $atts );
4602
4603 // --- output javascript
4604 if ( '' != $js ) {
4605 echo "<script>" . $js . "</script>" . "\n";
4606 }
4607
4608 exit;
4609 }
4610
4611
4612 // ----------------
4613 // Countdown Script
4614 // ----------------
4615 // 2.3.0: added shortcode/widget countdown script
4616 add_action( 'radio_station_countdown_enqueue', 'radio_station_countdown_enqueue' );
4617 function radio_station_countdown_enqueue() {
4618
4619 // 2.3.3.9: check if script is enqueued
4620 global $radio_station_data;
4621 if ( isset( $radio_station_data['countdown-script'] ) && $radio_station_data['countdown-script'] ) {
4622 return;
4623 }
4624
4625 // --- enqueue countdown script ---
4626 radio_station_enqueue_script( 'radio-station-countdown', array( 'radio-station' ), true );
4627
4628 // --- add script inline ---
4629 // 2.5.0: moved countdown labels to main script localization
4630 // wp_add_inline_script( 'radio-station-countdown', $js );
4631
4632 // 2.3.3.9: flag script as enqueued
4633 $radio_station_data['countdown-script'] = true;
4634
4635 }
4636
4637
4638 // -------------------------
4639 // === Legacy Shortcodes ===
4640 // -------------------------
4641
4642 // -------------------
4643 // Show List Shortcode
4644 // -------------------
4645 // 2.0.0: shortcode for displaying a list of all shows
4646 // [list-shows]
4647 add_shortcode( 'list-shows', 'radio_station_shortcode_list_shows' );
4648 function radio_station_shortcode_list_shows( $atts ) {
4649
4650 global $radio_station_data;
4651
4652 // --- set widget instance ID ---
4653 // 2.3.2: added for AJAX loading
4654 if ( !isset( $radio_station_data['instances']['list_shows'] ) ) {
4655 $radio_station_data['instances']['list_shows'] = 0;
4656 }
4657 $radio_station_data['instances']['list_shows']++;
4658 $instance = $radio_station_data['instances']['list_shows'];
4659
4660 // --- combine shortcode atts with defaults ---
4661 $defaults = array(
4662 'title' => false,
4663 'genre' => '',
4664 );
4665 $atts = shortcode_atts( $defaults, $atts, 'list-shows' );
4666
4667 // --- grab the published shows ---
4668 $args = array(
4669 'posts_per_page' => 1000,
4670 'offset' => 0,
4671 'orderby' => 'title',
4672 'order' => 'ASC',
4673 'post_type' => RADIO_STATION_SHOW_SLUG,
4674 'post_status' => 'publish',
4675 'meta_query' => array(
4676 array(
4677 'key' => 'show_active',
4678 'value' => 'on',
4679 'compare' => '=',
4680 ),
4681 ),
4682 );
4683 if ( !empty( $atts['genre'] ) ) {
4684 $args['tax_query'] = array(
4685 array(
4686 'taxonomy' => RADIO_STATION_GENRES_SLUG,
4687 'field' => 'slug',
4688 'terms' => $atts['genre'],
4689 ),
4690 );
4691 }
4692
4693 // 2.3.0: use get_posts instead of WP_Query
4694 $posts = get_posts( $args );
4695
4696 // if there are no shows saved, return nothing
4697 if ( !$posts || ( count( $posts ) == 0 ) ) {
4698 return '';
4699 }
4700
4701 $output = '';
4702
4703 $output .= '<div id="station-show-list">' . "\n";
4704
4705 if ( $atts['title'] ) {
4706 $output .= '<div class="station-show-list-title">' . "\n";
4707 $output .= '<h3>' . esc_html( $atts['title'] ) . '</h3>' . "\n";
4708 $output .= '</div>' . "\n";
4709 }
4710
4711 $output .= '<ul class="show-list">' . "\n";
4712
4713 // 2.3.0: use posts loop instead of query loop
4714 foreach ( $posts as $post ) {
4715 $output .= '<li class="show-list-item">' . "\n";
4716 $output .= '<div class="show-list-item-title">' . "\n";
4717 $output .= '<a href="' . esc_url( get_permalink( $post->ID ) ) . '">';
4718 $output .= esc_html( get_the_title( $post->ID ) );
4719 $output .= '</a>' . "\n";
4720 $output .= '</div>' . "\n";
4721 $output .= '</li>' . "\n";
4722 }
4723
4724 $output .= '</ul>' . "\n";
4725
4726 $output .= '</div>' . "\n";
4727
4728 // --- filter and return ---
4729 // 2.5.0: added shortcode filter for consistency
4730 $output = apply_filters( 'radio_station_list_shows_shortcode', $output, $atts, $instance );
4731 return $output;
4732 }
4733
4734 // ------------------------
4735 // Show Playlists Shortcode
4736 // ------------------------
4737 // 2.0.0: shortcode to fetch all playlists for a given show id
4738 // 2.3.0: added missing output sanitization
4739 // [get-playlists] / [show-playlists]
4740 add_shortcode( 'show-playlists', 'radio_station_shortcode_get_playlists_for_show' );
4741 add_shortcode( 'get-playlists', 'radio_station_shortcode_get_playlists_for_show' );
4742 function radio_station_shortcode_get_playlists_for_show( $atts ) {
4743
4744 global $radio_station_data;
4745
4746 // --- set widget instance ID ---
4747 // 2.3.2: added for AJAX loading
4748 if ( !isset( $radio_station_data['instances']['get_playlists'] ) ) {
4749 $radio_station_data['instances']['get_playlists'] = 0;
4750 }
4751 $radio_station_data['instances']['get_playlists']++;
4752 $instance = $radio_station_data['instances']['get_playlists'];
4753
4754 // --- combine shortcode atts with defaults ---
4755 $defaults = array(
4756 'show' => '',
4757 'limit' => -1,
4758 );
4759 $atts = shortcode_atts( $defaults, $atts, 'get-playlists' );
4760
4761 // don't return anything if we do not have a show
4762 if ( empty( $atts['show'] ) ) {
4763 return false;
4764 }
4765
4766 $args = array(
4767 'posts_per_page' => $atts['limit'],
4768 'offset' => 0,
4769 'orderby' => 'post_date',
4770 'order' => 'DESC',
4771 'post_type' => RADIO_STATION_PLAYLIST_SLUG,
4772 'post_status' => 'publish',
4773 'meta_key' => 'playlist_show_id',
4774 'meta_value' => $atts['show'],
4775 );
4776
4777 $query = new WP_Query( $args );
4778 $playlists = $query->posts;
4779
4780 // 2.3.0: return empty if no posts found
4781 if ( 0 == $query->post_count ) {
4782 return '';
4783 }
4784
4785 $output = '';
4786
4787 $output .= '<div id="myplaylist-playlistlinks">' . "\n";
4788
4789 $output .= '<ul class="myplaylist-linklist">' . "\n";
4790 foreach ( $playlists as $playlist ) {
4791 $output .= '<li class="myplaylist-linklist-item">' . "\n";
4792 $output .= '<a href="' . esc_url( get_permalink( $playlist->ID ) ) . '">';
4793 $output .= esc_html( $playlist->post_title );
4794 $output .= '</a>' . "\n";
4795 $output .= '</li>' . "\n";
4796 }
4797 $output .= '</ul>' . "\n";
4798
4799 $playlist_archive = get_post_type_archive_link( RADIO_STATION_PLAYLIST_SLUG );
4800 $params = array( 'show_id' => $atts['show'] );
4801 $playlist_archive = add_query_arg( $params, $playlist_archive );
4802
4803 $output .= '<a href="' . esc_url( $playlist_archive ) . '">';
4804 $output .= esc_html( __( 'More Playlists', 'radio-station' ) );
4805 $output .= '</a>' . "\n";
4806
4807 $output .= '</div>' . "\n";
4808
4809 // --- filter and return ---
4810 // 2.5.0: added shortcode filter for consistency
4811 $output = apply_filters( 'radio_station_get_playlists_shortcode', $output, $atts, $instance );
4812 return $output;
4813 }
4814
4815