PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | modules/shortcodes/googleapps.php +262 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,262 @@
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 + * @package automattic/jetpack
37 + */
38 +
39 +if ( ! defined( 'ABSPATH' ) ) {
40 + exit( 0 );
41 +}
42 +
43 +if ( jetpack_shortcodes_should_hook_pre_kses() ) {
44 + add_filter( 'pre_kses', 'googleapps_embed_to_shortcode' );
45 +}
46 +
47 +add_shortcode( 'googleapps', 'googleapps_shortcode' );
48 +
49 +/**
50 + * Reverse iframe embed to shortcode mapping HTML attributes to shortcode attributes.
51 + *
52 + * @since 4.5.0
53 + *
54 + * @param string $content Post content.
55 + *
56 + * @return mixed
57 + */
58 +function googleapps_embed_to_shortcode( $content ) {
59 + if (
60 + ! is_string( $content )
61 + || false === stripos( $content, '<iframe' )
62 + && false === stripos( $content, '.google.com' )
63 + ) {
64 + return $content;
65 + }
66 +
67 + $regexp = '#<iframe((?:\s+\w+="[^"]*")*?)\s*src="https?://(docs|drive|spreadsheets\d*|calendar|www)*\.google\.com/(?!maps)([-\w\./]+)(?:\?)?([^"]+)?"\s*((?:\s+\w+="[^"]*")*?)>.*?</iframe>#i';
68 + $regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
69 + $regexp_squot = str_replace( '"', "'", $regexp );
70 + $regexp_ent_squot = str_replace( '"', "'", $regexp_ent );
71 + $regexp_noquot = '!<iframe(.*?)src=https://(docs|drive)\.google\.com/[-\.\w/]*?(viewer)\?(.*?)>(.*?)</iframe>!';
72 + $regexp_ent_noquot = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp_noquot, ENT_NOQUOTES ) );
73 +
74 + foreach ( compact( 'regexp', 'regexp_ent', 'regexp_squot', 'regexp_ent_squot', 'regexp_noquot', 'regexp_ent_noquot' ) as $reg => $regexp ) {
75 + if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
76 + continue;
77 + }
78 +
79 + foreach ( $matches as $match ) {
80 + $params = $match[1] . $match[5];
81 + if ( in_array( $reg, array( 'regexp_ent', 'regexp_ent_squot' ), true ) ) {
82 + $params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
83 + }
84 +
85 + $params = wp_kses_hair( $params, array( 'http' ) );
86 +
87 + $width = 0;
88 + $height = 0;
89 +
90 + if ( isset( $params['width'] ) ) {
91 + $width = (int) $params['width']['value'];
92 + }
93 +
94 + if ( isset( $params['height'] ) ) {
95 + $height = (int) $params['height']['value'];
96 + }
97 +
98 + // allow the user to specify width greater than 200 inside text widgets.
99 + if (
100 + $width > 400
101 + // We don't need to check a nonce here. A nonce is already checked "further up" in most code paths.
102 + // In the case where no nonce is ever checked, setting this $_POST parameter doesn't do anything the submitter couldn't already do (set the width/height).
103 + && isset( $_POST['widget-text'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
104 + ) {
105 + $width = 200;
106 + $height = 200;
107 + }
108 +
109 + $attributes = '';
110 + if ( isset( $params['width'] ) && '100%' === $params['width']['value'] ) {
111 + $width = '100%';
112 + }
113 +
114 + if ( $width ) {
115 + $attributes = ' width="' . $width . '"';
116 + }
117 +
118 + if ( $height ) {
119 + $attributes .= ' height="' . $height . '"';
120 + }
121 +
122 + $domain = 'spreadsheets';
123 + if ( in_array( $match[2], array( 'docs', 'drive', 'www', 'calendar' ), true ) ) {
124 + $domain = $match[2];
125 + }
126 +
127 + // Make sure this is actually something that the shortcode supports. If it's not, leave the HTML alone.
128 + if ( ! googleapps_validate_domain_and_dir( $domain, $match[3] ) ) {
129 + continue;
130 + }
131 +
132 + /** This action is documented in modules/widgets/social-media-icons.php */
133 + do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', googleapps_service_name( $domain, $match[3] ) );
134 +
135 + $content = str_replace( $match[0], '[googleapps domain="' . $domain . '" dir="' . $match[3] . '" query="' . esc_attr( $match[4] ) . '"' . $attributes . ' /]', $content );
136 + }
137 + }
138 +
139 + return $content;
140 +}
141 +
142 +/**
143 + * Parse shortcode attributes and output a Google Docs embed.
144 + *
145 + * @since 4.5.0
146 + *
147 + * @param array $atts Shortcode attributes.
148 + *
149 + * @return string
150 + */
151 +function googleapps_shortcode( $atts ) {
152 + global $content_width;
153 +
154 + $attr = shortcode_atts(
155 + array(
156 + 'width' => '100%',
157 + 'height' => '560',
158 + 'domain' => 'docs',
159 + 'dir' => 'document',
160 + 'query' => '',
161 + 'src' => '',
162 + ),
163 + $atts
164 + );
165 +
166 + if ( is_numeric( $content_width ) && $content_width > 0 && is_numeric( $attr['width'] ) && $attr['width'] > $content_width ) {
167 + $attr['width'] = $content_width;
168 + }
169 +
170 + if ( is_numeric( $content_width ) && $content_width > 0 && '560' === $attr['height'] ) {
171 + $attr['height'] = floor( $content_width * 3 / 4 );
172 + }
173 +
174 + if ( isset( $atts[0] ) && $atts[0] ) {
175 + $attr['src'] = $atts[0];
176 + }
177 +
178 + if ( $attr['src'] && preg_match( '!https?://(docs|drive|spreadsheets\d*|calendar|www)*\.google\.com/([-\w\./]+)\?([^"]+)!', $attr['src'], $matches ) ) {
179 + $attr['domain'] = $matches[1];
180 + $attr['dir'] = $matches[2];
181 + parse_str( htmlspecialchars_decode( $matches[3], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ), $query_ar );
182 + $query_ar['chrome'] = 'false';
183 + $query_ar['embedded'] = 'true';
184 + $attr['query'] = http_build_query( $query_ar );
185 + }
186 +
187 + if ( ! googleapps_validate_domain_and_dir( $attr['domain'], $attr['dir'] ) ) {
188 + return '<!-- Unsupported URL -->';
189 + }
190 +
191 + $attr['query'] = $attr['dir'] . '?' . $attr['query'];
192 +
193 + /** This action is documented in modules/widgets/social-media-icons.php */
194 + do_action( 'jetpack_bump_stats_extras', 'embeds', googleapps_service_name( $attr['domain'], $attr['dir'] ) );
195 +
196 + return sprintf(
197 + '<iframe src="%s" frameborder="0" width="%s" height="%s" marginheight="0" marginwidth="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>',
198 + esc_url( 'https://' . $attr['domain'] . '.google.com/' . $attr['query'] ),
199 + esc_attr( $attr['width'] ),
200 + esc_attr( $attr['height'] )
201 + );
202 +}
203 +
204 +/**
205 + * Check that the domain blogs to a Google Apps domain.
206 + *
207 + * @since 4.5.0
208 + *
209 + * @param string $domain Google subdomain.
210 + * @param string $dir Subdirectory of the shared URL.
211 + *
212 + * @return bool
213 + */
214 +function googleapps_validate_domain_and_dir( $domain, $dir ) {
215 + if ( ! in_array( $domain, array( 'docs', 'drive', 'www', 'spreadsheets', 'calendar' ), true ) ) {
216 + return false;
217 + }
218 +
219 + // Calendars.
220 + if ( ( 'www' === $domain || 'calendar' === $domain ) && ! str_starts_with( $dir, 'calendar/' ) ) {
221 + return false;
222 + }
223 +
224 + // Docs.
225 + if ( in_array( $domain, array( 'docs', 'drive' ), true ) && ! 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 ) ) {
226 + return false;
227 + }
228 +
229 + // Spreadsheets.
230 + if ( 'spreadsheets' === $domain && ! preg_match( '!^([-\.\w/]+/pub|[-\.\w/]*embeddedform)$!', $dir ) ) {
231 + return false;
232 + }
233 +
234 + return true;
235 +}
236 +
237 +/**
238 + * Get the name of the service we'll be embedding.
239 + *
240 + * @since 4.5.0
241 + *
242 + * @param string $domain Google subdomain.
243 + * @param string $dir Subdirectory of the shared URL.
244 + *
245 + * @return string
246 + */
247 +function googleapps_service_name( $domain, $dir ) {
248 + switch ( $domain ) {
249 + case 'drive':
250 + case 'docs':
251 + $service_name = ( 'present/embed' === $dir ) ? 'googledocs_presentation' : 'googledocs_document';
252 + break;
253 + case 'spreadsheets':
254 + $service_name = ( 'embeddedform' === $dir ) ? 'googledocs_form' : 'googledocs_spreadsheet';
255 + break;
256 + case 'calendar':
257 + default:
258 + $service_name = 'google_calendar';
259 + }
260 +
261 + return $service_name;
262 +}