PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.7.3
Jetpack – WP Security, Backup, Speed, & Growth v12.7.3
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 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / comments / comments.php
jetpack / modules / comments Last commit date
admin.php 2 years ago base.php 2 years ago comments.php 2 years ago
comments.php
793 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Module: Comments
4 *
5 * @package automattic/jetpack
6 */
7
8 require __DIR__ . '/base.php';
9 use Automattic\Jetpack\Connection\Tokens;
10
11 /**
12 * Main Comments class
13 *
14 * @package automattic/jetpack
15 * @since 1.4
16 */
17 class Jetpack_Comments extends Highlander_Comments_Base {
18
19 /** Variables *************************************************************/
20
21 /**
22 * Possible comment form sources - empty array as default
23 *
24 * @var array
25 */
26 public $id_sources = array();
27
28 /**
29 * Remote comment URL - empty string as default
30 *
31 * @var string
32 */
33 public $signed_url = '';
34
35 /**
36 * The default comment form color scheme - default is light
37 *
38 * @var string
39 * @see ::set_default_color_theme_based_on_theme_settings()
40 */
41 public $default_color_scheme = 'light';
42
43 /** Methods ***************************************************************/
44
45 /**
46 * Initialize class
47 */
48 public static function init() {
49 static $instance = false;
50
51 if ( ! $instance ) {
52 $instance = new Jetpack_Comments();
53 }
54
55 return $instance;
56 }
57
58 /**
59 * Main constructor for Comments
60 *
61 * @since 1.4
62 */
63 public function __construct() {
64 parent::__construct();
65
66 // Comments is loaded.
67
68 /**
69 * Fires after the Jetpack_Comments object has been instantiated
70 *
71 * @module comments
72 *
73 * @since 1.4.0
74 *
75 * @param array $jetpack_comments_loaded First element in array of type Jetpack_Comments
76 */
77 do_action_ref_array( 'jetpack_comments_loaded', array( $this ) );
78 add_action( 'after_setup_theme', array( $this, 'set_default_color_theme_based_on_theme_settings' ), 100 );
79 }
80
81 /**
82 * Set the default comments color theme based on theme settings
83 */
84 public function set_default_color_theme_based_on_theme_settings() {
85 if ( function_exists( 'twentyeleven_get_theme_options' ) ) {
86 $theme_options = twentyeleven_get_theme_options();
87 $theme_color_scheme = isset( $theme_options['color_scheme'] ) ? $theme_options['color_scheme'] : 'transparent';
88 } else {
89 $theme_color_scheme = get_theme_mod( 'color_scheme', 'transparent' );
90 }
91 // Default for $theme_color_scheme is 'transparent' just so it doesn't match 'light' or 'dark'.
92 // The default for Jetpack's color scheme is still defined above as 'light'.
93
94 if ( false !== stripos( $theme_color_scheme, 'light' ) ) {
95 $this->default_color_scheme = 'light';
96 } elseif ( false !== stripos( $theme_color_scheme, 'dark' ) ) {
97 $this->default_color_scheme = 'dark';
98 }
99 }
100
101 /** Private Methods *******************************************************/
102
103 /**
104 * Set any global variables or class variables
105 *
106 * This is primarily defining the comment form sources.
107 *
108 * @since 1.4
109 */
110 protected function setup_globals() {
111 parent::setup_globals();
112
113 // Sources.
114 $this->id_sources = array(
115 'guest',
116 'jetpack',
117 'wordpress',
118 'facebook',
119 );
120 }
121
122 /**
123 * Setup actions for methods in this class
124 *
125 * @since 1.4
126 */
127 protected function setup_actions() {
128 parent::setup_actions();
129
130 // Selfishly remove everything from the existing comment form.
131 remove_all_actions( 'comment_form_before' );
132
133 // Selfishly add only our actions back to the comment form.
134 add_action( 'comment_form_before', array( $this, 'comment_form_before' ) );
135 add_action( 'comment_form_after', array( $this, 'comment_form_after' ), 1 ); // Set very early since we remove everything outputed before our action.
136
137 // Before a comment is posted.
138 add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ), 1 );
139
140 // After a comment is posted.
141 add_action( 'comment_post', array( $this, 'add_comment_meta' ) );
142 }
143
144 /**
145 * Setup filters for methods in this class
146 *
147 * @since 1.6.2
148 */
149 protected function setup_filters() {
150 parent::setup_filters();
151
152 add_filter( 'comment_post_redirect', array( $this, 'capture_comment_post_redirect_to_reload_parent_frame' ), 100 );
153 add_filter( 'get_avatar', array( $this, 'get_avatar' ), 10, 4 );
154 }
155
156 /**
157 * Get the comment avatar from Gravatar or Twitter/Facebook.
158 *
159 * Leaving the Twitter reference for legacy comments even though support is no longer offered.
160 *
161 * @since 1.4
162 *
163 * @param string $avatar Current avatar URL.
164 * @param string $comment Comment for the avatar.
165 * @param int $size Size of the avatar.
166 *
167 * @return string New avatar
168 */
169 public function get_avatar( $avatar, $comment, $size ) {
170 if ( ! isset( $comment->comment_post_ID ) || ! isset( $comment->comment_ID ) ) {
171 // it's not a comment - bail.
172 return $avatar;
173 }
174
175 // Detect whether it's a Facebook avatar.
176 $foreign_avatar = get_comment_meta( $comment->comment_ID, 'hc_avatar', true );
177 $foreign_avatar_hostname = wp_parse_url( $foreign_avatar, PHP_URL_HOST );
178 if ( ! $foreign_avatar_hostname ||
179 ! preg_match( '/\.?(graph\.facebook\.com|twimg\.com)$/', $foreign_avatar_hostname ) ) {
180 return $avatar;
181 }
182
183 // Return the Facebook or Twitter avatar.
184 return preg_replace( '#src=([\'"])[^\'"]+\\1#', 'src=\\1' . esc_url( set_url_scheme( $this->photon_avatar( $foreign_avatar, $size ), 'https' ) ) . '\\1', $avatar );
185 }
186
187 /**
188 * Get the site's blog token.
189 * This can be used to bypass Comments entirely if Jetpack is not properly connected.
190 *
191 * @since 11.2
192 *
193 * @return bool|object False if not properly connected. Object with the blog token if connected.
194 */
195 private function get_blog_token() {
196 $blog_token = ( new Tokens() )->get_access_token();
197 // If we have no token, bail.
198 if ( ! $blog_token || is_wp_error( $blog_token ) ) {
199 return false;
200 }
201
202 return $blog_token;
203 }
204
205 /** Output Methods ********************************************************/
206
207 /**
208 * Start capturing the core comment_form() output
209 *
210 * Comment form output will only be captured if comments are enabled - we return otherwise.
211 *
212 * @since 1.4
213 */
214 public function comment_form_before() {
215 /**
216 * Filters the setting that determines if Jetpack comments should be enabled for
217 * the current post type.
218 *
219 * @module comments
220 *
221 * @since 3.8.1
222 *
223 * @param boolean $return Should comments be enabled?
224 */
225 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type(), true ) ) {
226 return;
227 }
228
229 // If the Jetpack connection is not healthy, bail.
230 if ( ! $this->get_blog_token() ) {
231 return;
232 }
233
234 // Add some JS to the footer.
235 add_action( 'wp_footer', array( $this, 'watch_comment_parent' ), 100 );
236
237 ob_start();
238 }
239
240 /**
241 * Noop the default comment form output, get some options, and output our
242 * tricked out totally radical comment form.
243 *
244 * @since 1.4
245 */
246 public function comment_form_after() {
247 /** This filter is documented in modules/comments/comments.php */
248 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type(), true ) ) {
249 return;
250 }
251
252 $blog_token = $this->get_blog_token();
253 // If the Jetpack connection is not healthy, bail.
254 if ( ! $blog_token ) {
255 return;
256 }
257
258 // Throw it all out and drop in our replacement.
259 ob_end_clean();
260
261 // If users are required to be logged in, and they're not, then we don't need to do anything else.
262 if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
263 /**
264 * Changes the log in to comment prompt.
265 *
266 * @module comments
267 *
268 * @since 1.4.0
269 *
270 * @param string $var Default is "You must log in to post a comment."
271 */
272 echo '<p class="must-log-in">' . wp_kses_post(
273 sprintf(
274 apply_filters(
275 'jetpack_must_log_in_to_comment',
276 /* translators: %s is the wp-login URL for the site */
277 __( 'You must <a href="%s">log in</a> to post a comment.', 'jetpack' )
278 ),
279 wp_login_url( get_permalink() . '#respond' )
280 )
281 ) . '</p>';
282 return;
283 }
284
285 if ( in_array( 'subscriptions', Jetpack::get_active_modules(), true ) ) {
286 $stb_enabled = get_option( 'stb_enabled', 1 );
287 $stb_enabled = empty( $stb_enabled ) ? 0 : 1;
288
289 $stc_enabled = get_option( 'stc_enabled', 1 );
290 $stc_enabled = empty( $stc_enabled ) ? 0 : 1;
291 } else {
292 $stb_enabled = 0;
293 $stc_enabled = 0;
294 }
295
296 $params = array(
297 'blogid' => Jetpack_Options::get_option( 'id' ),
298 'postid' => get_the_ID(),
299 'comment_registration' => ( get_option( 'comment_registration' ) ? '1' : '0' ), // Need to explicitly send a '1' or a '0' for these.
300 'require_name_email' => ( get_option( 'require_name_email' ) ? '1' : '0' ),
301 'stc_enabled' => $stc_enabled,
302 'stb_enabled' => $stb_enabled,
303 'show_avatars' => ( get_option( 'show_avatars' ) ? '1' : '0' ),
304 'avatar_default' => get_option( 'avatar_default' ),
305 'greeting' => get_option( 'highlander_comment_form_prompt', __( 'Leave a Reply', 'jetpack' ) ),
306 'jetpack_comments_nonce' => wp_create_nonce( 'jetpack_comments_nonce-' . get_the_ID() ),
307 /**
308 * Changes the comment form prompt.
309 *
310 * @module comments
311 *
312 * @since 2.3.0
313 *
314 * @param string $var Default is "Leave a Reply to %s."
315 */
316 'greeting_reply' => apply_filters(
317 'jetpack_comment_form_prompt_reply',
318 /* translators: %s is the displayed username of the post (or comment) author */
319 __( 'Leave a Reply to %s', 'jetpack' )
320 ),
321 'color_scheme' => get_option( 'jetpack_comment_form_color_scheme', $this->default_color_scheme ),
322 'lang' => get_locale(),
323 'jetpack_version' => JETPACK__VERSION,
324 );
325
326 // Extra parameters for logged in user.
327 if ( is_user_logged_in() ) {
328 $current_user = wp_get_current_user();
329 $params['hc_post_as'] = 'jetpack';
330 $params['hc_userid'] = $current_user->ID;
331 $params['hc_username'] = $current_user->display_name;
332 $params['hc_userurl'] = $current_user->user_url;
333 $params['hc_useremail'] = md5( strtolower( trim( $current_user->user_email ) ) );
334 if ( current_user_can( 'unfiltered_html' ) ) {
335 $params['_wp_unfiltered_html_comment'] = wp_create_nonce( 'unfiltered-html-comment_' . get_the_ID() );
336 }
337 } else {
338 $commenter = wp_get_current_commenter();
339 $params['show_cookie_consent'] = (int) has_action( 'set_comment_cookies', 'wp_set_comment_cookies' );
340 $params['has_cookie_consent'] = (int) ! empty( $commenter['comment_author_email'] );
341 }
342
343 list( $token_key ) = explode( '.', $blog_token->secret, 2 );
344 // Prophylactic check: anything else should never happen.
345 if ( $token_key && $token_key !== $blog_token->secret ) {
346 // Is the token a Special Token (@see class.tokens.php)?
347 if ( preg_match( '/^;.\d+;\d+;$/', $token_key, $matches ) ) {
348 // The token key for a Special Token is public.
349 $params['token_key'] = $token_key;
350 } else {
351 /*
352 * The token key for a Normal Token is public but
353 * looks like sensitive data. Since there can only be
354 * one Normal Token per site, avoid concern by
355 * sending the magic "use the Normal Token" token key.
356 */
357 $params['token_key'] = Tokens::MAGIC_NORMAL_TOKEN_KEY;
358 }
359 }
360
361 $signature = self::sign_remote_comment_parameters( $params, $blog_token->secret );
362 if ( is_wp_error( $signature ) ) {
363 $signature = 'error';
364 }
365
366 $params['sig'] = $signature;
367 $url_origin = 'https://jetpack.wordpress.com';
368 $url = "{$url_origin}/jetpack-comment/?" . http_build_query( $params );
369 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sniff misses the esc_url_raw.
370 $url = "{$url}#parent=" . rawurlencode( esc_url_raw( set_url_scheme( 'http://' . ( isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : '' ) . ( isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '' ) ) ) );
371 $this->signed_url = $url;
372 $height = $params['comment_registration'] || is_user_logged_in() ? '315' : '430'; // Iframe can be shorter if we're not allowing guest commenting.
373 $transparent = ( 'transparent' === $params['color_scheme'] ) ? 'true' : 'false';
374
375 if ( isset( $_GET['replytocom'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
376 $url .= '&replytocom=' . (int) $_GET['replytocom']; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
377 }
378
379 /**
380 * Filter whether the comment title can be displayed.
381 *
382 * @module comments
383 *
384 * @since 4.7.0
385 *
386 * @param bool $show Can the comment be displayed? Default to true.
387 */
388 $show_greeting = apply_filters( 'jetpack_comment_form_display_greeting', true );
389
390 /**
391 * Filter the comment title tag.
392 *
393 * @module comments
394 * @since 12.4
395 *
396 * @param string $comment_reply_title_tag The comment title tag. Default to h3.
397 */
398 $comment_reply_title_tag = apply_filters( 'jetpack_comment_reply_title_tag', 'h3' );
399
400 // The actual iframe (loads comment form from Jetpack server).
401
402 $is_amp = class_exists( Jetpack_AMP_Support::class ) && Jetpack_AMP_Support::is_amp_request();
403 ?>
404
405 <div id="respond" class="comment-respond">
406 <?php
407 if ( true === $show_greeting ) :
408 printf(
409 '<%1$s id="reply-title" class="comment-reply-title">',
410 esc_html( $comment_reply_title_tag )
411 );
412
413 comment_form_title(
414 esc_html( $params['greeting'] ),
415 esc_html( $params['greeting_reply'] )
416 );
417 echo '<small>';
418 cancel_comment_reply_link( esc_html__( 'Cancel reply', 'jetpack' ) );
419 echo '</small>';
420
421 printf(
422 '</%1$s>',
423 esc_html( $comment_reply_title_tag )
424 );
425 endif;
426 ?>
427 <form id="commentform" class="comment-form">
428 <iframe
429 title="<?php esc_attr_e( 'Comment Form', 'jetpack' ); ?>"
430 src="<?php echo esc_url( $url ); ?>"
431 <?php if ( $is_amp ) : ?>
432 resizable
433 layout="fixed-height"
434 height="<?php echo esc_attr( $height ); ?>"
435 <?php else : ?>
436 name="jetpack_remote_comment"
437 style="width:100%; height: <?php echo esc_attr( $height ); ?>px; border:0;"
438 <?php endif; ?>
439 class="jetpack_remote_comment"
440 id="jetpack_remote_comment"
441 sandbox="allow-same-origin allow-top-navigation allow-scripts allow-forms allow-popups"
442 >
443 <?php if ( $is_amp ) : ?>
444 <button overflow><?php esc_html_e( 'Show more', 'jetpack' ); ?></button>
445 <?php endif; ?>
446 </iframe>
447 <?php if ( ! $is_amp ) : ?>
448 <!--[if !IE]><!-->
449 <script>
450 document.addEventListener('DOMContentLoaded', function () {
451 var commentForms = document.getElementsByClassName('jetpack_remote_comment');
452 for (var i = 0; i < commentForms.length; i++) {
453 commentForms[i].allowTransparency = <?php echo esc_html( $transparent ); ?>;
454 commentForms[i].scrolling = 'no';
455 }
456 });
457 </script>
458 <!--<![endif]-->
459 <?php endif; ?>
460 </form>
461 </div>
462
463 <?php // Below is required for comment reply JS to work. ?>
464
465 <input type="hidden" name="comment_parent" id="comment_parent" value="" />
466
467 <?php
468 }
469
470 /**
471 * Add some JS to wp_footer to watch for hierarchical reply parent change
472 *
473 * If AMP is enabled, we don't make any changes.
474 *
475 * @since 1.4
476 */
477 public function watch_comment_parent() {
478 if ( class_exists( Jetpack_AMP_Support::class ) && Jetpack_AMP_Support::is_amp_request() ) {
479 // @todo Implement AMP support.
480 return;
481 }
482
483 $url_origin = 'https://jetpack.wordpress.com';
484 ?>
485
486 <!--[if IE]>
487 <script type="text/javascript">
488 if ( 0 === window.location.hash.indexOf( '#comment-' ) ) {
489 // window.location.reload() doesn't respect the Hash in IE
490 window.location.hash = window.location.hash;
491 }
492 </script>
493 <![endif]-->
494 <script type="text/javascript">
495 (function () {
496 var comm_par_el = document.getElementById( 'comment_parent' ),
497 comm_par = ( comm_par_el && comm_par_el.value ) ? comm_par_el.value : '',
498 frame = document.getElementById( 'jetpack_remote_comment' ),
499 tellFrameNewParent;
500
501 tellFrameNewParent = function () {
502 if ( comm_par ) {
503 frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>" + '&replytocom=' + parseInt( comm_par, 10 ).toString();
504 } else {
505 frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>";
506 }
507 };
508
509 <?php if ( get_option( 'thread_comments' ) && get_option( 'thread_comments_depth' ) ) : ?>
510
511 if ( 'undefined' !== typeof addComment ) {
512 addComment._Jetpack_moveForm = addComment.moveForm;
513
514 addComment.moveForm = function ( commId, parentId, respondId, postId ) {
515 var returnValue = addComment._Jetpack_moveForm( commId, parentId, respondId, postId ),
516 cancelClick, cancel;
517
518 if ( false === returnValue ) {
519 cancel = document.getElementById( 'cancel-comment-reply-link' );
520 cancelClick = cancel.onclick;
521 cancel.onclick = function () {
522 var cancelReturn = cancelClick.call( this );
523 if ( false !== cancelReturn ) {
524 return cancelReturn;
525 }
526
527 if ( ! comm_par ) {
528 return cancelReturn;
529 }
530
531 comm_par = 0;
532
533 tellFrameNewParent();
534
535 return cancelReturn;
536 };
537 }
538
539 if ( comm_par == parentId ) {
540 return returnValue;
541 }
542
543 comm_par = parentId;
544
545 tellFrameNewParent();
546
547 return returnValue;
548 };
549 }
550
551 <?php endif; ?>
552
553 // Do the post message bit after the dom has loaded.
554 document.addEventListener( 'DOMContentLoaded', function () {
555 var iframe_url = <?php echo wp_json_encode( esc_url_raw( $url_origin ) ); ?>;
556 if ( window.postMessage ) {
557 if ( document.addEventListener ) {
558 window.addEventListener( 'message', function ( event ) {
559 var origin = event.origin.replace( /^http:\/\//i, 'https://' );
560 if ( iframe_url.replace( /^http:\/\//i, 'https://' ) !== origin ) {
561 return;
562 }
563 frame.style.height = event.data + 'px';
564 });
565 } else if ( document.attachEvent ) {
566 window.attachEvent( 'message', function ( event ) {
567 var origin = event.origin.replace( /^http:\/\//i, 'https://' );
568 if ( iframe_url.replace( /^http:\/\//i, 'https://' ) !== origin ) {
569 return;
570 }
571 frame.style.height = event.data + 'px';
572 });
573 }
574 }
575 })
576
577 })();
578 </script>
579
580 <?php
581 }
582
583 /**
584 * Verify the hash included in remote comments.
585 *
586 * If the Jetpack token is missing we return nothing,
587 * and if the token is unknown or invalid, or comments not allowed, an error is returned.
588 *
589 * @since 1.4
590 */
591 public function pre_comment_on_post() {
592 $post_array = stripslashes_deep( $_POST );
593
594 // Bail if missing the Jetpack token.
595 if ( ! isset( $post_array['sig'] ) || ! isset( $post_array['token_key'] ) ) {
596 unset( $_POST['hc_post_as'] );
597
598 return;
599 }
600
601 if ( empty( $post_array['jetpack_comments_nonce'] ) || ! wp_verify_nonce( $post_array['jetpack_comments_nonce'], "jetpack_comments_nonce-{$post_array['comment_post_ID']}" ) ) {
602 wp_die( esc_html__( 'Nonce verification failed.', 'jetpack' ), 400 );
603 }
604
605 if ( false !== strpos( $post_array['hc_avatar'], '.gravatar.com' ) ) {
606 $post_array['hc_avatar'] = htmlentities( $post_array['hc_avatar'], ENT_COMPAT );
607 }
608
609 $blog_token = ( new Tokens() )->get_access_token( false, $post_array['token_key'] );
610 if ( ! $blog_token || is_wp_error( $blog_token ) ) {
611 wp_die( esc_html__( 'Unknown security token.', 'jetpack' ), 400 );
612 }
613 $check = self::sign_remote_comment_parameters( $post_array, $blog_token->secret );
614 if ( is_wp_error( $check ) ) {
615 wp_die( esc_html( $check ) );
616 }
617
618 // Bail if token is expired or not valid.
619 if ( ! hash_equals( $check, $post_array['sig'] ) ) {
620 wp_die( esc_html__( 'Invalid security token.', 'jetpack' ), 400 );
621 }
622
623 /** This filter is documented in modules/comments/comments.php */
624 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type( $post_array['comment_post_ID'] ), true ) ) {
625 // In case the comment POST is legit, but the comments are
626 // now disabled, we don't allow the comment.
627
628 wp_die( esc_html__( 'Comments are not allowed.', 'jetpack' ), 403 );
629 }
630 }
631
632 /** Capabilities **********************************************************/
633
634 /**
635 * Add some additional comment meta after comment is saved about what
636 * service the comment is from, the avatar, user_id, etc...
637 *
638 * @since 1.4
639 *
640 * @param int $comment_id The comment ID.
641 */
642 public function add_comment_meta( $comment_id ) {
643 $comment_meta = array();
644
645 // phpcs:disable WordPress.Security.NonceVerification.Missing
646 switch ( $this->is_highlander_comment_post() ) {
647 case 'facebook':
648 $comment_meta['hc_post_as'] = 'facebook';
649 $comment_meta['hc_avatar'] = isset( $_POST['hc_avatar'] ) ? filter_var( wp_unslash( $_POST['hc_avatar'] ) ) : null;
650 $comment_meta['hc_foreign_user_id'] = isset( $_POST['hc_userid'] ) ? filter_var( wp_unslash( $_POST['hc_userid'] ) ) : null;
651 break;
652
653 // phpcs:ignore WordPress.WP.CapitalPDangit
654 case 'wordpress':
655 // phpcs:ignore WordPress.WP.CapitalPDangit
656 $comment_meta['hc_post_as'] = 'wordpress';
657 $comment_meta['hc_avatar'] = isset( $_POST['hc_avatar'] ) ? filter_var( wp_unslash( $_POST['hc_avatar'] ) ) : null;
658 $comment_meta['hc_foreign_user_id'] = isset( $_POST['hc_userid'] ) ? filter_var( wp_unslash( $_POST['hc_userid'] ) ) : null;
659 $comment_meta['hc_wpcom_id_sig'] = isset( $_POST['hc_wpcom_id_sig'] ) ? filter_var( wp_unslash( $_POST['hc_wpcom_id_sig'] ) ) : null; // since 1.9.
660 break;
661
662 case 'jetpack':
663 $comment_meta['hc_post_as'] = 'jetpack';
664 $comment_meta['hc_avatar'] = isset( $_POST['hc_avatar'] ) ? filter_var( wp_unslash( $_POST['hc_avatar'] ) ) : null;
665 $comment_meta['hc_foreign_user_id'] = isset( $_POST['hc_userid'] ) ? filter_var( wp_unslash( $_POST['hc_userid'] ) ) : null;
666 break;
667
668 }
669 // phpcs:enable WordPress.Security.NonceVerification.Missing
670
671 // Bail if no extra comment meta.
672 if ( empty( $comment_meta ) ) {
673 return;
674 }
675
676 // Loop through extra meta and add values.
677 foreach ( $comment_meta as $key => $value ) {
678 add_comment_meta( $comment_id, $key, $value, true );
679 }
680 }
681
682 /**
683 * POST the submitted comment to the iframe
684 *
685 * @param string $url The comment URL origin.
686 */
687 public function capture_comment_post_redirect_to_reload_parent_frame( $url ) {
688 if ( ! isset( $_GET['for'] ) || 'jetpack' !== $_GET['for'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
689 return $url;
690 }
691 ?>
692 <!DOCTYPE html>
693 <html <?php language_attributes(); ?>>
694 <!--<![endif]-->
695 <head>
696 <meta charset="<?php bloginfo( 'charset' ); ?>" />
697 <title>
698 <?php
699 wp_kses_post(
700 printf(
701 /* translators: %s is replaced by an ellipsis */
702 __( 'Submitting Comment%s', 'jetpack' ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
703 '&hellip;'
704 )
705 );
706 ?>
707 </title>
708 <style type="text/css">
709 body {
710 display: table;
711 width: 100%;
712 height: 60%;
713 position: absolute;
714 top: 0;
715 left: 0;
716 overflow: hidden;
717 color: #333;
718 }
719
720 h1 {
721 text-align: center;
722 margin: 0;
723 padding: 0;
724 display: table-cell;
725 vertical-align: middle;
726 font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
727 font-weight: normal;
728 }
729
730 .hidden {
731 opacity: 0;
732 }
733
734 h1 span {
735 -moz-transition-property: opacity;
736 -moz-transition-duration: 1s;
737 -moz-transition-timing-function: ease-in-out;
738
739 -webkit-transition-property: opacity;
740 -webkit-transition-duration: 1s;
741 -webbit-transition-timing-function: ease-in-out;
742
743 -o-transition-property: opacity;
744 -o-transition-duration: 1s;
745 -o-transition-timing-function: ease-in-out;
746
747 -ms-transition-property: opacity;
748 -ms-transition-duration: 1s;
749 -ms-transition-timing-function: ease-in-out;
750
751 transition-property: opacity;
752 transition-duration: 1s;
753 transition-timing-function: ease-in-out;
754 }
755 </style>
756 </head>
757 <body>
758 <h1>
759 <?php
760 wp_kses_post(
761 printf(
762 /* translators: %s is replaced by HTML markup to include an ellipsis */
763 __( 'Submitting Comment%s', 'jetpack' ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
764 '<span id="ellipsis" class="hidden">&hellip;</span>'
765 )
766 );
767 ?>
768 </h1>
769 <script type="text/javascript">
770 try {
771 window.parent.location = <?php echo wp_json_encode( $url ); ?>;
772 window.parent.location.reload(true);
773 } catch (e) {
774 window.location = <?php echo wp_json_encode( $url ); ?>;
775 window.location.reload(true);
776 }
777 ellipsis = document.getElementById('ellipsis');
778
779 function toggleEllipsis() {
780 ellipsis.className = ellipsis.className ? '' : 'hidden';
781 }
782
783 setInterval(toggleEllipsis, 1200);
784 </script>
785 </body>
786 </html>
787 <?php
788 exit;
789 }
790 }
791
792 Jetpack_Comments::init();
793