soundcloud.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <?php
  2. /*
  3. Plugin Name: SoundCloud Shortcode
  4. Plugin URI: https://wordpress.org/extend/plugins/soundcloud-shortcode/
  5. Description: Converts SoundCloud WordPress shortcodes to a SoundCloud widget. Example: [soundcloud]http://soundcloud.com/forss/flickermood[/soundcloud]
  6. Version: 2.3
  7. Author: SoundCloud Inc., simplified for Jetpack by Automattic, Inc.
  8. Author URI: http://soundcloud.com
  9. License: GPLv2
  10. Original version: Johannes Wagener <johannes@soundcloud.com>
  11. Options support: Tiffany Conroy <tiffany@soundcloud.com>
  12. HTML5 & oEmbed support: Tim Bormans <tim@soundcloud.com>
  13. */
  14. /*
  15. A8C: Taken from http://plugins.svn.wordpress.org/soundcloud-shortcode/trunk/
  16. at revision 664386.
  17. Commenting out (instead of removing) and replacing code with custom modifs
  18. so it's eqsy to see what differs from the standard DOTORG version.
  19. All custom modifs are annoted with "A8C" keyword in comment.
  20. */
  21. /**
  22. * Register oEmbed provider
  23. */
  24. /* A8C: oEmbed is handled now in core; see wp-includes/class-oembed.php
  25. wp_oembed_add_provider( '#https?://(?:api\.)?soundcloud\.com/.*#i', 'http://soundcloud.com/oembed', true );
  26. */
  27. /**
  28. * Register SoundCloud shortcode
  29. */
  30. add_shortcode( 'soundcloud', 'soundcloud_shortcode' );
  31. /**
  32. * SoundCloud shortcode handler
  33. *
  34. * @param string|array $atts The attributes passed to the shortcode like [soundcloud attr1="value" /].
  35. * Is an empty string when no arguments are given.
  36. * @param string $content The content between non-self closing [soundcloud]...[/soundcloud] tags.
  37. *
  38. * @return string Widget embed code HTML
  39. */
  40. function soundcloud_shortcode( $atts, $content = null ) {
  41. // Custom shortcode options
  42. $shortcode_options = array_merge( array( 'url' => trim( $content ) ), is_array( $atts ) ? $atts : array() );
  43. // Turn shortcode option "param" (param=value&param2=value) into array
  44. $shortcode_params = array();
  45. if ( isset( $shortcode_options['params'] ) ) {
  46. parse_str( html_entity_decode( $shortcode_options['params'] ), $shortcode_params );
  47. }
  48. $shortcode_options['params'] = $shortcode_params;
  49. /* A8C: The original plugin exposes options we don't. SoundCloud omits "visual" shortcode
  50. option when false, so if logic here remains, impossible to have non-visual shortcode.
  51. $player_type = soundcloud_get_option( 'player_type', 'visual' );
  52. $isIframe = $player_type !== 'flash';
  53. $isVisual = ! $player_type || $player_type === 'visual' || $shortcode_options['visual'];
  54. */
  55. // User preference options
  56. $plugin_options = array_filter(
  57. array(
  58. 'iframe' => true, // A8C: See above comment; flash is not a supported option
  59. 'width' => soundcloud_get_option( 'player_width' ),
  60. 'height' => soundcloud_url_has_tracklist( $shortcode_options['url'] ) ? soundcloud_get_option( 'player_height_multi' ) : soundcloud_get_option( 'player_height' ),
  61. 'params' => array_filter(
  62. array(
  63. 'auto_play' => soundcloud_get_option( 'auto_play' ),
  64. 'show_comments' => soundcloud_get_option( 'show_comments' ),
  65. 'color' => soundcloud_get_option( 'color' ),
  66. 'visual' => 'false', // A8C: Merged with params below at $options assignment
  67. )
  68. ),
  69. )
  70. );
  71. // Needs to be an array
  72. if ( ! isset( $plugin_options['params'] ) ) {
  73. $plugin_options['params'] = array();
  74. }
  75. // plugin options < shortcode options
  76. $options = array_merge(
  77. $plugin_options,
  78. $shortcode_options
  79. );
  80. // plugin params < shortcode params
  81. $options['params'] = array_merge(
  82. $plugin_options['params'],
  83. $shortcode_options['params']
  84. );
  85. // The "url" option is required
  86. if ( ! isset( $options['url'] ) ) {
  87. return '';
  88. } else {
  89. $options['url'] = trim( $options['url'] );
  90. }
  91. // Both "width" and "height" need to be integers
  92. if ( isset( $options['width'] ) && ! preg_match( '/^\d+$/', $options['width'] ) ) {
  93. // set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone
  94. $options['width'] = 0;
  95. }
  96. if ( isset( $options['height'] ) && ! preg_match( '/^\d+$/', $options['height'] ) ) {
  97. unset( $options['height'] );
  98. }
  99. // The "iframe" option must be true to load the iframe widget
  100. $iframe = soundcloud_booleanize( $options['iframe'] );
  101. // Remove visual parameter from Flash widget, when it's false because that's the default, or when displaying the smallest player
  102. if ( $options['params']['visual'] && ( ! $iframe || ! soundcloud_booleanize( $options['params']['visual'] ) || ( isset( $options['height'] ) && '20' == $options['height'] ) ) ) {
  103. unset( $options['params']['visual'] );
  104. }
  105. // Merge in "url" value
  106. $options['params'] = array_merge(
  107. array(
  108. 'url' => $options['url'],
  109. ), $options['params']
  110. );
  111. // Return html embed code
  112. if ( $iframe ) {
  113. return soundcloud_iframe_widget( $options );
  114. } else {
  115. return soundcloud_flash_widget( $options );
  116. }
  117. }
  118. /**
  119. * Plugin options getter
  120. *
  121. * @param string|array $option Option name
  122. * @param mixed $default Default value
  123. *
  124. * @return mixed Option value
  125. */
  126. function soundcloud_get_option( $option, $default = false ) {
  127. $value = get_option( 'soundcloud_' . $option );
  128. return $value === '' ? $default : $value;
  129. }
  130. /**
  131. * Booleanize a value
  132. *
  133. * @param boolean|string $value
  134. *
  135. * @return boolean
  136. */
  137. function soundcloud_booleanize( $value ) {
  138. return is_bool( $value ) ? $value : $value === 'true' ? true : false;
  139. }
  140. /**
  141. * Decide if a url has a tracklist
  142. *
  143. * @param string $url
  144. *
  145. * @return boolean
  146. */
  147. function soundcloud_url_has_tracklist( $url ) {
  148. return preg_match( '/^(.+?)\/(sets|groups|playlists)\/(.+?)$/', $url );
  149. }
  150. /**
  151. * Parameterize url
  152. *
  153. * @param array $match Matched regex
  154. *
  155. * @return string Parameterized url
  156. */
  157. function soundcloud_oembed_params_callback( $match ) {
  158. global $soundcloud_oembed_params;
  159. // Convert URL to array
  160. $url = parse_url( urldecode( $match[1] ) );
  161. // Convert URL query to array
  162. parse_str( $url['query'], $query_array );
  163. // Build new query string
  164. $query = http_build_query( array_merge( $query_array, $soundcloud_oembed_params ) );
  165. return 'src="' . $url['scheme'] . '://' . $url['host'] . $url['path'] . '?' . $query;
  166. }
  167. /**
  168. * Iframe widget embed code
  169. *
  170. * @param array $options Parameters
  171. *
  172. * @return string Iframe embed code
  173. */
  174. function soundcloud_iframe_widget( $options ) {
  175. // Build URL
  176. $url = set_url_scheme( 'https://w.soundcloud.com/player/?' . http_build_query( $options['params'] ) );
  177. // Set default width if not defined
  178. $width = isset( $options['width'] ) && $options['width'] !== 0 ? $options['width'] : '100%';
  179. // Set default height if not defined
  180. $height = isset( $options['height'] ) && $options['height'] !== 0
  181. ? $options['height']
  182. : ( soundcloud_url_has_tracklist( $options['url'] ) || ( isset( $options['params']['visual'] ) && soundcloud_booleanize( $options['params']['visual'] ) ) ? '450' : '166' );
  183. return sprintf( '<iframe width="%s" height="%s" scrolling="no" frameborder="no" src="%s"></iframe>', $width, $height, $url );
  184. }
  185. /**
  186. * Legacy Flash widget embed code
  187. *
  188. * @param array $options Parameters
  189. *
  190. * @return string Flash embed code
  191. */
  192. function soundcloud_flash_widget( $options ) {
  193. // Build URL
  194. $url = set_url_scheme( 'https://player.soundcloud.com/player.swf?' . http_build_query( $options['params'] ) );
  195. // Set default width if not defined
  196. $width = isset( $options['width'] ) && $options['width'] !== 0 ? $options['width'] : '100%';
  197. // Set default height if not defined
  198. $height = isset( $options['height'] ) && $options['height'] !== 0 ? $options['height'] : ( soundcloud_url_has_tracklist( $options['url'] ) ? '255' : '81' );
  199. return preg_replace(
  200. '/\s\s+/', '', sprintf(
  201. '<object width="%s" height="%s">
  202. <param name="movie" value="%s" />
  203. <param name="allowscriptaccess" value="always" />
  204. <embed width="%s" height="%s" src="%s" allowscriptaccess="always" type="application/x-shockwave-flash"></embed>
  205. </object>', $width, $height, $url, $width, $height, $url
  206. )
  207. );
  208. }
  209. /**
  210. * SoundCloud Embed Reversal
  211. *
  212. * Converts a generic HTML embed code from SoundClound into a
  213. * WordPress.com-compatibly shortcode.
  214. *
  215. * @param string $content HTML content.
  216. *
  217. * @return string Parsed content.
  218. */
  219. function jetpack_soundcloud_embed_reversal( $content ) {
  220. if ( ! is_string( $content ) || false === stripos( $content, 'w.soundcloud.com/player' ) ) {
  221. return $content;
  222. }
  223. /* Sample embed code:
  224. <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>
  225. */
  226. $regexes = array();
  227. $regexes[] = '#<iframe[^>]+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"[^>]*+>\s*?</iframe>#i';
  228. $regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';
  229. foreach ( $regexes as $regex ) {
  230. if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
  231. continue;
  232. }
  233. foreach ( $matches as $match ) {
  234. // if pasted from the visual editor - prevent double encoding
  235. $match[1] = str_replace( '&amp;amp;', '&amp;', $match[1] );
  236. $args = parse_url( html_entity_decode( $match[1] ), PHP_URL_QUERY );
  237. $args = wp_parse_args( $args );
  238. if ( ! preg_match( '#^(?:https?:)?//api\.soundcloud\.com/.+$#i', $args['url'], $url_matches ) ) {
  239. continue;
  240. }
  241. if ( ! preg_match( '#height="(\d+)"#i', $match[0], $hmatch ) ) {
  242. $height = '';
  243. } else {
  244. $height = ' height="' . intval( $hmatch[1] ) . '"';
  245. }
  246. unset( $args['url'] );
  247. $params = 'params="';
  248. if ( count( $args ) > 0 ) {
  249. foreach ( $args as $key => $value ) {
  250. $params .= esc_html( $key ) . '=' . esc_html( $value ) . '&amp;';
  251. }
  252. $params = substr( $params, 0, -5 );
  253. }
  254. $params .= '"';
  255. $shortcode = '[soundcloud url="' . esc_url( $url_matches[0] ) . '" ' . $params . ' width="100%"' . $height . ' iframe="true" /]';
  256. $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
  257. $content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $shortcode ), $content );
  258. /** This action is documented in modules/shortcodes/youtube.php */
  259. do_action( 'jetpack_embed_to_shortcode', 'soundcloud', $url_matches[0] );
  260. }
  261. }
  262. return $content;
  263. }
  264. add_filter( 'pre_kses', 'jetpack_soundcloud_embed_reversal' );