Completed
Push — add/block-image-compare ( 093ae3...f647cd )
by
unknown
07:08
created

blocks/podcast-player/podcast-player.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Podcast Player Block.
4
 *
5
 * @since 8.4.0
6
 *
7
 * @package Jetpack
8
 */
9
10
namespace Automattic\Jetpack\Extensions\Podcast_Player;
11
12
use WP_Error;
13
use Jetpack_Gutenberg;
14
use Jetpack_Podcast_Helper;
15
use Jetpack_AMP_Support;
16
17
const FEATURE_NAME = 'podcast-player';
18
const BLOCK_NAME   = 'jetpack/' . FEATURE_NAME;
19
20
if ( ! class_exists( 'Jetpack_Podcast_Helper' ) ) {
21
	\jetpack_require_lib( 'class-jetpack-podcast-helper' );
22
}
23
24
/**
25
 * Registers the block for use in Gutenberg. This is done via an action so that
26
 * we can disable registration if we need to.
27
 */
28
function register_block() {
29
	jetpack_register_block(
30
		BLOCK_NAME,
31
		array(
32
			'attributes'      => array(
33
				'url'                    => array(
34
					'type' => 'url',
35
				),
36
				'itemsToShow'            => array(
37
					'type'    => 'integer',
38
					'default' => 5,
39
				),
40
				'showCoverArt'           => array(
41
					'type'    => 'boolean',
42
					'default' => true,
43
				),
44
				'showEpisodeDescription' => array(
45
					'type'    => 'boolean',
46
					'default' => true,
47
				),
48
			),
49
			'render_callback' => __NAMESPACE__ . '\render_block',
50
		)
51
	);
52
}
53
add_action( 'init', __NAMESPACE__ . '\register_block' );
54
55
/**
56
 * Returns the error message wrapped in HTML if current user
57
 * has the capability to edit the post. Public visitors will
58
 * never see errors.
59
 *
60
 * @param string $message The error message to display.
61
 * @return string
62
 */
63
function render_error( $message ) {
64
	// Suppress errors for users unable to address them.
65
	if ( ! current_user_can( 'edit_posts' ) ) {
66
		return '';
67
	}
68
	return '<p>' . esc_html( $message ) . '</p>';
69
}
70
71
/**
72
 * Podcast Player block registration/dependency declaration.
73
 *
74
 * @param array $attributes Array containing the Podcast Player block attributes.
75
 * @return string
76
 */
77
function render_block( $attributes ) {
78
79
	// Test for empty URLS.
80
	if ( empty( $attributes['url'] ) ) {
81
		return render_error( __( 'No Podcast URL provided. Please enter a valid Podcast RSS feed URL.', 'jetpack' ) );
82
	}
83
84
	// Test for invalid URLs.
85
	if ( ! wp_http_validate_url( $attributes['url'] ) ) {
86
		return render_error( __( 'Your podcast URL is invalid and couldn\'t be embedded. Please double check your URL.', 'jetpack' ) );
87
	}
88
89
	// Sanitize the URL.
90
	$attributes['url'] = esc_url_raw( $attributes['url'] );
91
92
	$player_data = Jetpack_Podcast_Helper::get_player_data( $attributes['url'] );
93
94
	if ( is_wp_error( $player_data ) ) {
95
		return render_error( $player_data->get_error_message() );
0 ignored issues
show
The method get_error_message() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
96
	}
97
98
	return render_player( $player_data, $attributes );
99
}
100
101
/**
102
 * Renders the HTML for the Podcast player and tracklist.
103
 *
104
 * @param array $player_data The player data details.
105
 * @param array $attributes Array containing the Podcast Player block attributes.
106
 * @return string The HTML for the podcast player.
107
 */
108
function render_player( $player_data, $attributes ) {
109
	// If there are no tracks (it is possible) then display appropriate user facing error message.
110
	if ( empty( $player_data['tracks'] ) ) {
111
		return render_error( __( 'No tracks available to play.', 'jetpack' ) );
112
	}
113
114
	// Only use the amount of tracks requested.
115
	$player_data['tracks'] = array_slice(
116
		$player_data['tracks'],
117
		0,
118
		absint( $attributes['itemsToShow'] )
119
	);
120
121
	// Generate a unique id for the block instance.
122
	$instance_id             = wp_unique_id( 'jetpack-podcast-player-block-' );
123
	$player_data['playerId'] = $instance_id;
124
125
	// Generate object to be used as props for PodcastPlayer.
126
	$player_props = array_merge(
127
		// Add all attributes.
128
		array( 'attributes' => $attributes ),
129
		// Add all player data.
130
		$player_data
131
	);
132
133
	$primary_colors    = get_colors( 'primary', $attributes, 'color' );
134
	$secondary_colors  = get_colors( 'secondary', $attributes, 'color' );
135
	$background_colors = get_colors( 'background', $attributes, 'background-color' );
136
137
	$player_classes_name  = trim( "{$secondary_colors['class']} {$background_colors['class']}" );
138
	$player_inline_style  = trim( "{$secondary_colors['style']} ${background_colors['style']}" );
139
	$player_inline_style .= get_css_vars( $attributes );
140
141
	$block_classname = Jetpack_Gutenberg::block_classes( FEATURE_NAME, $attributes, array( 'is-default' ) );
142
	$is_amp          = ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() );
143
144
	ob_start();
145
	?>
146
	<div class="<?php echo esc_attr( $block_classname ); ?>" id="<?php echo esc_attr( $instance_id ); ?>">
147
		<section
148
			class="jetpack-podcast-player <?php echo esc_attr( $player_classes_name ); ?>"
149
			style="<?php echo esc_attr( $player_inline_style ); ?>"
150
		>
151
			<?php
152
			render(
153
				'podcast-header',
154
				array_merge(
155
					$player_props,
156
					array(
157
						'primary_colors' => $primary_colors,
158
						'player_id'      => $player_data['playerId'],
159
					)
160
				)
161
			);
162
			?>
163
			<ol class="jetpack-podcast-player__tracks">
164
				<?php foreach ( $player_data['tracks'] as $track_index => $attachment ) : ?>
165
					<?php
166
					render(
167
						'playlist-track',
168
						array(
169
							'is_active'        => 0 === $track_index,
170
							'attachment'       => $attachment,
171
							'primary_colors'   => $primary_colors,
172
							'secondary_colors' => $secondary_colors,
173
						)
174
					);
175
					?>
176
				<?php endforeach; ?>
177
			</ol>
178
		</section>
179
		<?php if ( ! $is_amp ) : ?>
180
		<script type="application/json"><?php echo wp_json_encode( $player_props ); ?></script>
181
		<?php endif; ?>
182
	</div>
183
	<?php if ( ! $is_amp ) : ?>
184
	<script>
185
		( function( instanceId ) {
186
			document.getElementById( instanceId ).classList.remove( 'is-default' );
187
			window.jetpackPodcastPlayers=(window.jetpackPodcastPlayers||[]);
188
			window.jetpackPodcastPlayers.push( instanceId );
189
		} )( <?php echo wp_json_encode( $instance_id ); ?> );
190
	</script>
191
	<?php endif; ?>
192
	<?php
193
	/**
194
	 * Enqueue necessary scripts and styles.
195
	 */
196
	if ( ! $is_amp ) {
197
		wp_enqueue_style( 'wp-mediaelement' );
198
	}
199
	Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME, array( 'mediaelement' ) );
200
201
	return ob_get_clean();
202
}
203
204
/**
205
 * Given the color name, block attributes and the CSS property,
206
 * the function will return an array with the `class` and `style`
207
 * HTML attributes to be used straight in the markup.
208
 *
209
 * @example
210
 * $color = get_colors( 'secondary', $attributes, 'border-color'
211
 *  => array( 'class' => 'has-secondary', 'style' => 'border-color: #333' )
212
 *
213
 * @param string $name     Color attribute name, for instance `primary`, `secondary`, ...
214
 * @param array  $attrs    Block attributes.
215
 * @param string $property Color CSS property, fo instance `color`, `background-color`, ...
216
 * @return array           Colors array.
217
 */
218
function get_colors( $name, $attrs, $property ) {
219
	$attr_color  = "{$name}Color";
220
	$attr_custom = 'custom' . ucfirst( $attr_color );
221
222
	$color        = isset( $attrs[ $attr_color ] ) ? $attrs[ $attr_color ] : null;
223
	$custom_color = isset( $attrs[ $attr_custom ] ) ? $attrs[ $attr_custom ] : null;
224
225
	$colors = array(
226
		'class' => '',
227
		'style' => '',
228
	);
229
230
	if ( $color || $custom_color ) {
231
		$colors['class'] .= "has-{$name}";
232
233
		if ( $color ) {
234
			$colors['class'] .= " has-{$color}-{$property}";
235
		} elseif ( $custom_color ) {
236
			$colors['style'] .= "{$property}: {$custom_color};";
237
		}
238
	}
239
240
	return $colors;
241
}
242
243
/**
244
 * It generates a string with CSS variables according to the
245
 * block colors, prefixing each one with `--jetpack-podcast-player'.
246
 *
247
 * @param array $attrs Podcast Block attributes object.
248
 * @return string      CSS variables depending on block colors.
249
 */
250
function get_css_vars( $attrs ) {
251
	$colors_name = array( 'primary', 'secondary', 'background' );
252
253
	$inline_style = '';
254
	foreach ( $colors_name as $color ) {
255
		$hex_color = 'hex' . ucfirst( $color ) . 'Color';
256
		if ( ! empty( $attrs[ $hex_color ] ) ) {
257
			$inline_style .= " --jetpack-podcast-player-{$color}: {$attrs[ $hex_color ]};";
258
		}
259
	}
260
	return $inline_style;
261
}
262
263
/**
264
 * Render the given template in server-side.
265
 * Important note:
266
 *    The $template_props array will be extracted.
267
 *    This means it will create a var for each array item.
268
 *    Keep it mind when using this param to pass
269
 *    properties to the template.
270
 *
271
 * @param string $name           Template name, available in `./templates` folder.
272
 * @param array  $template_props Template properties. Optional.
273
 * @param bool   $print          Render template. True as default.
274
 * @return false|string          HTML markup or false.
275
 */
276
function render( $name, $template_props = array(), $print = true ) {
277
	if ( ! strpos( $name, '.php' ) ) {
278
		$name = $name . '.php';
279
	}
280
281
	$template_path = dirname( __FILE__ ) . '/templates/' . $name;
282
283
	if ( ! file_exists( $template_path ) ) {
284
		return '';
285
	}
286
287
	/*
288
	 * Optionally provided an assoc array of data to pass to template.
289
	 * IMPORTANT: It will be extracted into variables.
290
	 */
291
	if ( is_array( $template_props ) ) {
292
		/*
293
		 * It ignores the `discouraging` sniffer rule for extract, since it's needed
294
		 * to make the templating system works.
295
		 */
296
		extract( $template_props ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
297
	}
298
299
	if ( $print ) {
300
		include $template_path;
301
	} else {
302
		ob_start();
303
		include $template_path;
304
		$markup = ob_get_contents();
305
		ob_end_clean();
306
307
		return $markup;
308
	}
309
}
310