PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.5.2
Jetpack – WP Security, Backup, Speed, & Growth v12.5.2
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 3 years ago base.php 3 years ago comments.php 3 years ago
comments.php
799 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 * @version 1.4
16 * @since 1.4
17 */
18 class Jetpack_Comments extends Highlander_Comments_Base {
19
20 /** Variables *************************************************************/
21
22 /**
23 * Possible comment form sources - empty array as default
24 *
25 * @var array
26 */
27 public $id_sources = array();
28
29 /**
30 * Remote comment URL - empty string as default
31 *
32 * @var string
33 */
34 public $signed_url = '';
35
36 /**
37 * The default comment form color scheme - default is light
38 *
39 * @var string
40 * @see ::set_default_color_theme_based_on_theme_settings()
41 */
42 public $default_color_scheme = 'light';
43
44 /** Methods ***************************************************************/
45
46 /**
47 * Initialize class
48 */
49 public static function init() {
50 static $instance = false;
51
52 if ( ! $instance ) {
53 $instance = new Jetpack_Comments();
54 }
55
56 return $instance;
57 }
58
59 /**
60 * Main constructor for Comments
61 *
62 * @since JetpackComments (1.4)
63 */
64 public function __construct() {
65 parent::__construct();
66
67 // Comments is loaded.
68
69 /**
70 * Fires after the Jetpack_Comments object has been instantiated
71 *
72 * @module comments
73 *
74 * @since 1.4.0
75 *
76 * @param array $jetpack_comments_loaded First element in array of type Jetpack_Comments
77 */
78 do_action_ref_array( 'jetpack_comments_loaded', array( $this ) );
79 add_action( 'after_setup_theme', array( $this, 'set_default_color_theme_based_on_theme_settings' ), 100 );
80 }
81
82 /**
83 * Set the default comments color theme based on theme settings
84 */
85 public function set_default_color_theme_based_on_theme_settings() {
86 if ( function_exists( 'twentyeleven_get_theme_options' ) ) {
87 $theme_options = twentyeleven_get_theme_options();
88 $theme_color_scheme = isset( $theme_options['color_scheme'] ) ? $theme_options['color_scheme'] : 'transparent';
89 } else {
90 $theme_color_scheme = get_theme_mod( 'color_scheme', 'transparent' );
91 }
92 // Default for $theme_color_scheme is 'transparent' just so it doesn't match 'light' or 'dark'.
93 // The default for Jetpack's color scheme is still defined above as 'light'.
94
95 if ( false !== stripos( $theme_color_scheme, 'light' ) ) {
96 $this->default_color_scheme = 'light';
97 } elseif ( false !== stripos( $theme_color_scheme, 'dark' ) ) {
98 $this->default_color_scheme = 'dark';
99 }
100 }
101
102 /** Private Methods *******************************************************/
103
104 /**
105 * Set any global variables or class variables
106 *
107 * This is primarily defining the comment form sources.
108 *
109 * @since JetpackComments (1.4)
110 */
111 protected function setup_globals() {
112 parent::setup_globals();
113
114 // Sources.
115 $this->id_sources = array(
116 'guest',
117 'jetpack',
118 'wordpress',
119 'twitter',
120 'facebook',
121 );
122 }
123
124 /**
125 * Setup actions for methods in this class
126 *
127 * @since JetpackComments (1.4)
128 */
129 protected function setup_actions() {
130 parent::setup_actions();
131
132 // Selfishly remove everything from the existing comment form.
133 remove_all_actions( 'comment_form_before' );
134
135 // Selfishly add only our actions back to the comment form.
136 add_action( 'comment_form_before', array( $this, 'comment_form_before' ) );
137 add_action( 'comment_form_after', array( $this, 'comment_form_after' ), 1 ); // Set very early since we remove everything outputed before our action.
138
139 // Before a comment is posted.
140 add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ), 1 );
141
142 // After a comment is posted.
143 add_action( 'comment_post', array( $this, 'add_comment_meta' ) );
144 }
145
146 /**
147 * Setup filters for methods in this class
148 *
149 * @since 1.6.2
150 */
151 protected function setup_filters() {
152 parent::setup_filters();
153
154 add_filter( 'comment_post_redirect', array( $this, 'capture_comment_post_redirect_to_reload_parent_frame' ), 100 );
155 add_filter( 'get_avatar', array( $this, 'get_avatar' ), 10, 4 );
156 }
157
158 /**
159 * Get the comment avatar from Gravatar, Twitter, or Facebook
160 *
161 * @since JetpackComments (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 or Twitter 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 JetpackComments (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 JetpackComments (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 JetpackComments (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 JetpackComments (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 JetpackComments (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 case 'twitter':
654 $comment_meta['hc_post_as'] = 'twitter';
655 $comment_meta['hc_avatar'] = isset( $_POST['hc_avatar'] ) ? filter_var( wp_unslash( $_POST['hc_avatar'] ) ) : null;
656 $comment_meta['hc_foreign_user_id'] = isset( $_POST['hc_userid'] ) ? filter_var( wp_unslash( $_POST['hc_userid'] ) ) : null;
657 break;
658
659 // phpcs:ignore WordPress.WP.CapitalPDangit
660 case 'wordpress':
661 // phpcs:ignore WordPress.WP.CapitalPDangit
662 $comment_meta['hc_post_as'] = 'wordpress';
663 $comment_meta['hc_avatar'] = isset( $_POST['hc_avatar'] ) ? filter_var( wp_unslash( $_POST['hc_avatar'] ) ) : null;
664 $comment_meta['hc_foreign_user_id'] = isset( $_POST['hc_userid'] ) ? filter_var( wp_unslash( $_POST['hc_userid'] ) ) : null;
665 $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.
666 break;
667
668 case 'jetpack':
669 $comment_meta['hc_post_as'] = 'jetpack';
670 $comment_meta['hc_avatar'] = isset( $_POST['hc_avatar'] ) ? filter_var( wp_unslash( $_POST['hc_avatar'] ) ) : null;
671 $comment_meta['hc_foreign_user_id'] = isset( $_POST['hc_userid'] ) ? filter_var( wp_unslash( $_POST['hc_userid'] ) ) : null;
672 break;
673
674 }
675 // phpcs:enable WordPress.Security.NonceVerification.Missing
676
677 // Bail if no extra comment meta.
678 if ( empty( $comment_meta ) ) {
679 return;
680 }
681
682 // Loop through extra meta and add values.
683 foreach ( $comment_meta as $key => $value ) {
684 add_comment_meta( $comment_id, $key, $value, true );
685 }
686 }
687
688 /**
689 * POST the submitted comment to the iframe
690 *
691 * @param string $url The comment URL origin.
692 */
693 public function capture_comment_post_redirect_to_reload_parent_frame( $url ) {
694 if ( ! isset( $_GET['for'] ) || 'jetpack' !== $_GET['for'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
695 return $url;
696 }
697 ?>
698 <!DOCTYPE html>
699 <html <?php language_attributes(); ?>>
700 <!--<![endif]-->
701 <head>
702 <meta charset="<?php bloginfo( 'charset' ); ?>" />
703 <title>
704 <?php
705 wp_kses_post(
706 printf(
707 /* translators: %s is replaced by an ellipsis */
708 __( 'Submitting Comment%s', 'jetpack' ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
709 '&hellip;'
710 )
711 );
712 ?>
713 </title>
714 <style type="text/css">
715 body {
716 display: table;
717 width: 100%;
718 height: 60%;
719 position: absolute;
720 top: 0;
721 left: 0;
722 overflow: hidden;
723 color: #333;
724 }
725
726 h1 {
727 text-align: center;
728 margin: 0;
729 padding: 0;
730 display: table-cell;
731 vertical-align: middle;
732 font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
733 font-weight: normal;
734 }
735
736 .hidden {
737 opacity: 0;
738 }
739
740 h1 span {
741 -moz-transition-property: opacity;
742 -moz-transition-duration: 1s;
743 -moz-transition-timing-function: ease-in-out;
744
745 -webkit-transition-property: opacity;
746 -webkit-transition-duration: 1s;
747 -webbit-transition-timing-function: ease-in-out;
748
749 -o-transition-property: opacity;
750 -o-transition-duration: 1s;
751 -o-transition-timing-function: ease-in-out;
752
753 -ms-transition-property: opacity;
754 -ms-transition-duration: 1s;
755 -ms-transition-timing-function: ease-in-out;
756
757 transition-property: opacity;
758 transition-duration: 1s;
759 transition-timing-function: ease-in-out;
760 }
761 </style>
762 </head>
763 <body>
764 <h1>
765 <?php
766 wp_kses_post(
767 printf(
768 /* translators: %s is replaced by HTML markup to include an ellipsis */
769 __( 'Submitting Comment%s', 'jetpack' ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
770 '<span id="ellipsis" class="hidden">&hellip;</span>'
771 )
772 );
773 ?>
774 </h1>
775 <script type="text/javascript">
776 try {
777 window.parent.location = <?php echo wp_json_encode( $url ); ?>;
778 window.parent.location.reload(true);
779 } catch (e) {
780 window.location = <?php echo wp_json_encode( $url ); ?>;
781 window.location.reload(true);
782 }
783 ellipsis = document.getElementById('ellipsis');
784
785 function toggleEllipsis() {
786 ellipsis.className = ellipsis.className ? '' : 'hidden';
787 }
788
789 setInterval(toggleEllipsis, 1200);
790 </script>
791 </body>
792 </html>
793 <?php
794 exit;
795 }
796 }
797
798 Jetpack_Comments::init();
799