PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 4.9.3
Jetpack – WP Security, Backup, Speed, & Growth v4.9.3
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 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / comments / comments.php

comments.php in Jetpack – WP Security, Backup, Speed, & Growth 4.9.3, at modules/comments/comments.php

595 lines 18.0 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 remove_all_actions( 'comment_form_after' );
116
117 // Selfishly add only our actions back to the comment form
118 add_action( 'comment_form_before', array( $this, 'comment_form_before' ) );
119 add_action( 'comment_form_after', array( $this, 'comment_form_after' ) );
120
121 // Before a comment is posted
122 add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ), 1 );
123
124 // After a comment is posted
125 add_action( 'comment_post', array( $this, 'add_comment_meta' ) );
126 }
127
128 /**
129 * Setup filters for methods in this class
130 * @since 1.6.2
131 */
132 protected function setup_filters() {
133 parent::setup_filters();
134
135 add_filter( 'comment_post_redirect', array( $this, 'capture_comment_post_redirect_to_reload_parent_frame' ), 100 );
136 add_filter( 'get_avatar', array( $this, 'get_avatar' ), 10, 4 );
137 }
138
139 /**
140 * Get the comment avatar from Gravatar, Twitter, or Facebook
141 *
142 * @since JetpackComments (1.4)
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 * @return string New avatar
148 */
149 public function get_avatar( $avatar, $comment, $size, $default ) {
150 if ( ! isset( $comment->comment_post_ID ) || ! isset( $comment->comment_ID ) ) {
151 // it's not a comment - bail
152 return $avatar;
153 }
154
155 // Detect whether it's a Facebook or Twitter avatar
156 $foreign_avatar = get_comment_meta( $comment->comment_ID, 'hc_avatar', true );
157 $foreign_avatar_hostname = parse_url( $foreign_avatar, PHP_URL_HOST );
158 if ( ! $foreign_avatar_hostname ||
159 ! preg_match( '/\.?(graph\.facebook\.com|twimg\.com)$/', $foreign_avatar_hostname ) ) {
160 return $avatar;
161 }
162
163 // Return the FB or Twitter avatar
164 return preg_replace( '#src=([\'"])[^\'"]+\\1#', 'src=\\1' . esc_url( $this->photon_avatar( $foreign_avatar, $size ) ) . '\\1', $avatar );
165 }
166
167 /** Output Methods ********************************************************/
168
169 /**
170 * Start capturing the core comment_form() output
171 * @since JetpackComments (1.4)
172 */
173 public function comment_form_before() {
174 /**
175 * Filters the setting that determines if Jetpagk comments should be enabled for
176 * the current post type.
177 *
178 * @module comments
179 *
180 * @since 3.8.1
181 *
182 * @param boolean $return Should comments be enabled?
183 */
184 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type(), true ) ) {
185 return;
186 }
187
188 // Add some JS to the footer
189 add_action( 'wp_footer', array( $this, 'watch_comment_parent' ), 100 );
190
191 ob_start();
192 }
193
194 /**
195 * Noop the default comment form output, get some options, and output our
196 * tricked out totally radical comment form.
197 *
198 * @since JetpackComments (1.4)
199 */
200 public function comment_form_after() {
201 /** This filter is documented in modules/comments/comments.php */
202 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type(), true ) ) {
203 return;
204 }
205
206 // Throw it all out and drop in our replacement
207 ob_end_clean();
208
209 // If users are required to be logged in, and they're not, then we don't need to do anything else
210 if ( get_option( 'comment_registration' ) && !is_user_logged_in() ) {
211 /**
212 * Changes the log in to comment prompt.
213 *
214 * @module comments
215 *
216 * @since 1.4.0
217 *
218 * @param string $var Default is "You must log in to post a comment."
219 */
220 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>';
221 return;
222 }
223
224 if ( in_array( 'subscriptions', Jetpack::get_active_modules() ) ) {
225 $stb_enabled = get_option( 'stb_enabled', 1 );
226 $stb_enabled = empty( $stb_enabled ) ? 0 : 1;
227
228 $stc_enabled = get_option( 'stc_enabled', 1 );
229 $stc_enabled = empty( $stc_enabled ) ? 0 : 1;
230 } else {
231 $stb_enabled = 0;
232 $stc_enabled = 0;
233 }
234
235 $params = array(
236 'blogid' => Jetpack_Options::get_option( 'id' ),
237 'postid' => get_the_ID(),
238 'comment_registration' => ( get_option( 'comment_registration' ) ? '1' : '0' ), // Need to explicitly send a '1' or a '0' for these
239 'require_name_email' => ( get_option( 'require_name_email' ) ? '1' : '0' ),
240 'stc_enabled' => $stc_enabled,
241 'stb_enabled' => $stb_enabled,
242 'show_avatars' => ( get_option( 'show_avatars' ) ? '1' : '0' ),
243 'avatar_default' => get_option( 'avatar_default' ),
244 'greeting' => get_option( 'highlander_comment_form_prompt', __( 'Leave a Reply', 'jetpack' ) ),
245 /**
246 * Changes the comment form prompt.
247 *
248 * @module comments
249 *
250 * @since 2.3.0
251 *
252 * @param string $var Default is "Leave a Reply to %s."
253 */
254 'greeting_reply' => apply_filters( 'jetpack_comment_form_prompt_reply', __( 'Leave a Reply to %s' , 'jetpack' ) ),
255 'color_scheme' => get_option( 'jetpack_comment_form_color_scheme', $this->default_color_scheme ),
256 'lang' => get_locale(),
257 'jetpack_version' => JETPACK__VERSION,
258 );
259
260 // Extra parameters for logged in user
261 if ( is_user_logged_in() ) {
262 $current_user = wp_get_current_user();
263 $params['hc_post_as'] = 'jetpack';
264 $params['hc_userid'] = $current_user->ID;
265 $params['hc_username'] = $current_user->display_name;
266 $params['hc_userurl'] = $current_user->user_url;
267 $params['hc_useremail'] = md5( strtolower( trim( $current_user->user_email ) ) );
268 if ( current_user_can( 'unfiltered_html' ) )
269 $params['_wp_unfiltered_html_comment'] = wp_create_nonce( 'unfiltered-html-comment_' . get_the_ID() );
270 }
271
272 $signature = Jetpack_Comments::sign_remote_comment_parameters( $params, Jetpack_Options::get_option( 'blog_token' ) );
273 if ( is_wp_error( $signature ) ) {
274 $signature = 'error';
275 }
276
277 $params['sig'] = $signature;
278 $url = "https://jetpack.wordpress.com/jetpack-comment/?" . http_build_query( $params );
279 $url = "{$url}#parent=" . urlencode( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) );
280 $this->signed_url = $url;
281 $height = $params['comment_registration'] || is_user_logged_in() ? '315' : '430'; // Iframe can be shorter if we're not allowing guest commenting
282 $transparent = ( $params['color_scheme'] == 'transparent' ) ? 'true' : 'false';
283
284 if ( isset( $_GET['replytocom'] ) ) {
285 $url .= '&replytocom=' . (int) $_GET['replytocom'];
286 }
287
288 /**
289 * Filter whether the comment title can be displayed.
290 *
291 * @module comments
292 *
293 * @since 4.7.0
294 *
295 * @param bool $show Can the comment be displayed? Default to true.
296 */
297 $show_greeting = apply_filters( 'jetpack_comment_form_display_greeting', true );
298
299 // The actual iframe (loads comment form from Jetpack server)
300 ?>
301
302 <div id="respond" class="comment-respond">
303 <?php if ( true === $show_greeting ) : ?>
304 <h3 id="reply-title" class="comment-reply-title"><?php comment_form_title( esc_html( $params['greeting'] ), esc_html( $params['greeting_reply'] ) ); ?> <small><?php cancel_comment_reply_link( esc_html__( 'Cancel reply' , 'jetpack') ); ?></small></h3>
305 <?php endif; ?>
306 <form id="commentform" class="comment-form">
307 <iframe 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"></iframe>
308 <!--[if !IE]><!-->
309 <script>
310 document.addEventListener( 'DOMContentLoaded', function () {
311 var commentForms = document.getElementsByClassName( 'jetpack_remote_comment' );
312 for ( var i = 0; i < commentForms.length; i++ ) {
313 commentForms[i].allowTransparency = <?php echo $transparent; ?>;
314 commentForms[i].scrolling = 'no';
315 }
316 } );
317 </script>
318 <!--<![endif]-->
319 </form>
320 </div>
321
322 <?php // Below is required for comment reply JS to work ?>
323
324 <input type="hidden" name="comment_parent" id="comment_parent" value="" />
325
326 <?php
327 }
328
329 /**
330 * Add some JS to wp_footer to watch for hierarchical reply parent change
331 *
332 * @since JetpackComments (1.4)
333 */
334 public function watch_comment_parent() {
335 $url_origin = 'https://jetpack.wordpress.com';
336 ?>
337
338 <!--[if IE]>
339 <script type="text/javascript">
340 if ( 0 === window.location.hash.indexOf( '#comment-' ) ) {
341 // window.location.reload() doesn't respect the Hash in IE
342 window.location.hash = window.location.hash;
343 }
344 </script>
345 <![endif]-->
346 <script type="text/javascript">
347 var comm_par_el = document.getElementById( 'comment_parent' ),
348 comm_par = (comm_par_el && comm_par_el.value) ? comm_par_el.value : '',
349 frame = document.getElementById( 'jetpack_remote_comment' ),
350 tellFrameNewParent;
351
352 tellFrameNewParent = function() {
353 if ( comm_par ) {
354 frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>" + '&replytocom=' + parseInt( comm_par, 10 ).toString();
355 } else {
356 frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>";
357 }
358 };
359
360 <?php if ( get_option( 'thread_comments' ) && get_option( 'thread_comments_depth' ) ) : ?>
361
362 if ( 'undefined' !== typeof addComment ) {
363 addComment._Jetpack_moveForm = addComment.moveForm;
364
365 addComment.moveForm = function( commId, parentId, respondId, postId ) {
366 var returnValue = addComment._Jetpack_moveForm( commId, parentId, respondId, postId ), cancelClick, cancel;
367
368 if ( false === returnValue ) {
369 cancel = document.getElementById( 'cancel-comment-reply-link' );
370 cancelClick = cancel.onclick;
371 cancel.onclick = function() {
372 var cancelReturn = cancelClick.call( this );
373 if ( false !== cancelReturn ) {
374 return cancelReturn;
375 }
376
377 if ( !comm_par ) {
378 return cancelReturn;
379 }
380
381 comm_par = 0;
382
383 tellFrameNewParent();
384
385 return cancelReturn;
386 };
387 }
388
389 if ( comm_par == parentId ) {
390 return returnValue;
391 }
392
393 comm_par = parentId;
394
395 tellFrameNewParent();
396
397 return returnValue;
398 };
399 }
400
401 <?php endif; ?>
402
403 if ( window.postMessage ) {
404 if ( document.addEventListener ) {
405 window.addEventListener( 'message', function( event ) {
406 if ( <?php echo json_encode( esc_url_raw( $url_origin ) ); ?> !== event.origin ) {
407 return;
408 }
409
410 jQuery( frame ).height( event.data );
411 } );
412 } else if ( document.attachEvent ) {
413 window.attachEvent( 'message', function( event ) {
414 if ( <?php echo json_encode( esc_url_raw( $url_origin ) ); ?> !== event.origin ) {
415 return;
416 }
417
418 jQuery( frame ).height( event.data );
419 } );
420 }
421 }
422 </script>
423
424 <?php
425 }
426
427 /**
428 * Verify the hash included in remote comments.
429 *
430 * @since JetpackComments (1.4)
431 * @param type $comment Not used
432 */
433 public function pre_comment_on_post( $comment ) {
434 $post_array = stripslashes_deep( $_POST );
435
436 // Bail if missing the Jetpack token
437 if ( ! isset( $post_array['sig'] ) ) {
438 unset( $_POST['hc_post_as'] );
439 return;
440 }
441
442 if ( FALSE !== strpos( $post_array['hc_avatar'], '.gravatar.com' ) )
443 $post_array['hc_avatar'] = htmlentities( $post_array['hc_avatar'] );
444
445 $check = Jetpack_Comments::sign_remote_comment_parameters( $post_array, Jetpack_Options::get_option( 'blog_token' ) );
446 if ( is_wp_error( $check ) ) {
447 wp_die( $check );
448 }
449
450 // Bail if token is expired or not valid
451 if ( $check !== $post_array['sig'] )
452 wp_die( __( 'Invalid security token.', 'jetpack' ) );
453
454 /** This filter is documented in modules/comments/comments.php */
455 if ( ! apply_filters( 'jetpack_comment_form_enabled_for_' . get_post_type( $post_array['comment_post_ID'] ), true ) ) {
456 // In case the comment POST is legit, but the comments are
457 // now disabled, we don't allow the comment
458
459 wp_die( __( 'Comments are not allowed.', 'jetpack' ) );
460 }
461 }
462
463 /** Capabilities **********************************************************/
464
465 /**
466 * Add some additional comment meta after comment is saved about what
467 * service the comment is from, the avatar, user_id, etc...
468 *
469 * @since JetpackComments (1.4)
470 * @param type $comment_id
471 */
472 public function add_comment_meta( $comment_id ) {
473 $comment_meta = array();
474
475 switch( $this->is_highlander_comment_post() ) {
476 case 'facebook' :
477 $comment_meta['hc_post_as'] = 'facebook';
478 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
479 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
480 break;
481
482 case 'twitter' :
483 $comment_meta['hc_post_as'] = 'twitter';
484 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
485 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
486 break;
487
488 case 'wordpress' :
489 $comment_meta['hc_post_as'] = 'wordpress';
490 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
491 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
492 $comment_meta['hc_wpcom_id_sig'] = stripslashes( $_POST['hc_wpcom_id_sig'] ); //since 1.9
493 break;
494
495 case 'jetpack' :
496 $comment_meta['hc_post_as'] = 'jetpack';
497 $comment_meta['hc_avatar'] = stripslashes( $_POST['hc_avatar'] );
498 $comment_meta['hc_foreign_user_id'] = stripslashes( $_POST['hc_userid'] );
499 break;
500
501 }
502
503 // Bail if no extra comment meta
504 if ( empty( $comment_meta ) )
505 return;
506
507 // Loop through extra meta and add values
508 foreach ( $comment_meta as $key => $value )
509 add_comment_meta( $comment_id, $key, $value, true );
510 }
511 function capture_comment_post_redirect_to_reload_parent_frame( $url ) {
512 if ( !isset( $_GET['for'] ) || 'jetpack' != $_GET['for'] ) {
513 return $url;
514 }
515 ?>
516 <!DOCTYPE html>
517 <html <?php language_attributes(); ?>>
518 <!--<![endif]-->
519 <head>
520 <meta charset="<?php bloginfo( 'charset' ); ?>" />
521 <title><?php printf( __( 'Submitting Comment%s', 'jetpack' ), '&hellip;' ); ?></title>
522 <style type="text/css">
523 body {
524 display: table;
525 width: 100%;
526 height: 60%;
527 position: absolute;
528 top: 0;
529 left: 0;
530 overflow: hidden;
531 color: #333;
532 }
533
534 h1 {
535 text-align: center;
536 margin: 0;
537 padding: 0;
538 display: table-cell;
539 vertical-align: middle;
540 font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
541 font-weight: normal;
542 }
543
544 .hidden {
545 opacity: 0;
546 }
547
548 h1 span {
549 -moz-transition-property: opacity;
550 -moz-transition-duration: 1s;
551 -moz-transition-timing-function: ease-in-out;
552
553 -webkit-transition-property: opacity;
554 -webkit-transition-duration: 1s;
555 -webbit-transition-timing-function: ease-in-out;
556
557 -o-transition-property: opacity;
558 -o-transition-duration: 1s;
559 -o-transition-timing-function: ease-in-out;
560
561 -ms-transition-property: opacity;
562 -ms-transition-duration: 1s;
563 -ms-transition-timing-function: ease-in-out;
564
565 transition-property: opacity;
566 transition-duration: 1s;
567 transition-timing-function: ease-in-out;
568 }
569 </style>
570 </head>
571 <body>
572 <h1><?php printf( __( 'Submitting Comment%s', 'jetpack' ), '<span id="ellipsis" class="hidden">&hellip;</span>' ); ?></h1>
573 <script type="text/javascript">
574 try {
575 window.parent.location = <?php echo json_encode( $url ); ?>;
576 window.parent.location.reload( true );
577 } catch ( e ) {
578 window.location = <?php echo json_encode( $url ); ?>;
579 window.location.reload( true );
580 }
581 ellipsis = document.getElementById( 'ellipsis' );
582 function toggleEllipsis() {
583 ellipsis.className = ellipsis.className ? '' : 'hidden';
584 }
585 setInterval( toggleEllipsis, 1200 );
586 </script>
587 </body>
588 </html>
589 <?php
590 exit;
591 }
592 }
593
594 Jetpack_Comments::init();
595