Completed
Push — fusion-sync/danroundhill/r2061... ( 6c7cf7...0f1caf )
by Jeremy
213:37 queued 206:26
created

modules/shortcodes/soundcloud.php (2 issues)

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
 * SoundCloud Shortcode
4
 * Based on this plugin: https://wordpress.org/plugins/soundcloud-shortcode/
5
 *
6
 * Credits:
7
 * Original version: Johannes Wagener <[email protected]>
8
 * Options support: Tiffany Conroy <[email protected]>
9
 * HTML5 & oEmbed support: Tim Bormans <[email protected]>
10
 *
11
 * Examples:
12
 * [soundcloud]http://soundcloud.com/forss/flickermood[/soundcloud]
13
 * [soundcloud url="https://api.soundcloud.com/tracks/156661852" params="auto_play=false&amp;hide_related=false&amp;visual=false" width="100%" height="450" iframe="true" /]
14
 * [soundcloud url="https://api.soundcloud.com/tracks/156661852" params="auto_play=false&amp;hide_related=false&amp;visual=true" width="100%" height="450" iframe="true" /]
15
 * [soundcloud url="https://soundcloud.com/closetorgan/paul-is-dead" width=400 height=400]
16
 * [soundcloud url="https://soundcloud.com/closetorgan/sets/smells-like-lynx-africa-private"]
17
 * [soundcloud url="https://soundcloud.com/closetorgan/sets/smells-like-lynx-africa-private" color="00cc11"]
18
 * <iframe width="100%" height="450" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/150745932&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;visual=true"></iframe>
19
 *
20
 * @package Jetpack
21
 */
22
23
/**
24
 * SoundCloud shortcode handler
25
 *
26
 * @param  string|array $atts        The attributes passed to the shortcode like [soundcloud attr1="value" /].
27
 *                                   Is an empty string when no arguments are given.
28
 * @param  string       $content     The content between non-self closing [soundcloud]...[/soundcloud] tags.
29
 *
30
 * @return string                  Widget embed code HTML
31
 */
32
function soundcloud_shortcode( $atts, $content = null ) {
33
	global $wp_embed;
34
35
	// Custom shortcode options.
36
	$shortcode_options = array_merge(
37
		array( 'url' => trim( $content ) ),
38
		is_array( $atts ) ? $atts : array()
39
	);
40
41
	// The "url" option is required.
42 View Code Duplication
	if ( empty( $shortcode_options['url'] ) ) {
43
		if ( current_user_can( 'edit_posts' ) ) {
44
			return esc_html__( 'Please specify a Soundcloud URL.', 'jetpack' );
45
		} else {
46
			return '<!-- Missing Soundcloud URL -->';
47
		}
48
	}
49
50
	// Turn shortcode option "param" (param=value&param2=value) into array of params.
51
	$shortcode_params = array();
52
	if ( isset( $shortcode_options['params'] ) ) {
53
		parse_str( html_entity_decode( $shortcode_options['params'] ), $shortcode_params );
54
		$shortcode_options = array_merge(
55
			$shortcode_options,
56
			$shortcode_params
57
		);
58
		unset( $shortcode_options['params'] );
59
	}
60
61
	$options = shortcode_atts(
62
		// This list used to include an 'iframe' option. We don't include it anymore as we don't support the Flash player anymore.
63
		array(
64
			'url'           => '',
65
			'width'         => soundcloud_get_option( 'player_width' ),
66
			'height'        => soundcloud_url_has_tracklist( $shortcode_options['url'] ) ? soundcloud_get_option( 'player_height_multi' ) : soundcloud_get_option( 'player_height' ),
67
			'auto_play'     => soundcloud_get_option( 'auto_play' ),
68
			'hide_related'  => false,
69
			'visual'        => false,
70
			'show_comments' => soundcloud_get_option( 'show_comments' ),
71
			'color'         => soundcloud_get_option( 'color' ),
72
			'show_user'     => false,
73
			'show_reposts'  => false,
74
		),
75
		$shortcode_options,
76
		'soundcloud'
77
	);
78
79
	// "width" needs to be an integer.
80
	if ( ! empty( $options['width'] ) && ! preg_match( '/^\d+$/', $options['width'] ) ) {
81
		// set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone.
82
		$options['width'] = 0;
83
	}
84
	// Set default width if not defined.
85
	$width = ! empty( $options['width'] ) ? absint( $options['width'] ) : '100%';
86
87
	// Set default height if not defined.
88
	if (
89
		empty( $options['height'] )
90
		|| (
91
			// "height" needs to be an integer.
92
			! empty( $options['height'] )
93
			&& ! preg_match( '/^\d+$/', $options['height'] )
94
		)
95
	) {
96
		if (
97
			soundcloud_url_has_tracklist( $options['url'] )
98
			|| 'true' === $options['visual']
99
		) {
100
			$height = 450;
101
		} else {
102
			$height = 166;
103
		}
104
	} else {
105
		$height = absint( $options['height'] );
106
	}
107
108
	// Set visual to false when displaying the smallest player.
109
	if ( '20' === $options['height'] ) {
110
		$options['visual'] = false;
111
	}
112
113
	if (
114
		class_exists( 'Jetpack_AMP_Support' )
115
		&& Jetpack_AMP_Support::is_amp_request()
116
		&& ! empty( $options['url'] )
117
		&& 'api.soundcloud.com' !== wp_parse_url( $options['url'], PHP_URL_HOST )
0 ignored issues
show
The call to wp_parse_url() has too many arguments starting with PHP_URL_HOST.

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
118
	) {
119
		// Defer to oEmbed if an oEmbeddable URL is provided.
120
		return $wp_embed->shortcode( $options, $options['url'] );
121
	}
122
123
	// Build our list of Soundcloud parameters.
124
	$query_args = array(
125
		'url' => rawurlencode( $options['url'] ),
126
	);
127
128
	// Add our options, if they are set to true or false.
129
	foreach ( $options as $name => $value ) {
130
		if ( 'true' === $value ) {
131
			$query_args[ $name ] = 'true';
132
		}
133
134
		if ( 'false' === $value || false === $value ) {
135
			$query_args[ $name ] = 'false';
136
		}
137
	}
138
139
	// Add the color parameter if it was specified and is a valid color.
140
	if ( ! empty( $options['color'] ) ) {
141
		$color = sanitize_hex_color_no_hash( $options['color'] );
142
		if ( ! empty( $color ) ) {
143
			$query_args['color'] = $color;
144
		}
145
	}
146
147
	// Build final embed URL.
148
	$url = add_query_arg(
149
		$query_args,
150
		'https://w.soundcloud.com/player/'
151
	);
152
153
	return sprintf(
154
		'<iframe width="%1$s" height="%2$d" scrolling="no" frameborder="no" src="%3$s"></iframe>',
155
		esc_attr( $width ),
156
		esc_attr( $height ),
157
		$url
158
	);
159
}
160
add_shortcode( 'soundcloud', 'soundcloud_shortcode' );
161
162
/**
163
 * Plugin options getter
164
 *
165
 * @param  string|array $option  Option name.
166
 * @param  mixed        $default Default value.
167
 *
168
 * @return mixed                   Option value
169
 */
170
function soundcloud_get_option( $option, $default = false ) {
171
	$value = get_option( 'soundcloud_' . $option );
172
173
	return '' === $value ? $default : $value;
174
}
175
176
/**
177
 * Decide if a url has a tracklist
178
 *
179
 * @param string $url Soundcloud URL.
180
 *
181
 * @return boolean
182
 */
183
function soundcloud_url_has_tracklist( $url ) {
184
	return preg_match( '/^(.+?)\/(sets|groups|playlists)\/(.+?)$/', $url );
185
}
186
187
/**
188
 * SoundCloud Embed Reversal
189
 *
190
 * Converts a generic HTML embed code from SoundClound into a
191
 * WordPress.com-compatibly shortcode.
192
 *
193
 * @param string $content HTML content.
194
 *
195
 * @return string Parsed content.
196
 */
197
function jetpack_soundcloud_embed_reversal( $content ) {
198
	if ( ! is_string( $content ) || false === stripos( $content, 'w.soundcloud.com/player' ) ) {
199
		return $content;
200
	}
201
202
	$regexes = array();
203
204
	$regexes[] = '#<iframe[^>]+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"[^>]*+>\s*?</iframe>#i';
205
	$regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';
206
207
	foreach ( $regexes as $regex ) {
208
		if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
209
			continue;
210
		}
211
212
		foreach ( $matches as $match ) {
213
214
			// if pasted from the visual editor - prevent double encoding.
215
			$match[1] = str_replace( '&amp;amp;', '&amp;', $match[1] );
216
217
			$args = wp_parse_url( html_entity_decode( $match[1] ), PHP_URL_QUERY );
0 ignored issues
show
The call to wp_parse_url() has too many arguments starting with PHP_URL_QUERY.

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
218
			$args = wp_parse_args( $args );
219
220
			if ( ! preg_match( '#^(?:https?:)?//api\.soundcloud\.com/.+$#i', $args['url'], $url_matches ) ) {
221
				continue;
222
			}
223
224
			if ( ! preg_match( '#height="(\d+)"#i', $match[0], $hmatch ) ) {
225
				$height = '';
226
			} else {
227
				$height = ' height="' . intval( $hmatch[1] ) . '"';
228
			}
229
230
			unset( $args['url'] );
231
			$params = 'params="';
232
			if ( count( $args ) > 0 ) {
233
				foreach ( $args as $key => $value ) {
234
					$params .= esc_html( $key ) . '=' . esc_html( $value ) . '&amp;';
235
				}
236
				$params = substr( $params, 0, -5 );
237
			}
238
			$params .= '"';
239
240
			$shortcode = '[soundcloud url="' . esc_url( $url_matches[0] ) . '" ' . $params . ' width="100%"' . $height . ' iframe="true" /]';
241
242
			$replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
243
			$content       = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $shortcode ), $content );
244
245
			/** This action is documented in modules/shortcodes/youtube.php */
246
			do_action( 'jetpack_embed_to_shortcode', 'soundcloud', $url_matches[0] );
247
		}
248
	}
249
250
	return $content;
251
}
252
add_filter( 'pre_kses', 'jetpack_soundcloud_embed_reversal' );
253