|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Podcast Player Block. |
|
4
|
|
|
* |
|
5
|
|
|
* @since 8.x |
|
6
|
|
|
* |
|
7
|
|
|
* @package Jetpack |
|
8
|
|
|
*/ |
|
9
|
|
|
|
|
10
|
|
|
namespace Jetpack\Podcast_Episodes_Block; |
|
11
|
|
|
|
|
12
|
|
|
use WP_Error; |
|
13
|
|
|
|
|
14
|
|
|
const FEATURE_NAME = 'podcast-player'; |
|
15
|
|
|
const BLOCK_NAME = 'jetpack/' . FEATURE_NAME; |
|
16
|
|
|
const BLOG_SLUG = 'jetpack-' . FEATURE_NAME; |
|
17
|
|
|
/** |
|
18
|
|
|
* Registers the block for use in Gutenberg |
|
19
|
|
|
* This is done via an action so that we can disable |
|
20
|
|
|
* registration if we need to. |
|
21
|
|
|
*/ |
|
22
|
|
|
function register_block() { |
|
23
|
|
|
jetpack_register_block( |
|
24
|
|
|
BLOCK_NAME, |
|
25
|
|
|
array( |
|
26
|
|
|
'attributes' => array( |
|
27
|
|
|
'url' => array( |
|
28
|
|
|
'type' => 'url', |
|
29
|
|
|
), |
|
30
|
|
|
'itemsToShow' => array( |
|
31
|
|
|
'type' => 'integer', |
|
32
|
|
|
'default' => 5, |
|
33
|
|
|
), |
|
34
|
|
|
), |
|
35
|
|
|
'render_callback' => __NAMESPACE__ . '\render_block', |
|
36
|
|
|
) |
|
37
|
|
|
); |
|
38
|
|
|
} |
|
39
|
|
|
add_action( 'init', __NAMESPACE__ . '\register_block' ); |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* Podcast Player block registration/dependency declaration. |
|
43
|
|
|
* |
|
44
|
|
|
* @param array $attributes Array containing the Podcast Player block attributes. |
|
45
|
|
|
* @param string $content String containing the Podcast Player block content. |
|
46
|
|
|
* |
|
47
|
|
|
* @return string |
|
48
|
|
|
*/ |
|
49
|
|
|
function render_block( $attributes, $content ) { |
|
50
|
|
|
|
|
51
|
|
|
if ( empty( $attributes['url'] ) ) { |
|
52
|
|
|
return; |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
$track_list = get_track_list( $attributes['url'], $attributes['itemsToShow'] ); |
|
56
|
|
|
|
|
57
|
|
|
if ( is_wp_error( $track_list ) ) { |
|
58
|
|
|
return '<p>' . __( 'Unable to retrieve track list. Please check your Podcast feed URL.', 'jetpack' ) . '</p>'; |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
return render_player( $track_list ); |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Renders the HTML for the Podcast player and tracklist. |
|
66
|
|
|
* |
|
67
|
|
|
* @param array $track_list the list of podcast tracks. |
|
68
|
|
|
* @return string the HTML for the podcast player. |
|
69
|
|
|
*/ |
|
70
|
|
|
function render_player( $track_list ) { |
|
71
|
|
|
global $content_width; |
|
72
|
|
|
|
|
73
|
|
|
$player_data = array( |
|
74
|
|
|
'type' => 'audio', |
|
75
|
|
|
// Don't pass strings to JSON, will be truthy in JS. |
|
76
|
|
|
'tracklist' => true, |
|
77
|
|
|
'tracknumbers' => true, |
|
78
|
|
|
'images' => true, |
|
79
|
|
|
'artists' => true, |
|
80
|
|
|
'tracks' => $track_list, |
|
81
|
|
|
); |
|
82
|
|
|
|
|
83
|
|
|
$outer = 22; // Default padding and border of wrapper. |
|
84
|
|
|
$default_width = 640; |
|
85
|
|
|
$theme_width = empty( $content_width ) ? $default_width : ( $content_width - $outer ); |
|
86
|
|
|
|
|
87
|
|
|
// If there are no tracks (it is possible) then display appropriate user facing error message. |
|
88
|
|
|
if ( empty( $track_list ) ) { |
|
89
|
|
|
return '<p>' . __( 'No tracks available to play.', 'jetpack' ) . '</p>'; |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
ob_start(); |
|
93
|
|
|
wp_playlist_scripts( 'audio' ); |
|
94
|
|
|
/** |
|
95
|
|
|
* Prints and enqueues playlist scripts, styles, and JavaScript templates. |
|
96
|
|
|
* |
|
97
|
|
|
* @since 3.9.0 |
|
98
|
|
|
* |
|
99
|
|
|
* @param string $type Type of playlist. Possible values are 'audio' or 'video'. |
|
100
|
|
|
* @param string $style The 'theme' for the playlist. Core provides 'light' and 'dark'. |
|
101
|
|
|
*/ |
|
102
|
|
|
do_action( 'wp_playlist_scripts', 'audio', 'light' ); |
|
103
|
|
|
|
|
104
|
|
|
$initial_track_src = ! empty( $track_list[0]['src'] ) ? $track_list[0]['src'] : ''; |
|
105
|
|
|
|
|
106
|
|
|
?> |
|
107
|
|
|
<div class="wp-block-<?php echo esc_attr( $initial_track_src ); ?> wp-playlist wp-audio-playlist wp-playlist-light"> |
|
108
|
|
|
<div class="wp-playlist-current-item"></div> |
|
109
|
|
|
<audio src="<?php echo esc_url( $track_list[0]['src'] ); ?>" controls="controls" preload="none" width="<?php echo esc_attr( (int) $theme_width ); ?>"></audio> |
|
110
|
|
|
<div class="wp-playlist-next"></div> |
|
111
|
|
|
<div class="wp-playlist-prev"></div> |
|
112
|
|
|
<noscript> |
|
113
|
|
|
<ol> |
|
114
|
|
|
<?php |
|
115
|
|
|
foreach ( $track_list as $track ) : |
|
116
|
|
|
printf( '<li>%s</li>', esc_url( $track['src'] ) ); |
|
117
|
|
|
endforeach; |
|
118
|
|
|
?> |
|
119
|
|
|
</ol> |
|
120
|
|
|
</noscript> |
|
121
|
|
|
<script type="application/json" class="wp-playlist-script"><?php echo wp_json_encode( $player_data ); ?></script> |
|
122
|
|
|
</div> |
|
123
|
|
|
<?php |
|
124
|
|
|
/* |
|
125
|
|
|
* Enqueue necessary scripts and styles. |
|
126
|
|
|
*/ |
|
127
|
|
|
\Jetpack_Gutenberg::load_assets_as_required( 'podcast-player' ); |
|
128
|
|
|
|
|
129
|
|
|
return ob_get_clean(); |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
/** |
|
133
|
|
|
* Gets a list of tracks for the supplied RSS feed. |
|
134
|
|
|
* |
|
135
|
|
|
* @param string $feed the RSS feed to load and list tracks for. |
|
136
|
|
|
* @param int $quantity the number of tracks to return. |
|
137
|
|
|
* @return array|WP_Error the feed's tracks or a error object. |
|
138
|
|
|
*/ |
|
139
|
|
|
function get_track_list( $feed, $quantity = 5 ) { |
|
140
|
|
|
if ( empty( $feed ) ) { |
|
141
|
|
|
return new WP_Error( 'missing_feed', __( 'Podcast audio RSS feed missing.', 'jetpack' ) ); |
|
|
|
|
|
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
$rss = fetch_feed( $feed ); |
|
145
|
|
|
|
|
146
|
|
|
if ( is_wp_error( $rss ) ) { |
|
147
|
|
|
return $rss; // returns the WP_Error object. |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
|
|
if ( ! $rss->get_item_quantity() ) { |
|
151
|
|
|
return new WP_Error( 'no_tracks', __( 'Podcast audio RSS feed has no tracks.', 'jetpack' ) ); |
|
|
|
|
|
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
$episodes = $rss->get_items( 0, $quantity ); |
|
155
|
|
|
|
|
156
|
|
|
$track_list = array_map( |
|
157
|
|
|
function( $episode ) { |
|
158
|
|
|
|
|
159
|
|
|
$url = ! empty( $episode->data['child']['']['enclosure'][0]['attribs']['']['url'] ) ? $episode->data['child']['']['enclosure'][0]['attribs']['']['url'] : null; |
|
160
|
|
|
$type = ! empty( $episode->data['child']['']['enclosure'][0]['attribs']['']['type'] ) ? $episode->data['child']['']['enclosure'][0]['attribs']['']['type'] : null; |
|
161
|
|
|
|
|
162
|
|
|
// If there is no type return an empty array as the array entry. We will filter out later. |
|
163
|
|
|
if ( ! $url ) { |
|
164
|
|
|
return array(); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
// Build track data. |
|
168
|
|
|
$track = array( |
|
169
|
|
|
'src' => $url, |
|
170
|
|
|
'type' => $type, |
|
171
|
|
|
'caption' => '', |
|
172
|
|
|
'description' => wp_kses_post( $episode->get_description() ), |
|
173
|
|
|
'meta' => array(), |
|
174
|
|
|
); |
|
175
|
|
|
|
|
176
|
|
|
$track['title'] = esc_html( trim( wp_strip_all_tags( $episode->get_title() ) ) ); |
|
177
|
|
|
|
|
178
|
|
|
if ( empty( $track['title'] ) ) { |
|
179
|
|
|
$track['title'] = __( '(no title)', 'jetpack' ); |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
return $track; |
|
183
|
|
|
}, |
|
184
|
|
|
$episodes |
|
185
|
|
|
); |
|
186
|
|
|
|
|
187
|
|
|
// Remove empty tracks. |
|
188
|
|
|
return \array_filter( $track_list ); |
|
189
|
|
|
} |
|
190
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.