PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 6.4
Jetpack – WP Security, Backup, Speed, & Growth v6.4
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 All 500 releases
jetpack / modules / comments / comments.php
comments.php
625 lines 19.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require dirname( __FILE__ ) . '/base.php';
4
5 /**
6 * Main Comments class
7 *
8 * @package JetpackComments
9 * @version 1.4
10 * @since 1.4
11 */
12 class Jetpack_Comments extends Highlander_Comments_Base {
13
14 /** Variables *************************************************************/
15
16 /**
17 * Possible comment form sources
18 * @var array
19 */
20 public $id_sources = array();
21
22 /**
23 * URL
24 * @var string
25 */
26 public $signed_url = '';
27
28 /**
29 * The default comment form color scheme
30 * @var string
31 * @see ::set_default_color_theme_based_on_theme_settings()
32 */
33 public $default_color_scheme = 'light';
34
35 /** Methods ***************************************************************/
36
37 public static function init() {
38 static $instance = false;
39
40 if ( ! $instance ) {
41 $instance = new Jetpack_Comments;
42 }
43
44 return $instance;
45 }
46
47 /**
48 * Main constructor for Comments
49 *
50 * @since JetpackComments (1.4)
51 */
52 public function __construct() {
53 parent::__construct();
54
55 // Comments is loaded
56
57 /**
58 * Fires after the Jetpack_Comments object has been instantiated
59 *
60 * @module comments
61 *
62 * @since 1.4.0
63 *
64 * @param array $jetpack_comments_loaded First element in array of type Jetpack_Comments
65 **/
66 do_action_ref_array( 'jetpack_comments_loaded', array( $this ) );
67 add_action( 'after_setup_theme', array( $this, 'set_default_color_theme_based_on_theme_settings' ), 100 );
68 }
69
70 public function set_default_color_theme_based_on_theme_settings() {
71 if ( function_exists( 'twentyeleven_get_theme_options' ) ) {
72 $theme_options = twentyeleven_get_theme_options();
73 $theme_color_scheme = isset( $theme_options['color_scheme'] ) ? $theme_options['color_scheme'] : 'transparent';
74 } else {
75 $theme_color_scheme = get_theme_mod( 'color_scheme', 'transparent' );
76 }
77 // Default for $theme_color_scheme is 'transparent' just so it doesn't match 'light' or 'dark'
78 // The default for Jetpack's color scheme is still defined above as 'light'
79
80 if ( false !== stripos( $theme_color_scheme, 'light' ) ) {
81 $this->default_color_scheme = 'light';
82 } elseif ( false !== stripos( $theme_color_scheme, 'dark' ) ) {
83 $this->default_color_scheme = 'dark';
84 }
85 }
86
87 /** Private Methods *******************************************************/
88
89 /**
90 * Set any global variables or class variables
91 * @since JetpackComments (1.4)
92 */
93 protected function setup_globals() {
94 parent::setup_globals();
95
96 // Sources
97 $this->id_sources = array(
98 'guest',
99 'jetpack',
100 'wordpress',
101 'twitter',
102 'facebook'
103 );
104 }
105
106 /**
107 * Setup actions for methods in this class
108 * @since JetpackComments (1.4)
109 */
110 protected function setup_actions() {
111 parent::setup_actions();
112
113 // Selfishly remove everything from the existing comment form
114 remove_all_actions( 'comment_form_before' );
115
116 // Selfishly add only our actions back to the comment form
117 add_action( 'comment_form_before', array( $this, 'comment_form_before' ) );
118 add_action( 'comment_form_after', array( $this, 'comment_form_after' ), 1 ); // Set very early since we remove everything outputed before our action.
119
120 // Before a comment is posted
121 add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ), 1 );
122
123 // After a comment is posted
124 add_action( 'comment_post', array( $this, 'add_comment_meta' ) );
125 }
126
127 /**
128 * Setup filters for methods in this class
129 * @since 1.6.2
130 */
131 protected function setup_filters() {
132 parent::setup_filters();
133
134 add_filter( 'comment_post_redirect', array( $this, 'capture_comment_post_redirect_to_reload_parent_frame' ), 100 );
135 add_filter( 'get_avatar', array( $this, 'get_avatar' ), 10, 4 );
136 }
137
138 /**
139 * Get the comment avatar from Gravatar, Twitter, or Facebook
140 *
141 * @since JetpackComments (1.4)
142 *
143 * @param string $avatar Current avatar URL
144 * @param string $comment Comment for the avatar
145 * @param int $size Size of the avatar
146 * @param string $default Not used
147 *
148 * @return string New avatar
149 */
150 public function get_avatar( $avatar, $comment, $size, $default ) {
151 if ( ! isset( $comment->comment_post_ID ) || ! isset( $comment->comment_ID ) ) {
152 // it's not a comment - bail
153 return $avatar;
154 }
155
156 // Detect whether it's a Facebook or Twitter avatar
157 $foreign_avatar = get_comment_meta( $comment->comment_ID, 'hc_avatar', true );
158 $foreign_avatar_hostname = parse_url( $foreign_avatar, PHP_URL_HOST );
159 if ( ! $foreign_avatar_hostname ||
160 ! preg_match( '/\.?(graph\.facebook\.com|twimg\.com)$/', $foreign_avatar_hostname ) ) {
161 return $avatar;
162 }
163
164 // Return the FB or Twitter avatar
165 return preg_replace( '#src=([\'"])[^\'"]+\\1#', 'src=\\1' . esc_url( set_url_scheme( $this->photon_avatar( $foreign_avatar, $size ), 'https' ) ) . '\\1', $avatar );
166 }
167
168 /** Output Methods ********************************************************/
169
170 /**
171 * Start capturing the core comment_form() output
172 * @since JetpackComments (1.4)
173 */
174 public function comment_form_before() {
175 /**
176 * Filters the setting that determines if Jetpagk comments should be enabled for
177 * the current post type.
178 *
179 * @module comments
180 *
181 * @since 3.8.1
182 *
183 * @param boolean $return Should comments be enabled?
184 */
185 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type(), true ) ) {
186 return;
187 }
188
189 // Add some JS to the footer
190 add_action( 'wp_footer', array( $this, 'watch_comment_parent' ), 100 );
191
192 ob_start();
193 }
194
195 /**
196 * Noop the default comment form output, get some options, and output our
197 * tricked out totally radical comment form.
198 *
199 * @since JetpackComments (1.4)
200 */
201 public function comment_form_after() {
202 /** This filter is documented in modules/comments/comments.php */
203 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type(), true ) ) {
204 return;
205 }
206
207 // Throw it all out and drop in our replacement
208 ob_end_clean();
209
210 // If users are required to be logged in, and they're not, then we don't need to do anything else
211 if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
212 /**
213 * Changes the log in to comment prompt.
214 *
215 * @module comments
216 *
217 * @since 1.4.0
218 *
219 * @param string $var Default is "You must log in to post a comment."
220 */
221 echo '<p class="must-log-in">' . sprintf( apply_filters( 'jetpack_must_log_in_to_comment', __( 'You must <a href="%s">log in</a> to post a comment.', 'jetpack' ) ), wp_login_url( get_permalink() . '#respond' ) ) . '</p>';
222
223 return;
224 }
225
226 if ( in_array( 'subscriptions', Jetpack::get_active_modules() ) ) {
227 $stb_enabled = get_option( 'stb_enabled', 1 );
228 $stb_enabled = empty( $stb_enabled ) ? 0 : 1;
229
230 $stc_enabled = get_option( 'stc_enabled', 1 );
231 $stc_enabled = empty( $stc_enabled ) ? 0 : 1;
232 } else {
233 $stb_enabled = 0;
234 $stc_enabled = 0;
235 }
236
237 $params = array(
238 'blogid' => Jetpack_Options::get_option( 'id' ),
239 'postid' => get_the_ID(),
240 'comment_registration' => ( get_option( 'comment_registration' ) ? '1' : '0' ), // Need to explicitly send a '1' or a '0' for these
241 'require_name_email' => ( get_option( 'require_name_email' ) ? '1' : '0' ),
242 'stc_enabled' => $stc_enabled,
243 'stb_enabled' => $stb_enabled,
244 'show_avatars' => ( get_option( 'show_avatars' ) ? '1' : '0' ),
245 'avatar_default' => get_option( 'avatar_default' ),
246 'greeting' => get_option( 'highlander_comment_form_prompt', __( 'Leave a Reply', 'jetpack' ) ),
247 /**
248 * Changes the comment form prompt.
249 *
250 * @module comments
251 *
252 * @since 2.3.0
253 *
254 * @param string $var Default is "Leave a Reply to %s."
255 */
256 'greeting_reply' => apply_filters( 'jetpack_comment_form_prompt_reply', __( 'Leave a Reply to %s', 'jetpack' ) ),
257 'color_scheme' => get_option( 'jetpack_comment_form_color_scheme', $this->default_color_scheme ),
258 'lang' => get_locale(),
259 'jetpack_version' => JETPACK__VERSION,
260 );
261
262 // Extra parameters for logged in user
263 if ( is_user_logged_in() ) {
264 $current_user = wp_get_current_user();
265 $params['hc_post_as'] = 'jetpack';
266 $params['hc_userid'] = $current_user->ID;
267 $params['hc_username'] = $current_user->display_name;
268 $params['hc_userurl'] = $current_user->user_url;
269 $params['hc_useremail'] = md5( strtolower( trim( $current_user->user_email ) ) );
270 if ( current_user_can( 'unfiltered_html' ) ) {
271 $params['_wp_unfiltered_html_comment'] = wp_create_nonce( 'unfiltered-html-comment_' . get_the_ID() );
272 }
273 } else {
274 $commenter = wp_get_current_commenter();
275 $params['show_cookie_consent'] = (int) has_action( 'set_comment_cookies', 'wp_set_comment_cookies' );
276 $params['has_cookie_consent'] = (int) ! empty( $commenter['comment_author_email'] );
277 }
278
279 $signature = Jetpack_Comments::sign_remote_comment_parameters( $params, Jetpack_Options::get_option( 'blog_token' ) );
280 if ( is_wp_error( $signature ) ) {
281 $signature = 'error';
282 }
283
284 $params['sig'] = $signature;
285 $url_origin = set_url_scheme( 'http://jetpack.wordpress.com' );
286 $url = "{$url_origin}/jetpack-comment/?" . http_build_query( $params );
287 $url = "{$url}#parent=" . urlencode( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) );
288 $this->signed_url = $url;
289 $height = $params['comment_registration'] || is_user_logged_in() ? '315' : '430'; // Iframe can be shorter if we're not allowing guest commenting
290 $transparent = ( $params['color_scheme'] == 'transparent' ) ? 'true' : 'false';
291
292 if ( isset( $_GET['replytocom'] ) ) {
293 $url .= '&replytocom=' . (int) $_GET['replytocom'];
294 }
295
296 /**
297 * Filter whether the comment title can be displayed.
298 *
299 * @module comments
300 *
301 * @since 4.7.0
302 *
303 * @param bool $show Can the comment be displayed? Default to true.
304 */
305 $show_greeting = apply_filters( 'jetpack_comment_form_display_greeting', true );
306
307 // The actual iframe (loads comment form from Jetpack server)
308 ?>
309
310 <div id="respond" class="comment-respond">
311 <?php if ( true === $show_greeting ) : ?>
312 <h3 id="reply-title" class="comment-reply-title"><?php comment_form_title( esc_html( $params['greeting'] ), esc_html( $params['greeting_reply'] ) ); ?>
313 <small><?php cancel_comment_reply_link( esc_html__( 'Cancel reply', 'jetpack' ) ); ?></small>
314 </h3>
315 <?php endif; ?>
316 <form id="commentform" class="comment-form">
317 <iframe title="<?php esc_attr_e( 'Comment Form' , 'jetpack' ); ?>" src="<?php echo esc_url( $url ); ?>" style="width:100%; height: <?php echo $height; ?>px; border:0;" name="jetpack_remote_comment" class="jetpack_remote_comment" id="jetpack_remote_comment" sandbox="allow-scripts allow-top-navigation-by-user-activation allow-forms"></iframe>
318 <?php if ( ! Jetpack_AMP_Support::is_amp_request() ) : ?>
319 <!--[if !IE]><!-->
320 <script>
321 document.addEventListener('DOMContentLoaded', function () {
322 var commentForms = document.getElementsByClassName('jetpack_remote_comment');
323 for (var i = 0; i < commentForms.length; i++) {
324 commentForms[i].allowTransparency = <?php echo $transparent; ?>;
325 commentForms[i].scrolling = 'no';
326 }
327 });
328 </script>
329 <!--<![endif]-->
330 <?php endif; ?>
331 </form>
332 </div>
333
334 <?php // Below is required for comment reply JS to work ?>
335
336 <input type="hidden" name="comment_parent" id="comment_parent" value="" />
337
338 <?php
339 }
340
341 /**
342 * Add some JS to wp_footer to watch for hierarchical reply parent change
343 *
344 * @since JetpackComments (1.4)
345 */
346 public function watch_comment_parent() {
347 $url_origin = set_url_scheme( 'http://jetpack.wordpress.com' );
348 ?>
349
350 <!--[if IE]>
351 <script type="text/javascript">
352 if ( 0 === window.location.hash.indexOf( '#comment-' ) ) {
353 // window.location.reload() doesn't respect the Hash in IE
354 window.location.hash = window.location.hash;
355 }
356 </script>
357 <![endif]-->
358 <script type="text/javascript">
359 (function () {
360 var comm_par_el = document.getElementById( 'comment_parent' ),
361 comm_par = ( comm_par_el && comm_par_el.value ) ? comm_par_el.value : '',
362 frame = document.getElementById( 'jetpack_remote_comment' ),
363 tellFrameNewParent;
364
365 tellFrameNewParent = function () {
366 if ( comm_par ) {
367 frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>" + '&replytocom=' + parseInt( comm_par, 10 ).toString();
368 } else {
369 frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>";
370 }
371 };
372
373 <?php if ( get_option( 'thread_comments' ) && get_option( 'thread_comments_depth' ) ) : ?>
374
375 if ( 'undefined' !== typeof addComment ) {
376 addComment._Jetpack_moveForm = addComment.moveForm;
377
378 addComment.moveForm = function ( commId, parentId, respondId, postId ) {
379 var returnValue = addComment._Jetpack_moveForm( commId, parentId, respondId, postId ),
380 cancelClick, cancel;
381
382 if ( false === returnValue ) {
383 cancel = document.getElementById( 'cancel-comment-reply-link' );
384 cancelClick = cancel.onclick;
385 cancel.onclick = function () {
386 var cancelReturn = cancelClick.call( this );
387 if ( false !== cancelReturn ) {
388 return cancelReturn;
389 }
390
391 if ( ! comm_par ) {
392 return cancelReturn;
393 }
394
395 comm_par = 0;
396
397 tellFrameNewParent();
398
399 return cancelReturn;
400 };
401 }
402
403 if ( comm_par == parentId ) {
404 return returnValue;
405 }
406
407 comm_par = parentId;
408
409 tellFrameNewParent();
410
411 return returnValue;
412 };
413 }
414
415 <?php endif; ?>
416
417 // Do the post message bit after the dom has loaded.
418 document.addEventListener( 'DOMContentLoaded', function () {
419 var iframe_url = <?php echo json_encode( esc_url_raw( $url_origin ) ); ?>;
420 if ( window.postMessage ) {
421 if ( document.addEventListener ) {
422 window.addEventListener( 'message', function ( event ) {
423 var origin = event.origin.replace( /^http:\/\//i, 'https://' );
424 if ( iframe_url.replace( /^http:\/\//i, 'https://' ) !== origin ) {
425 return;
426 }
427 jQuery( frame ).height( event.data );
428 });
429 } else if ( document.attachEvent ) {
430 window.attachEvent( 'message', function ( event ) {
431 var origin = event.origin.replace( /^http:\/\//i, 'https://' );
432 if ( iframe_url.replace( /^http:\/\//i, 'https://' ) !== origin ) {
433 return;
434 }
435 jQuery( frame ).height( event.data );
436 });
437 }
438 }
439 })
440
441 })();
442 </script>
443
444 <?php
445 }
446
447 /**
448 * Verify the hash included in remote comments.
449 *
450 * @since JetpackComments (1.4)
451 *
452 * @param type $comment Not used
453 */
454 public function pre_comment_on_post( $comment ) {
455 $post_array = stripslashes_deep( $_POST );
456
457 // Bail if missing the Jetpack token
458 if ( ! isset( $post_array['sig'] ) ) {
459 unset( $_POST['hc_post_as'] );
460
461 return;
462 }
463
464 if ( false !== strpos( $post_array['hc_avatar'], '.gravatar.com' ) ) {
465 $post_array['hc_avatar'] = htmlentities( $post_array['hc_avatar'] );
466 }
467
468 $check = Jetpack_Comments::sign_remote_comment_parameters( $post_array, Jetpack_Options::get_option( 'blog_token' ) );
469 if ( is_wp_error( $check ) ) {
470 wp_die( $check );
471 }
472
473 // Bail if token is expired or not valid
474 if ( $check !== $post_array['sig'] ) {
475 wp_die( __( 'Invalid security token.', 'jetpack' ) );
476 }
477
478 /** This filter is documented in modules/comments/comments.php */
479 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type( $post_array['comment_post_ID'] ), true ) ) {
480 // In case the comment POST is legit, but the comments are
481 // now disabled, we don't allow the comment
482
483 wp_die( __( 'Comments are not allowed.', 'jetpack' ) );
484 }
485 }
486
487 /** Capabilities **********************************************************/
488
489 /**
490 * Add some additional comment meta after comment is saved about what
491 * service the comment is from, the avatar, user_id, etc...
492 *
493 * @since JetpackComments (1.4)
494 *
495 * @param type $comment_id
496 */
497 public function add_comment_meta( $comment_id ) {
498 $comment_meta = array();
499
500 switch ( $this->is_highlander_comment_post() ) {
501 case 'facebook' :
502 $comment_meta['hc_post_as'] = 'facebook';
503 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
504 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
505 break;
506
507 case 'twitter' :
508 $comment_meta['hc_post_as'] = 'twitter';
509 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
510 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
511 break;
512
513 case 'wordpress' :
514 $comment_meta['hc_post_as'] = 'wordpress';
515 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
516 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
517 $comment_meta['hc_wpcom_id_sig'] = stripslashes( $_POST['hc_wpcom_id_sig'] ); //since 1.9
518 break;
519
520 case 'jetpack' :
521 $comment_meta['hc_post_as'] = 'jetpack';
522 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
523 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
524 break;
525
526 }
527
528 // Bail if no extra comment meta
529 if ( empty( $comment_meta ) ) {
530 return;
531 }
532
533 // Loop through extra meta and add values
534 foreach ( $comment_meta as $key => $value ) {
535 add_comment_meta( $comment_id, $key, $value, true );
536 }
537 }
538
539 function capture_comment_post_redirect_to_reload_parent_frame( $url ) {
540 if ( ! isset( $_GET['for'] ) || 'jetpack' != $_GET['for'] ) {
541 return $url;
542 }
543 ?>
544 <!DOCTYPE html>
545 <html <?php language_attributes(); ?>>
546 <!--<![endif]-->
547 <head>
548 <meta charset="<?php bloginfo( 'charset' ); ?>" />
549 <title><?php printf( __( 'Submitting Comment%s', 'jetpack' ), '&hellip;' ); ?></title>
550 <style type="text/css">
551 body {
552 display: table;
553 width: 100%;
554 height: 60%;
555 position: absolute;
556 top: 0;
557 left: 0;
558 overflow: hidden;
559 color: #333;
560 }
561
562 h1 {
563 text-align: center;
564 margin: 0;
565 padding: 0;
566 display: table-cell;
567 vertical-align: middle;
568 font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
569 font-weight: normal;
570 }
571
572 .hidden {
573 opacity: 0;
574 }
575
576 h1 span {
577 -moz-transition-property: opacity;
578 -moz-transition-duration: 1s;
579 -moz-transition-timing-function: ease-in-out;
580
581 -webkit-transition-property: opacity;
582 -webkit-transition-duration: 1s;
583 -webbit-transition-timing-function: ease-in-out;
584
585 -o-transition-property: opacity;
586 -o-transition-duration: 1s;
587 -o-transition-timing-function: ease-in-out;
588
589 -ms-transition-property: opacity;
590 -ms-transition-duration: 1s;
591 -ms-transition-timing-function: ease-in-out;
592
593 transition-property: opacity;
594 transition-duration: 1s;
595 transition-timing-function: ease-in-out;
596 }
597 </style>
598 </head>
599 <body>
600 <h1><?php printf( __( 'Submitting Comment%s', 'jetpack' ), '<span id="ellipsis" class="hidden">&hellip;</span>' ); ?></h1>
601 <script type="text/javascript">
602 try {
603 window.parent.location = <?php echo json_encode( $url ); ?>;
604 window.parent.location.reload(true);
605 } catch (e) {
606 window.location = <?php echo json_encode( $url ); ?>;
607 window.location.reload(true);
608 }
609 ellipsis = document.getElementById('ellipsis');
610
611 function toggleEllipsis() {
612 ellipsis.className = ellipsis.className ? '' : 'hidden';
613 }
614
615 setInterval(toggleEllipsis, 1200);
616 </script>
617 </body>
618 </html>
619 <?php
620 exit;
621 }
622 }
623
624 Jetpack_Comments::init();
625