PluginProbe
Edit Flow / 0.8
Edit Flow v0.8
0.11.1 0.11.0 0.7.2 0.7.3 0.7.4 0.7.5 0.7.6 0.8 0.8.1 0.8.2 0.9 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 0.9.7 0.9.8 0.9.9 trunk 0.1.5 0.10.0 0.10.1 0.10.2 All 44 releases
edit-flow / modules / editorial-comments / editorial-comments.php

editorial-comments.php in Edit Flow 0.8, at modules/editorial-comments/editorial-comments.php

567 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * class EF_Editorial_Comments
4 * Threaded commenting in the admin for discussion between writers and editors
5 *
6 * @author batmoo
7 */
8
9 if ( !class_exists( 'EF_Editorial_Comments' ) ) {
10
11 class EF_Editorial_Comments extends EF_Module
12 {
13 // This is comment type used to differentiate editorial comments
14 const comment_type = 'editorial-comment';
15
16 function __construct() {
17 global $edit_flow;
18
19 $this->module_url = $this->get_module_url( __FILE__ );
20 // Register the module with Edit Flow
21 $args = array(
22 'title' => __( 'Editorial Comments', 'edit-flow' ),
23 'short_description' => __( 'Share internal notes with your team.', 'edit-flow' ),
24 'extended_description' => __( 'Use editorial comments to hold a private discussion about a post. Communicate directly with your writers or editors about what works and what needs to be improved for each piece.', 'edit-flow' ),
25 'module_url' => $this->module_url,
26 'img_url' => $this->module_url . 'lib/editorial_comments_s128.png',
27 'slug' => 'editorial-comments',
28 'default_options' => array(
29 'enabled' => 'on',
30 'post_types' => array(
31 'post' => 'on',
32 'page' => 'on',
33 ),
34 ),
35 'configure_page_cb' => 'print_configure_view',
36 'configure_link_text' => __( 'Choose Post Types', 'edit-flow' ),
37 'autoload' => false,
38 'settings_help_tab' => array(
39 'id' => 'ef-editorial-comments-overview',
40 'title' => __('Overview', 'edit-flow'),
41 'content' => __('<p>Editorial comments help you cut down on email overload and keep the conversation close to where it matters: your content. Threaded commenting in the admin, similar to what you find at the end of a blog post, allows writers and editors to privately leave feedback and discuss what needs to be changed before publication.</p><p>Anyone with access to view the story in progress will also have the ability to comment on it. If you have notifications enabled, those following the post will receive an email every time a comment is left.</p>', 'edit-flow'),
42 ),
43 'settings_help_sidebar' => __( '<p><strong>For more information:</strong></p><p><a href="http://editflow.org/features/editorial-comments/">Editorial Comments Documentation</a></p><p><a href="http://wordpress.org/tags/edit-flow?forum_id=10">Edit Flow Forum</a></p><p><a href="https://github.com/danielbachhuber/Edit-Flow">Edit Flow on Github</a></p>', 'edit-flow' ),
44 );
45 $this->module = EditFlow()->register_module( 'editorial_comments', $args );
46 }
47
48 /**
49 * Initialize the rest of the stuff in the class if the module is active
50 */
51 function init() {
52
53 add_action( 'add_meta_boxes', array ( $this, 'add_post_meta_box' ) );
54 add_action( 'admin_init', array( $this, 'register_settings' ) );
55 add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_scripts' ) );
56 add_action( 'wp_ajax_editflow_ajax_insert_comment', array( $this, 'ajax_insert_comment' ) );
57
58 // Add Editorial Comments to the calendar if the calendar is activated
59 if ( $this->module_enabled( 'calendar' ) ) {
60 // Still in progress. See: https://www.pivotaltracker.com/story/show/5930884 and https://www.pivotaltracker.com/story/show/5930895
61 //add_filter( 'ef_calendar_item_information_fields', array( $this, 'filter_calendar_item_fields' ), null, 2 );
62 }
63 }
64
65 /**
66 * Upgrade our data in case we need to
67 *
68 * @since 0.7
69 */
70 function upgrade( $previous_version ) {
71 global $edit_flow;
72
73 // Upgrade path to v0.7
74 if ( version_compare( $previous_version, '0.7' , '<' ) ) {
75 // Technically we've run this code before so we don't want to auto-install new data
76 $edit_flow->update_module_option( $this->module->name, 'loaded_once', true );
77 }
78
79 }
80
81 /**
82 * Load any of the admin scripts we need but only on the pages we need them
83 */
84 function add_admin_scripts( ) {
85 global $pagenow;
86
87 $post_type = $this->get_current_post_type();
88 $supported_post_types = $this->get_post_types_for_module( $this->module );
89 if ( !in_array( $post_type, $supported_post_types ) )
90 return;
91
92 if ( !in_array( $pagenow, array( 'post.php', 'page.php', 'post-new.php', 'page-new.php' ) ) )
93 return;
94
95 wp_enqueue_script( 'edit_flow-post_comment', $this->module_url . 'lib/editorial-comments.js', array( 'jquery','post' ), EDIT_FLOW_VERSION, true );
96 wp_enqueue_style( 'edit-flow-editorial-comments-css', $this->module_url . 'lib/editorial-comments.css', false, EDIT_FLOW_VERSION, 'all' );
97
98 $thread_comments = (int) get_option('thread_comments');
99 ?>
100 <script type="text/javascript">
101 var ef_thread_comments = <?php echo ($thread_comments) ? $thread_comments : 0; ?>;
102 </script>
103 <?php
104
105 }
106
107 /**
108 * Add the editorial comments metabox to enabled post types
109 *
110 * @uses add_meta_box()
111 */
112 function add_post_meta_box() {
113
114 $supported_post_types = $this->get_post_types_for_module( $this->module );
115 foreach ( $supported_post_types as $post_type )
116 add_meta_box('edit-flow-editorial-comments', __('Editorial Comments', 'edit-flow'), array($this, 'editorial_comments_meta_box'), $post_type, 'normal' );
117
118 }
119
120 /**
121 * Get the total number of editorial comments for a post
122 *
123 * @param int $id Unique post ID
124 * @return int $comment_count Number of editorial comments for a post
125 */
126 function get_editorial_comment_count( $id ) {
127 global $wpdb;
128 $comment_count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_type = %s", $id, self::comment_type));
129 if ( !$comment_count )
130 $comment_count = 0;
131 return $comment_count;
132 }
133
134 function editorial_comments_meta_box( ) {
135 global $post, $post_ID;
136 ?>
137 <div id="ef-comments_wrapper">
138 <a name="editorialcomments"></a>
139
140 <?php
141 // Show comments only if not a new post
142 if( ! in_array( $post->post_status, array( 'new', 'auto-draft' ) ) ) :
143
144 // Unused since switched to wp_list_comments
145 $editorial_comments = ef_get_comments_plus (
146 array(
147 'post_id' => $post->ID,
148 'comment_type' => self::comment_type,
149 'orderby' => 'comment_date',
150 'order' => 'ASC',
151 'status' => self::comment_type
152 )
153 );
154 ?>
155
156 <ul id="ef-comments">
157 <?php
158 // We use this so we can take advantage of threading and such
159
160 wp_list_comments(
161 array(
162 'type' => self::comment_type,
163 'callback' => array($this, 'the_comment'),
164 'end-callback' => '__return_false'
165 ),
166 $editorial_comments
167 );
168 ?>
169 </ul>
170
171 <?php $this->the_comment_form(); ?>
172
173 <?php
174 else :
175 ?>
176 <p><?php _e( 'You can add editorial comments to a post once you\'ve saved it for the first time.', 'edit-flow' ); ?></p>
177 <?php
178 endif;
179 ?>
180 <div class="clear"></div>
181 </div>
182 <div class="clear"></div>
183 <?php
184 }
185
186 /**
187 * Displays the main commenting form
188 */
189 function the_comment_form( ) {
190 global $post;
191
192 ?>
193 <a href="#" id="ef-comment_respond" onclick="editorialCommentReply.open();return false;" class="button-primary alignright hide-if-no-js" title=" <?php _e( 'Respond to this post', 'edit-flow' ); ?>"><span><?php _e( 'Respond to this post', 'edit-flow' ); ?></span></a>
194
195 <!-- Reply form, hidden until reply clicked by user -->
196 <div id="ef-replyrow" style="display: none;">
197 <div id="ef-replycontainer">
198 <textarea id="ef-replycontent" name="replycontent" cols="40" rows="5"></textarea>
199 </div>
200
201 <p id="ef-replysubmit">
202 <a class="ef-replysave button-primary alignright" href="#comments-form">
203 <span id="ef-replybtn"><?php _e('Submit Response', 'edit-flow') ?></span>
204 </a>
205 <a class="ef-replycancel button-secondary alignright" href="#comments-form"><?php _e( 'Cancel', 'edit-flow' ); ?></a>
206 <img alt="Sending comment..." src="<?php echo admin_url('/images/wpspin_light.gif') ?>" class="alignright" style="display: none;" id="ef-comment_loading" />
207 <br class="clear" style="margin-bottom:35px;" />
208 <span style="display: none;" class="error"></span>
209 </p>
210
211 <input type="hidden" value="" id="ef-comment_parent" name="ef-comment_parent" />
212 <input type="hidden" name="ef-post_id" id="ef-post_id" value="<?php echo esc_attr( $post->ID ); ?>" />
213
214 <?php wp_nonce_field('comment', 'ef_comment_nonce', false); ?>
215
216 <br class="clear" />
217 </div>
218
219 <?php
220 }
221
222 /**
223 * Displays a single comment
224 */
225 function the_comment($comment, $args, $depth) {
226 global $current_user, $userdata;
227
228 // Get current user
229 get_currentuserinfo() ;
230
231 $GLOBALS['comment'] = $comment;
232
233 // Deleting editorial comments is not enabled for now for the sake of transparency. However, we could consider
234 // EF comment edits (with history, if possible). P2 already allows for edits without history, so even that might work.
235 // Pivotal ticket: https://www.pivotaltracker.com/story/show/18483757
236 //$delete_url = esc_url( wp_nonce_url( "comment.php?action=deletecomment&p=$comment->comment_post_ID&c=$comment->comment_ID", "delete-comment_$comment->comment_ID" ) );
237
238 $actions = array();
239
240 $actions_string = '';
241 // Comments can only be added by users that can edit the post
242 if ( current_user_can('edit_post', $comment->comment_post_ID) ) {
243 $actions['reply'] = '<a onclick="editorialCommentReply.open(\''.$comment->comment_ID.'\',\''.$comment->comment_post_ID.'\');return false;" class="vim-r hide-if-no-js" title="'.__( 'Reply to this comment', 'edit-flow' ).'" href="#">' . __( 'Reply', 'edit-flow' ) . '</a>';
244
245 $sep = ' ';
246 $i = 0;
247 foreach ( $actions as $action => $link ) {
248 ++$i;
249 // Reply and quickedit need a hide-if-no-js span
250 if ( 'reply' == $action || 'quickedit' == $action )
251 $action .= ' hide-if-no-js';
252
253 $actions_string .= "<span class='$action'>$sep$link</span>";
254 }
255 }
256
257 ?>
258
259 <li id="comment-<?php echo esc_attr( $comment->comment_ID ); ?>" <?php comment_class( array( 'comment-item', wp_get_comment_status($comment->comment_ID) ) ); ?>>
260
261 <?php echo get_avatar( $comment->comment_author_email, 50 ); ?>
262
263 <div class="post-comment-wrap">
264 <h5 class="comment-meta">
265 <?php printf( __('<span class="comment-author">%1$s</span><span class="meta"> said on %2$s at %3$s</span>', 'edit-flow'),
266 comment_author_email_link( $comment->comment_author ),
267 get_comment_date( get_option( 'date_format' ) ),
268 get_comment_time() ); ?>
269 </h5>
270
271 <div class="comment-content"><?php comment_text(); ?></div>
272 <p class="row-actions"><?php echo $actions_string; ?></p>
273
274 </div>
275 </li>
276 <?php
277 }
278
279 /**
280 * Handles AJAX insert comment
281 */
282 function ajax_insert_comment( ) {
283 global $current_user, $user_ID, $wpdb;
284
285 // Verify nonce
286 if ( !wp_verify_nonce( $_POST['_nonce'], 'comment') )
287 die( __( "Nonce check failed. Please ensure you're supposed to be adding editorial comments.", 'edit-flow' ) );
288
289 // Get user info
290 get_currentuserinfo();
291
292 // Set up comment data
293 $post_id = absint( $_POST['post_id'] );
294 $parent = absint( $_POST['parent'] );
295
296 // Only allow the comment if user can edit post
297 // @TODO: allow contributers to add comments as well (?)
298 if ( ! current_user_can( 'edit_post', $post_id ) )
299 die( __('Sorry, you don\'t have the privileges to add editorial comments. Please talk to your Administrator.', 'edit-flow' ) );
300
301 // Verify that comment was actually entered
302 $comment_content = trim($_POST['content']);
303 if( !$comment_content )
304 die( __( "Please enter a comment.", 'edit-flow' ) );
305
306 // Check that we have a post_id and user logged in
307 if( $post_id && $current_user ) {
308
309 // set current time
310 $time = current_time('mysql', $gmt = 0);
311
312 // Set comment data
313 $data = array(
314 'comment_post_ID' => (int) $post_id,
315 'comment_author' => esc_sql($current_user->display_name),
316 'comment_author_email' => esc_sql($current_user->user_email),
317 'comment_author_url' => esc_sql($current_user->user_url),
318 'comment_content' => wp_kses($comment_content, array('a' => array('href' => array(),'title' => array()),'b' => array(),'i' => array(),'strong' => array(),'em' => array(),'u' => array(),'del' => array(), 'blockquote' => array(), 'sub' => array(), 'sup' => array() )),
319 'comment_type' => self::comment_type,
320 'comment_parent' => (int) $parent,
321 'user_id' => (int) $user_ID,
322 'comment_author_IP' => esc_sql($_SERVER['REMOTE_ADDR']),
323 'comment_agent' => esc_sql($_SERVER['HTTP_USER_AGENT']),
324 'comment_date' => $time,
325 'comment_date_gmt' => $time,
326 // Set to -1?
327 'comment_approved' => self::comment_type,
328 );
329
330 apply_filters( 'ef_pre_insert_editorial_comment', $data );
331
332 // Insert Comment
333 $comment_id = wp_insert_comment($data);
334 $comment = get_comment($comment_id);
335
336 // Register actions -- will be used to set up notifications and other modules can hook into this
337 if ( $comment_id )
338 do_action( 'ef_post_insert_editorial_comment', $comment );
339
340 // Prepare response
341 $response = new WP_Ajax_Response();
342
343 ob_start();
344 $this->the_comment( $comment, '', '' );
345 $comment_list_item = ob_get_contents();
346 ob_end_clean();
347
348 $response->add( array(
349 'what' => 'comment',
350 'id' => $comment_id,
351 'data' => $comment_list_item,
352 'action' => ($parent) ? 'reply' : 'new'
353 ));
354
355 $response->send();
356
357 } else {
358 die( __('There was a problem of some sort. Try again or contact your administrator.', 'edit-flow') );
359 }
360 }
361
362 /**
363 * Register settings for editorial comments so we can partially use the Settings API
364 * (We use the Settings API for form generation, but not saving)
365 *
366 * @since 0.7
367 */
368 function register_settings() {
369 add_settings_section( $this->module->options_group_name . '_general', false, '__return_false', $this->module->options_group_name );
370 add_settings_field( 'post_types', __( 'Enable for these post types:', 'edit-flow' ), array( $this, 'settings_post_types_option' ), $this->module->options_group_name, $this->module->options_group_name . '_general' );
371 }
372
373 /**
374 * Chose the post types for editorial comments
375 *
376 * @since 0.7
377 */
378 function settings_post_types_option() {
379 global $edit_flow;
380 $edit_flow->settings->helper_option_custom_post_type( $this->module );
381 }
382
383 /**
384 * Validate our user input as the settings are being saved
385 *
386 * @since 0.7
387 */
388 function settings_validate( $new_options ) {
389
390 // Whitelist validation for the post type options
391 if ( !isset( $new_options['post_types'] ) )
392 $new_options['post_types'] = array();
393 $new_options['post_types'] = $this->clean_post_type_options( $new_options['post_types'], $this->module->post_type_support );
394
395 return $new_options;
396
397 }
398
399 /**
400 * Settings page for editorial comments
401 *
402 * @since 0.7
403 */
404 function print_configure_view() {
405 ?>
406
407 <form class="basic-settings" action="<?php echo add_query_arg( 'page', $this->module->settings_slug, get_admin_url( null, 'admin.php' ) ); ?>" method="post">
408 <?php settings_fields( $this->module->options_group_name ); ?>
409 <?php do_settings_sections( $this->module->options_group_name ); ?>
410 <?php
411 echo '<input id="edit_flow_module_name" name="edit_flow_module_name" type="hidden" value="' . esc_attr( $this->module->name ) . '" />';
412 ?>
413 <p class="submit"><?php submit_button( null, 'primary', 'submit', false ); ?><a class="cancel-settings-link" href="<?php echo EDIT_FLOW_SETTINGS_PAGE; ?>"><?php _e( 'Back to Edit Flow', 'edit-flow' ); ?></a></p>
414
415 </form>
416 <?php
417 }
418
419 /**
420 * If the Edit Flow Calendar is enabled, add the editorial comment count to the post overlay.
421 *
422 * @since 0.7
423 * @uses apply_filters( 'ef_calendar_item_information_fields' )
424 *
425 * @param array $calendar_fields Additional data fields to include on the calendar
426 * @param int $post_id Unique ID for the post data we're building
427 * @return array $calendar_fields Calendar fields with our viewable Editorial Metadata added
428 */
429 function filter_calendar_item_fields( $calendar_fields, $post_id ) {
430 // Make sure we respect which post type we're on
431 if ( !in_array( get_post_type( $post_id ), $this->get_post_types_for_module( $this->module ) ) )
432 return $calendar_fields;
433
434 // Name/value for the field to add
435 $comment_count_data = array(
436 'label' => $this->module->title,
437 'value' => $this->get_editorial_comment_count( $post_id ),
438 );
439
440 $calendar_fields[$this->module->slug] = $comment_count_data;
441
442 return $calendar_fields;
443 }
444
445 }
446
447 }
448
449 /**
450 * Retrieve a list of comments -- overloaded from get_comments and with mods by filosofo (SVN Ticket #10668)
451 *
452 * @param mixed $args Optional. Array or string of options to override defaults.
453 * @return array List of comments.
454 */
455 function ef_get_comments_plus( $args = '' ) {
456 global $wpdb;
457
458 $defaults = array(
459 'author_email' => '',
460 'ID' => '',
461 'karma' => '',
462 'number' => '',
463 'offset' => '',
464 'orderby' => '',
465 'order' => 'DESC',
466 'parent' => '',
467 'post_ID' => '',
468 'post_id' => 0,
469 'status' => '',
470 'type' => '',
471 'user_id' => '',
472 );
473
474 $args = wp_parse_args( $args, $defaults );
475 extract( $args, EXTR_SKIP );
476
477 // $args can be whatever, only use the args defined in defaults to compute the key
478 $key = md5( serialize( compact(array_keys($defaults)) ) );
479 $last_changed = wp_cache_get('last_changed', 'comment');
480 if ( !$last_changed ) {
481 $last_changed = time();
482 wp_cache_set('last_changed', $last_changed, 'comment');
483 }
484 $cache_key = "get_comments:$key:$last_changed";
485
486 if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
487 return $cache;
488 }
489
490 $post_id = absint($post_id);
491
492 if ( 'hold' == $status )
493 $approved = "comment_approved = '0'";
494 elseif ( 'approve' == $status )
495 $approved = "comment_approved = '1'";
496 elseif ( 'spam' == $status )
497 $approved = "comment_approved = 'spam'";
498 elseif( ! empty( $status ) )
499 $approved = $wpdb->prepare( "comment_approved = %s", $status );
500 else
501 $approved = "( comment_approved = '0' OR comment_approved = '1' )";
502
503 $order = ( 'ASC' == $order ) ? 'ASC' : 'DESC';
504
505 if ( ! empty( $orderby ) ) {
506 $ordersby = is_array($orderby) ? $orderby : preg_split('/[,\s]/', $orderby);
507 $ordersby = array_intersect(
508 $ordersby,
509 array(
510 'comment_agent',
511 'comment_approved',
512 'comment_author',
513 'comment_author_email',
514 'comment_author_IP',
515 'comment_author_url',
516 'comment_content',
517 'comment_date',
518 'comment_date_gmt',
519 'comment_ID',
520 'comment_karma',
521 'comment_parent',
522 'comment_post_ID',
523 'comment_type',
524 'user_id',
525 )
526 );
527 $orderby = empty( $ordersby ) ? 'comment_date_gmt' : implode(', ', $ordersby);
528 } else {
529 $orderby = 'comment_date_gmt';
530 }
531
532 $number = absint($number);
533 $offset = absint($offset);
534
535 if ( !empty($number) ) {
536 if ( $offset )
537 $number = 'LIMIT ' . $offset . ',' . $number;
538 else
539 $number = 'LIMIT ' . $number;
540
541 } else {
542 $number = '';
543 }
544
545 $post_where = '';
546
547 if ( ! empty($post_id) )
548 $post_where .= $wpdb->prepare( 'comment_post_ID = %d AND ', $post_id );
549 if ( '' !== $author_email )
550 $post_where .= $wpdb->prepare( 'comment_author_email = %s AND ', $author_email );
551 if ( '' !== $karma )
552 $post_where .= $wpdb->prepare( 'comment_karma = %d AND ', $karma );
553 if ( 'comment' == $type )
554 $post_where .= "comment_type = '' AND ";
555 elseif ( ! empty( $type ) )
556 $post_where .= $wpdb->prepare( 'comment_type = %s AND ', $type );
557 if ( '' !== $parent )
558 $post_where .= $wpdb->prepare( 'comment_parent = %d AND ', $parent );
559 if ( '' !== $user_id )
560 $post_where .= $wpdb->prepare( 'user_id = %d AND ', $user_id );
561
562 $comments = $wpdb->get_results( "SELECT * FROM $wpdb->comments WHERE $post_where $approved ORDER BY $orderby $order $number" );
563 wp_cache_add( $cache_key, $comments, 'comment' );
564
565 return $comments;
566 }
567