googleapps.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. /**
  3. * Google Docs and Google Calendar Shortcode
  4. *
  5. * Presentation:
  6. * <iframe src="https://docs.google.com/present/embed?id=dhfhrphh_123drp8s65c&interval=15&autoStart=true&loop=true&size=l" frameborder="0" width="700" height="559"></iframe>
  7. * <iframe src="https://docs.google.com/presentation/embed?id=13ItX4jV0SOSdr-ZjHarcpTh9Lr4omfsHAp87jpxv8-0&start=false&loop=false&delayms=3000" frameborder="0" width="960" height="749" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
  8. *
  9. * Document:
  10. * <iframe src="https://docs.google.com/document/pub?id=1kDatklacdZ_tZUOpWtt_ONzY97Ldj2zFcuO9LBY2Ln4&amp;embedded=true"></iframe>
  11. * <iframe src="https://docs.google.com/document/d/1kDatklacdZ_tZUOpWtt_ONzY97Ldj2zFcuO9LBY2Ln4/pub?embedded=true"></iframe>
  12. * <iframe src="https://docs.google.com/document/d/e/2PACX-1vRkpIdasKL-eKXDjJgpEONduUspZTz0YmKaajfie0eJYnzikuyusuG1_V8X8T9XflN9l8A1oCM2sgEA/pub?embedded=true"></iframe>
  13. *
  14. * External document:
  15. * <iframe width=100% height=560px frameborder=0 src=https://docs.google.com/a/pranab.in/viewer?a=v&pid=explorer&chrome=false&embedded=true&srcid=1VTMwdgGiDMt8MCr75-YkQP-4u9WmEp1Qvf6C26KYBgFilxU2qndpd-VHhBIn&hl=en></iframe>
  16. *
  17. * Spreadsheet Form:
  18. * <iframe src="https://spreadsheets.google.com/embeddedform?formkey=dEVOYnMzZG5jMUpGbjFMYjFYNVB3NkE6MQ" width="760" height="710" frameborder="0" marginheight="0" marginwidth="0">Loading...</iframe>
  19. *
  20. * Spreadsheet Widget:
  21. * <iframe width='500' height='300' frameborder='0' src='https://spreadsheets1.google.com/a/petedavies.com/pub?hl=en&hl=en&key=0AjSij7nlnXvKdHNsNjRSWG12YmVfOEFwdlMxQ3J1S1E&single=true&gid=0&output=html&widget=true'></iframe>
  22. * <iframe width='500' height='300' frameborder='0' src='https://spreadsheets.google.com/spreadsheet/pub?hl=en&hl=en&key=0AhInIwfvYrIUdGJiTXhtUEhBSFVPUzdRZU5OMDlqdnc&output=html&widget=true'></iframe>
  23. *
  24. * Calendar:
  25. * <iframe src="https://www.google.com/calendar/embed?src=serjant%40gmail.com&ctz=Europe/Sofia" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>
  26. * <iframe src="http://www.google.com/calendar/hosted/belcastro.com/embed?src=n8nr8sd6v9hnus3nmlk7ed1238%40group.calendar.google.com&ctz=Europe/Zurich" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>
  27. *
  28. * Customized calendar:
  29. * <iframe src="https://www.google.com/calendar/embed?title=asdf&amp;showTitle=0&amp;showNav=0&amp;showDate=0&amp;showPrint=0&amp;showTabs=0&amp;showCalendars=0&amp;
  30. * showTz=0&amp;mode=AGENDA&amp;height=300&amp;wkst=2&amp;hl=fi&amp;bgcolor=%23ffcccc&amp;src=m52gdmbgelo3itf00u1v44g0ns%40group.calendar.google.com&amp;color=%234E5D6C&amp;
  31. * src=serjant%40gmail.com&amp;color=%235229A3&amp;ctz=Europe%2FRiga" style=" border:solid 1px #777 " width="500" height="300" frameborder="0" scrolling="no"></iframe>
  32. *
  33. * Generic
  34. * <iframe src="https://docs.google.com/file/d/0B0SIdZW7iu-zX1RWREJpMXVHZVU/preview" width="640" height="480"></iframe>
  35. */
  36. add_filter( 'pre_kses', 'googleapps_embed_to_shortcode' );
  37. add_shortcode( 'googleapps', 'googleapps_shortcode' );
  38. /**
  39. * Reverse iframe embed to shortcode mapping HTML attributes to shortcode attributes.
  40. *
  41. * @since 4.5.0
  42. *
  43. * @param string $content
  44. *
  45. * @return mixed
  46. */
  47. function googleapps_embed_to_shortcode( $content ) {
  48. if ( ! is_string( $content ) || false === stripos( $content, '<iframe' ) && false === stripos( $content, '.google.com' ) ) {
  49. return $content;
  50. }
  51. $regexp = '#<iframe((?:\s+\w+="[^"]*")*?)\s*src="https?://(docs|drive|spreadsheets\d*|calendar|www)*\.google\.com/(?!maps)([-\w\./]+)(?:\?)?([^"]+)?"\s*((?:\s+\w+="[^"]*")*?)>.*?</iframe>#i';
  52. $regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
  53. $regexp_squot = str_replace( '"', "'", $regexp );
  54. $regexp_ent_squot = str_replace( '"', "'", $regexp_ent );
  55. $regexp_noquot = '!<iframe(.*?)src=https://(docs|drive)\.google\.com/[-\.\w/]*?(viewer)\?(.*?)>(.*?)</iframe>!';
  56. $regexp_ent_noquot = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp_noquot, ENT_NOQUOTES ) );
  57. foreach ( array( 'regexp', 'regexp_ent', 'regexp_squot', 'regexp_ent_squot', 'regexp_noquot', 'regexp_ent_noquot' ) as $reg ) {
  58. if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) ) {
  59. continue;
  60. }
  61. foreach ( $matches as $match ) {
  62. $params = $match[1] . $match[5];
  63. if ( in_array( $reg, array( 'regexp_ent', 'regexp_ent_squot' ) ) ) {
  64. $params = html_entity_decode( $params );
  65. }
  66. $params = wp_kses_hair( $params, array( 'http' ) );
  67. $width = $height = 0;
  68. if ( isset( $params['width'] ) ) {
  69. $width = (int) $params['width']['value'];
  70. }
  71. if ( isset( $params['height'] ) ) {
  72. $height = (int) $params['height']['value'];
  73. }
  74. // allow the user to specify width greater than 200 inside text widgets
  75. if ( $width > 400 && isset( $_POST['widget-text'] ) ) {
  76. $width = 200;
  77. $height = 200;
  78. }
  79. $attributes = '';
  80. if ( isset( $params['width'] ) && '100%' == $params['width']['value'] ) {
  81. $width = '100%';
  82. }
  83. if ( $width ) {
  84. $attributes = ' width="' . $width . '"';
  85. }
  86. if ( $height ) {
  87. $attributes .= ' height="' . $height . '"';
  88. }
  89. $domain = 'spreadsheets';
  90. if ( in_array( $match[2], array( 'docs', 'drive', 'www', 'calendar' ) ) ) {
  91. $domain = $match[2];
  92. }
  93. // Make sure this is actually something that the shortcode supports. If it's not, leave the HTML alone.
  94. if ( ! googleapps_validate_domain_and_dir( $domain, $match[3] ) ) {
  95. continue;
  96. }
  97. /** This action is documented in modules/widgets/social-media-icons.php */
  98. do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', googleapps_service_name( $domain, $match[3] ) );
  99. $content = str_replace( $match[0], '[googleapps domain="' . $domain . '" dir="' . $match[3] . '" query="' . esc_attr( $match[4] ) . '"' . $attributes . ' /]', $content );
  100. }
  101. }
  102. return $content;
  103. }
  104. /**
  105. * Parse shortcode attributes and output a Google Docs embed.
  106. *
  107. * @since 4.5.0
  108. *
  109. * @param array $atts
  110. *
  111. * @return string
  112. */
  113. function googleapps_shortcode( $atts ) {
  114. global $content_width;
  115. $attr = shortcode_atts(
  116. array(
  117. 'width' => '100%',
  118. 'height' => '560',
  119. 'domain' => 'docs',
  120. 'dir' => 'document',
  121. 'query' => '',
  122. 'src' => '',
  123. ), $atts
  124. );
  125. if ( isset( $content_width ) && is_numeric( $attr['width'] ) && $attr['width'] > $content_width ) {
  126. $attr['width'] = $content_width;
  127. }
  128. if ( isset( $content_width ) && '560' === $attr['height'] ) {
  129. $attr['height'] = $content_height = floor( $content_width * 3 / 4 );
  130. }
  131. if ( isset( $atts[0] ) && $atts[0] ) {
  132. $attr['src'] = $atts[0];
  133. }
  134. if ( $attr['src'] && preg_match( '!https?://(docs|drive|spreadsheets\d*|calendar|www)*\.google\.com/([-\w\./]+)\?([^"]+)!', $attr['src'], $matches ) ) {
  135. $attr['domain'] = $matches[1];
  136. $attr['dir'] = $matches[2];
  137. parse_str( htmlspecialchars_decode( $matches[3] ), $query_ar );
  138. $query_ar['chrome'] = 'false';
  139. $query_ar['embedded'] = 'true';
  140. $attr['query'] = http_build_query( $query_ar );
  141. }
  142. if ( ! googleapps_validate_domain_and_dir( $attr['domain'], $attr['dir'] ) ) {
  143. return '<!-- Unsupported URL -->';
  144. }
  145. $attr['query'] = $attr['dir'] . '?' . $attr['query'];
  146. /** This action is documented in modules/widgets/social-media-icons.php */
  147. do_action( 'jetpack_bump_stats_extras', 'embeds', googleapps_service_name( $attr['domain'], $attr['dir'] ) );
  148. return sprintf(
  149. '<iframe src="%s" frameborder="0" width="%s" height="%s" marginheight="0" marginwidth="0"></iframe>',
  150. esc_url( 'https://' . $attr['domain'] . '.google.com/' . $attr['query'] ),
  151. esc_attr( $attr['width'] ),
  152. esc_attr( $attr['height'] )
  153. );
  154. }
  155. /**
  156. * Check that the domain blogs to a Google Apps domain.
  157. *
  158. * @since 4.5.0
  159. *
  160. * @param string $domain
  161. * @param string $dir
  162. *
  163. * @return bool
  164. */
  165. function googleapps_validate_domain_and_dir( $domain, $dir ) {
  166. if ( ! in_array( $domain, array( 'docs', 'drive', 'www', 'spreadsheets', 'calendar' ) ) ) {
  167. return false;
  168. }
  169. // Calendars
  170. if ( ( 'www' === $domain || 'calendar' === $domain ) && 'calendar/' !== substr( $dir, 0, 9 ) ) {
  171. return false;
  172. }
  173. // Docs
  174. if ( in_array( $domain, array( 'docs', 'drive' ) ) && ! preg_match( '![-\.\w/]*(presentation/embed|presentation/d/(.*)|present/embed|document/pub|spreadsheets/d/(.*)|document/d/(e/)?[\w-]+/pub|file/d/[\w-]+/preview|viewer|forms/d/(.*)/viewform|spreadsheet/\w+)$!', $dir ) ) {
  175. return false;
  176. }
  177. // Spreadsheets
  178. if ( 'spreadsheets' == $domain && ! preg_match( '!^([-\.\w/]+/pub|[-\.\w/]*embeddedform)$!', $dir ) ) {
  179. return false;
  180. }
  181. return true;
  182. }
  183. /**
  184. * Get the name of the service we'll be embedding.
  185. *
  186. * @since 4.5.0
  187. *
  188. * @param string $domain
  189. * @param string $dir
  190. *
  191. * @return string
  192. */
  193. function googleapps_service_name( $domain, $dir ) {
  194. switch ( $domain ) {
  195. case 'drive':
  196. case 'docs':
  197. $service_name = ( 'present/embed' == $dir ) ? 'googledocs_presentation' : 'googledocs_document';
  198. break;
  199. case 'spreadsheets':
  200. $service_name = ( 'embeddedform' == $dir ) ? 'googledocs_form' : 'googledocs_spreadsheet';
  201. break;
  202. case 'calendar':
  203. default:
  204. $service_name = 'google_calendar';
  205. }
  206. return $service_name;
  207. }