Co-Authors Plus - Version 2.6.2

Version Description

Download this release

Release Info

Developer danielbachhuber
Plugin Icon wp plugin Co-Authors Plus
Version 2.6.2
Comparing to
See all releases

Code changes from version 2.6.1 to 2.6.2

Files changed (4) hide show
  1. co-authors-plus.php +310 -104
  2. js/co-authors-plus.js +6 -1
  3. readme.txt +17 -9
  4. template-tags.php +14 -6
co-authors-plus.php CHANGED
@@ -3,8 +3,8 @@
3
  Plugin Name: Co-Authors Plus
4
  Plugin URI: http://wordpress.org/extend/plugins/co-authors-plus/
5
  Description: Allows multiple authors to be assigned to a post. This plugin is an extended version of the Co-Authors plugin developed by Weston Ruter.
6
- Version: 2.6.1
7
- Author: Mohammad Jangda, Daniel Bachhuber
8
  Copyright: 2008-2011 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
10
  GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
@@ -24,22 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
 
25
  */
26
 
27
- define( 'COAUTHORS_PLUS_VERSION', '2.6.1' );
28
-
29
- if( ! defined( 'COAUTHORS_PLUS_DEBUG' ) )
30
- define( 'COAUTHORS_PLUS_DEBUG', false );
31
-
32
- if( ! defined( 'COAUTHORS_DEFAULT_BEFORE' ) )
33
- define( 'COAUTHORS_DEFAULT_BEFORE', '' );
34
-
35
- if( ! defined( 'COAUTHORS_DEFAULT_BETWEEN' ) )
36
- define( 'COAUTHORS_DEFAULT_BETWEEN', ', ' );
37
-
38
- if( ! defined( 'COAUTHORS_DEFAULT_BETWEEN_LAST' ) )
39
- define( 'COAUTHORS_DEFAULT_BETWEEN_LAST', __( ' and ', 'co-authors-plus' ) );
40
-
41
- if( ! defined( 'COAUTHORS_DEFAULT_AFTER' ) )
42
- define( 'COAUTHORS_DEFAULT_AFTER', '' );
43
 
44
  define( 'COAUTHORS_PLUS_PATH', dirname( __FILE__ ) );
45
  define( 'COAUTHORS_PLUS_URL', plugin_dir_url( __FILE__ ) );
@@ -81,7 +66,7 @@ class coauthors_plus {
81
  // Action to set users when a post is saved
82
  add_action( 'save_post', array( $this, 'coauthors_update_post' ), 10, 2 );
83
  // Filter to set the post_author field when wp_insert_post is called
84
- add_filter( 'wp_insert_post_data', array( $this, 'coauthors_set_post_author_field' ) );
85
 
86
  // Action to reassign posts when a user is deleted
87
  add_action( 'delete_user', array( $this, 'delete_user_action' ) );
@@ -93,9 +78,7 @@ class coauthors_plus {
93
 
94
  // Filter to allow coauthors to edit posts
95
  add_filter( 'user_has_cap', array( $this, 'add_coauthor_cap' ), 10, 3 );
96
-
97
- add_filter( 'comment_notification_headers', array( $this, 'notify_coauthors' ), 10, 3 );
98
-
99
  // Handle the custom author meta box
100
  add_action( 'add_meta_boxes', array( $this, 'add_coauthors_box' ) );
101
  add_action( 'add_meta_boxes', array( $this, 'remove_authors_box' ) );
@@ -109,6 +92,10 @@ class coauthors_plus {
109
  // Fix for author info not properly displaying on author pages
110
  add_action( 'the_post', array( $this, 'fix_author_page' ) );
111
 
 
 
 
 
112
  }
113
 
114
  function coauthors_plus() {
@@ -454,7 +441,7 @@ class coauthors_plus {
454
  /**
455
  * Filters post data before saving to db to set post_author
456
  */
457
- function coauthors_set_post_author_field( $data ) {
458
 
459
  // Bail on autosave
460
  if ( defined( 'DOING_AUTOSAVE' ) && !DOING_AUTOSAVE )
@@ -474,6 +461,15 @@ class coauthors_plus {
474
  }
475
  }
476
 
 
 
 
 
 
 
 
 
 
477
  // If for some reason we don't have the coauthors fields set
478
  if( ! isset( $data['post_author'] ) ) {
479
  $user = wp_get_current_user();
@@ -666,58 +662,69 @@ class coauthors_plus {
666
 
667
  if( empty( $_REQUEST['q'] ) )
668
  die();
669
-
670
- if( ! $this->current_user_can_set_authors() )
671
- die();
672
-
673
  $search = sanitize_text_field( strtolower( $_REQUEST['q'] ) );
674
-
675
- $authors = $this->search_authors( $search );
 
676
 
677
  foreach( $authors as $author ) {
678
  echo $author->ID ." | ". $author->user_login ." | ". $author->display_name ." | ". $author->user_email ."\n";
679
  }
680
-
681
- if( COAUTHORS_PLUS_DEBUG ) {
682
- echo 'queries:' . get_num_queries() ."\n";
683
- echo 'timer: ' . timer_stop(1) . "sec\n";
684
- }
685
-
686
  die();
687
-
688
  }
689
 
690
  /**
691
  * Get matching authors based on a search value
692
  */
693
- function search_authors( $search = '' ) {
694
-
695
- $args = array(
696
- 'search' => sprintf( '*%s*', $search ), // Enable wildcard searching
697
- 'who' => 'authors',
698
- 'fields' => array(
 
 
 
699
  'ID',
700
  'display_name',
 
 
 
 
701
  'user_login',
702
- 'user_email'
703
- ),
704
- );
705
- add_filter( 'pre_user_query', array( &$this, 'filter_pre_user_query' ) );
706
- $authors = get_users( $args );
707
- remove_filter( 'pre_user_query', array( &$this, 'filter_pre_user_query' ) );
708
-
709
- return (array) $authors;
710
- }
711
 
712
- /**
713
- * Modify get_users() to search display_name instead of user_nicename
714
- */
715
- function filter_pre_user_query( &$user_query ) {
716
- if ( is_object( $user_query ) )
717
- $user_query->query_where = str_replace( "user_nicename LIKE", "display_name LIKE", $user_query->query_where );
718
- return $user_query;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719
  }
720
-
721
  /**
722
  * Functions to add scripts and css
723
  */
@@ -726,25 +733,24 @@ class coauthors_plus {
726
 
727
  $post_type = $this->get_current_post_type();
728
 
729
- // TODO: Check if user can set authors? $this->current_user_can_set_authors()
730
- if( $this->is_valid_page() && $this->authors_supported( $post_type ) ) {
731
 
732
- wp_enqueue_script( 'jquery' );
733
- wp_enqueue_script( 'jquery-ui-sortable' );
734
- wp_enqueue_style( 'co-authors-plus-css', COAUTHORS_PLUS_URL . 'css/co-authors-plus.css', false, COAUTHORS_PLUS_VERSION, 'all' );
735
- wp_enqueue_script( 'co-authors-plus-js', COAUTHORS_PLUS_URL . 'js/co-authors-plus.js', array('jquery', 'suggest'), COAUTHORS_PLUS_VERSION, true);
736
-
737
- $js_strings = array(
738
- 'edit_label' => __( 'Edit', 'co-authors-plus' ),
739
- 'delete_label' => __( 'Remove', 'co-authors-plus' ),
740
- 'confirm_delete' => __( 'Are you sure you want to remove this author?', 'co-authors-plus' ),
741
- 'input_box_title' => __( 'Click to change this author, or drag to change their position', 'co-authors-plus' ),
742
- 'search_box_text' => __( 'Search for an author', 'co-authors-plus' ),
743
- 'help_text' => __( 'Click on an author to change them. Drag to change their order. Click on <strong>Remove</strong> to remove them.', 'co-authors-plus' ),
744
- );
745
- wp_localize_script( 'co-authors-plus-js', 'coAuthorsPlusStrings', $js_strings );
746
-
747
- }
748
  }
749
 
750
  /**
@@ -842,40 +848,240 @@ class coauthors_plus {
842
 
843
  return $allcaps;
844
  }
845
-
846
  /**
847
- * Emails all coauthors when comment added instead of the main author
848
- *
 
849
  */
850
- function notify_coauthors( $message_headers, $comment_id ) {
851
- // TODO: this is broken!
852
- $comment = get_comment($comment_id);
853
- $post = get_post($comment->comment_post_ID);
854
- $coauthors = get_coauthors($comment->comment_post_ID);
855
-
856
- $message_headers .= 'cc: ';
857
- $count = 0;
858
- foreach($coauthors as $author) {
859
- $count++;
860
- if($author->ID != $post->post_author){
861
- $message_headers .= $author->user_email;
862
- if($count < count($coauthors)) $message_headers .= ',';
863
- }
864
  }
865
- $message_headers .= "\n";
866
- return $message_headers;
867
  }
868
-
869
- function debug($msg, $object) {
870
- if( COAUTHORS_PLUS_DEBUG ) {
871
- echo '<hr />';
872
- echo sprintf('<p>%s</p>', $msg);
873
- echo '<pre>';
874
- var_dump($object);
875
- echo '</pre>';
 
 
 
 
 
 
 
 
876
  }
 
877
  }
 
878
  }
879
 
880
  global $coauthors_plus;
881
  $coauthors_plus = new coauthors_plus();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  Plugin Name: Co-Authors Plus
4
  Plugin URI: http://wordpress.org/extend/plugins/co-authors-plus/
5
  Description: Allows multiple authors to be assigned to a post. This plugin is an extended version of the Co-Authors plugin developed by Weston Ruter.
6
+ Version: 2.6.2
7
+ Author: Mohammad Jangda, Daniel Bachhuber, Automattic
8
  Copyright: 2008-2011 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
10
  GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
24
 
25
  */
26
 
27
+ define( 'COAUTHORS_PLUS_VERSION', '2.6.2' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  define( 'COAUTHORS_PLUS_PATH', dirname( __FILE__ ) );
30
  define( 'COAUTHORS_PLUS_URL', plugin_dir_url( __FILE__ ) );
66
  // Action to set users when a post is saved
67
  add_action( 'save_post', array( $this, 'coauthors_update_post' ), 10, 2 );
68
  // Filter to set the post_author field when wp_insert_post is called
69
+ add_filter( 'wp_insert_post_data', array( $this, 'coauthors_set_post_author_field' ), 10, 2 );
70
 
71
  // Action to reassign posts when a user is deleted
72
  add_action( 'delete_user', array( $this, 'delete_user_action' ) );
78
 
79
  // Filter to allow coauthors to edit posts
80
  add_filter( 'user_has_cap', array( $this, 'add_coauthor_cap' ), 10, 3 );
81
+
 
 
82
  // Handle the custom author meta box
83
  add_action( 'add_meta_boxes', array( $this, 'add_coauthors_box' ) );
84
  add_action( 'add_meta_boxes', array( $this, 'remove_authors_box' ) );
92
  // Fix for author info not properly displaying on author pages
93
  add_action( 'the_post', array( $this, 'fix_author_page' ) );
94
 
95
+ // Support for Edit Flow's calendar and story budget
96
+ add_filter( 'ef_calendar_item_information_fields', array( $this, 'filter_ef_calendar_item_information_fields' ), 10, 2 );
97
+ add_filter( 'ef_story_budget_term_column_value', array( $this, 'filter_ef_story_budget_term_column_value' ), 10, 3 );
98
+
99
  }
100
 
101
  function coauthors_plus() {
441
  /**
442
  * Filters post data before saving to db to set post_author
443
  */
444
+ function coauthors_set_post_author_field( $data, $postarr ) {
445
 
446
  // Bail on autosave
447
  if ( defined( 'DOING_AUTOSAVE' ) && !DOING_AUTOSAVE )
461
  }
462
  }
463
 
464
+ // Restore the co-author when quick editing because we don't
465
+ // allow changing the co-author on quick edit. In wp_insert_post(),
466
+ // 'post_author' is set to current user if the $_REQUEST value doesn't exist
467
+ if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'inline-save' ) {
468
+ $coauthors = get_coauthors( $postarr['ID'] );
469
+ if ( is_array( $coauthors ) )
470
+ $data['post_author'] = $coauthors[0]->ID;
471
+ }
472
+
473
  // If for some reason we don't have the coauthors fields set
474
  if( ! isset( $data['post_author'] ) ) {
475
  $user = wp_get_current_user();
662
 
663
  if( empty( $_REQUEST['q'] ) )
664
  die();
665
+
 
 
 
666
  $search = sanitize_text_field( strtolower( $_REQUEST['q'] ) );
667
+ $ignore = array_map( 'sanitize_user', explode( ',', $_REQUEST['existing_authors'] ) );
668
+
669
+ $authors = $this->search_authors( $search, $ignore );
670
 
671
  foreach( $authors as $author ) {
672
  echo $author->ID ." | ". $author->user_login ." | ". $author->display_name ." | ". $author->user_email ."\n";
673
  }
674
+
 
 
 
 
 
675
  die();
676
+
677
  }
678
 
679
  /**
680
  * Get matching authors based on a search value
681
  */
682
+ function search_authors( $search = '', $ignored_authors = array() ) {
683
+
684
+ // Getting all of the users with one query style should allow us to cache it better
685
+ $all_users = get_users( array( 'count_total' => false, 'fields' => 'all_with_meta' ) );
686
+
687
+ // Go through all of the users associated with the site and see which match our query
688
+ // We allow our search query to match against a number of fields
689
+ $found_users = array();
690
+ $search_fields = array(
691
  'ID',
692
  'display_name',
693
+ 'first_name',
694
+ 'last_name',
695
+ 'nickname',
696
+ 'user_email',
697
  'user_login',
698
+ );
699
+ $search_fields = apply_filters( 'coauthors_edit_search_fields', $search_fields );
700
+ foreach( $all_users as $blog_user ) {
 
 
 
 
 
 
701
 
702
+ $search_results = array();
703
+ foreach( $search_fields as $search_field ) {
704
+ if ( false !== stripos( $blog_user->$search_field, $search ) )
705
+ $search_results[$search_field] = true;
706
+ else
707
+ $search_results[$search_field] = false;
708
+ }
709
+ // Don't include the user if 0 of the search fields were true
710
+ if ( !in_array( true, $search_results ) )
711
+ continue;
712
+
713
+ // Make sure the user is contributor and above (or a custom cap)
714
+ if ( $blog_user->has_cap( apply_filters( 'coauthors_edit_author_cap', 'edit_posts' ) ) )
715
+ $found_users[] = $blog_user;
716
+
717
+ }
718
+
719
+ // Allow users to always filter out certain users if needed (e.g. administrators)
720
+ $ignored_authors = apply_filters( 'coauthors_edit_ignored_authors', $ignored_authors );
721
+ foreach( $found_users as $key => $found_user ) {
722
+ if ( in_array( $found_user->user_login, $ignored_authors ) )
723
+ unset( $found_users[$key] );
724
+ }
725
+ return (array) $found_users;
726
  }
727
+
728
  /**
729
  * Functions to add scripts and css
730
  */
733
 
734
  $post_type = $this->get_current_post_type();
735
 
736
+ if ( !$this->is_valid_page() || !$this->authors_supported( $post_type ) || !$this->current_user_can_set_authors() )
737
+ return;
738
 
739
+ wp_enqueue_script( 'jquery' );
740
+ wp_enqueue_script( 'jquery-ui-sortable' );
741
+ wp_enqueue_style( 'co-authors-plus-css', COAUTHORS_PLUS_URL . 'css/co-authors-plus.css', false, COAUTHORS_PLUS_VERSION, 'all' );
742
+ wp_enqueue_script( 'co-authors-plus-js', COAUTHORS_PLUS_URL . 'js/co-authors-plus.js', array('jquery', 'suggest'), COAUTHORS_PLUS_VERSION, true);
743
+
744
+ $js_strings = array(
745
+ 'edit_label' => __( 'Edit', 'co-authors-plus' ),
746
+ 'delete_label' => __( 'Remove', 'co-authors-plus' ),
747
+ 'confirm_delete' => __( 'Are you sure you want to remove this author?', 'co-authors-plus' ),
748
+ 'input_box_title' => __( 'Click to change this author, or drag to change their position', 'co-authors-plus' ),
749
+ 'search_box_text' => __( 'Search for an author', 'co-authors-plus' ),
750
+ 'help_text' => __( 'Click on an author to change them. Drag to change their order. Click on <strong>Remove</strong> to remove them.', 'co-authors-plus' ),
751
+ );
752
+ wp_localize_script( 'co-authors-plus-js', 'coAuthorsPlusStrings', $js_strings );
753
+
 
754
  }
755
 
756
  /**
848
 
849
  return $allcaps;
850
  }
851
+
852
  /**
853
+ * Filter Edit Flow's 'ef_calendar_item_information_fields' to add co-authors
854
+ *
855
+ * @see https://github.com/danielbachhuber/Co-Authors-Plus/issues/2
856
  */
857
+ function filter_ef_calendar_item_information_fields( $information_fields, $post_id ) {
858
+
859
+ // Don't add the author row again if another plugin has removed
860
+ if ( !array_key_exists( 'author', $information_fields ) )
861
+ return $information_fields;
862
+
863
+ $co_authors = get_coauthors( $post_id );
864
+ if ( count( $co_authors ) > 1 )
865
+ $information_fields['author']['label'] = __( 'Authors', 'co-authors-plus' );
866
+ $co_authors_names = '';
867
+ foreach( $co_authors as $co_author ) {
868
+ $co_authors_names .= $co_author->display_name . ', ';
 
 
869
  }
870
+ $information_fields['author']['value'] = rtrim( $co_authors_names, ', ' );
871
+ return $information_fields;
872
  }
873
+
874
+ /**
875
+ * Filter Edit Flow's 'ef_story_budget_term_column_value' to add co-authors to the story budget
876
+ *
877
+ * @see https://github.com/danielbachhuber/Co-Authors-Plus/issues/2
878
+ */
879
+ function filter_ef_story_budget_term_column_value( $column_name, $post, $parent_term ) {
880
+
881
+ // We only want to modify the 'author' column
882
+ if ( 'author' != $column_name )
883
+ return $column_name;
884
+
885
+ $co_authors = get_coauthors( $post->ID );
886
+ $co_authors_names = '';
887
+ foreach( $co_authors as $co_author ) {
888
+ $co_authors_names .= $co_author->display_name . ', ';
889
  }
890
+ return rtrim( $co_authors_names, ', ' );
891
  }
892
+
893
  }
894
 
895
  global $coauthors_plus;
896
  $coauthors_plus = new coauthors_plus();
897
+
898
+ if ( ! function_exists('wp_notify_postauthor') ) :
899
+ /**
900
+ * Notify a co-author of a comment/trackback/pingback to one of their posts.
901
+ * This is a modified version of the core function in wp-includes/pluggable.php that
902
+ * supports notifs to multiple co-authors. Unfortunately, this is the best way to do it :(
903
+ *
904
+ * @since 2.6.2
905
+ *
906
+ * @param int $comment_id Comment ID
907
+ * @param string $comment_type Optional. The comment type either 'comment' (default), 'trackback', or 'pingback'
908
+ * @return bool False if user email does not exist. True on completion.
909
+ */
910
+ function wp_notify_postauthor( $comment_id, $comment_type = '' ) {
911
+ $comment = get_comment( $comment_id );
912
+ $post = get_post( $comment->comment_post_ID );
913
+ $coauthors = get_coauthors( $post->ID );
914
+ foreach( $coauthors as $author ) {
915
+
916
+ // The comment was left by the co-author
917
+ if ( $comment->user_id == $author->ID )
918
+ return false;
919
+
920
+ // The co-author moderated a comment on his own post
921
+ if ( $author->ID == get_current_user_id() )
922
+ return false;
923
+
924
+ // If there's no email to send the comment to
925
+ if ( '' == $author->user_email )
926
+ return false;
927
+
928
+ $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
929
+
930
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
931
+ // we want to reverse this for the plain text arena of emails.
932
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
933
+
934
+ if ( empty( $comment_type ) ) $comment_type = 'comment';
935
+
936
+ if ('comment' == $comment_type) {
937
+ $notify_message = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
938
+ /* translators: 1: comment author, 2: author IP, 3: author domain */
939
+ $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
940
+ $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
941
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
942
+ $notify_message .= sprintf( __('Whois : http://whois.arin.net/rest/ip/%s'), $comment->comment_author_IP ) . "\r\n";
943
+ $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
944
+ $notify_message .= __('You can see all comments on this post here: ') . "\r\n";
945
+ /* translators: 1: blog name, 2: post title */
946
+ $subject = sprintf( __('[%1$s] Comment: "%2$s"'), $blogname, $post->post_title );
947
+ } elseif ('trackback' == $comment_type) {
948
+ $notify_message = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
949
+ /* translators: 1: website name, 2: author IP, 3: author domain */
950
+ $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
951
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
952
+ $notify_message .= __('Excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
953
+ $notify_message .= __('You can see all trackbacks on this post here: ') . "\r\n";
954
+ /* translators: 1: blog name, 2: post title */
955
+ $subject = sprintf( __('[%1$s] Trackback: "%2$s"'), $blogname, $post->post_title );
956
+ } elseif ('pingback' == $comment_type) {
957
+ $notify_message = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
958
+ /* translators: 1: comment author, 2: author IP, 3: author domain */
959
+ $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
960
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
961
+ $notify_message .= __('Excerpt: ') . "\r\n" . sprintf('[...] %s [...]', $comment->comment_content ) . "\r\n\r\n";
962
+ $notify_message .= __('You can see all pingbacks on this post here: ') . "\r\n";
963
+ /* translators: 1: blog name, 2: post title */
964
+ $subject = sprintf( __('[%1$s] Pingback: "%2$s"'), $blogname, $post->post_title );
965
+ }
966
+ $notify_message .= get_permalink($comment->comment_post_ID) . "#comments\r\n\r\n";
967
+ $notify_message .= sprintf( __('Permalink: %s'), get_permalink( $comment->comment_post_ID ) . '#comment-' . $comment_id ) . "\r\n";
968
+ if ( EMPTY_TRASH_DAYS )
969
+ $notify_message .= sprintf( __('Trash it: %s'), admin_url("comment.php?action=trash&c=$comment_id") ) . "\r\n";
970
+ else
971
+ $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=delete&c=$comment_id") ) . "\r\n";
972
+ $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=spam&c=$comment_id") ) . "\r\n";
973
+
974
+ $wp_email = 'wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
975
+
976
+ if ( '' == $comment->comment_author ) {
977
+ $from = "From: \"$blogname\" <$wp_email>";
978
+ if ( '' != $comment->comment_author_email )
979
+ $reply_to = "Reply-To: $comment->comment_author_email";
980
+ } else {
981
+ $from = "From: \"$comment->comment_author\" <$wp_email>";
982
+ if ( '' != $comment->comment_author_email )
983
+ $reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
984
+ }
985
+
986
+ $message_headers = "$from\n"
987
+ . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
988
+
989
+ if ( isset($reply_to) )
990
+ $message_headers .= $reply_to . "\n";
991
+
992
+ $notify_message = apply_filters('comment_notification_text', $notify_message, $comment_id);
993
+ $subject = apply_filters('comment_notification_subject', $subject, $comment_id);
994
+ $message_headers = apply_filters('comment_notification_headers', $message_headers, $comment_id);
995
+
996
+ @wp_mail( $author->user_email, $subject, $notify_message, $message_headers );
997
+ }
998
+
999
+ return true;
1000
+ }
1001
+ endif;
1002
+
1003
+ if ( !function_exists('wp_notify_moderator') ) :
1004
+ /**
1005
+ * Notifies the moderator of the blog about a new comment that is awaiting approval.
1006
+ * This is a modified version of the core function in wp-includes/pluggable.php that
1007
+ * supports notifs to multiple co-authors. Unfortunately, this is the best way to do it :(
1008
+ *
1009
+ * @since 2.6.2
1010
+ *
1011
+ * @param int $comment_id Comment ID
1012
+ * @return bool Always returns true
1013
+ */
1014
+ function wp_notify_moderator( $comment_id ) {
1015
+ global $wpdb;
1016
+
1017
+ if ( 0 == get_option( 'moderation_notify' ) )
1018
+ return true;
1019
+
1020
+ $comment = get_comment($comment_id);
1021
+ $post = get_post($comment->comment_post_ID);
1022
+ $coauthors = get_coauthors( $post->ID );
1023
+ // Send to the administration and to the co-authors if the co-author can modify the comment.
1024
+ $email_to = array( get_option('admin_email') );
1025
+ foreach( $coauthors as $user ) {
1026
+ if ( user_can($user->ID, 'edit_comment', $comment_id) && !empty($user->user_email) && ( get_option('admin_email') != $user->user_email) )
1027
+ $email_to[] = $user->user_email;
1028
+ }
1029
+
1030
+ $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
1031
+ $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
1032
+
1033
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
1034
+ // we want to reverse this for the plain text arena of emails.
1035
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1036
+
1037
+ switch ($comment->comment_type)
1038
+ {
1039
+ case 'trackback':
1040
+ $notify_message = sprintf( __('A new trackback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1041
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1042
+ $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1043
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
1044
+ $notify_message .= __('Trackback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
1045
+ break;
1046
+ case 'pingback':
1047
+ $notify_message = sprintf( __('A new pingback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1048
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1049
+ $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1050
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
1051
+ $notify_message .= __('Pingback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
1052
+ break;
1053
+ default: //Comments
1054
+ $notify_message = sprintf( __('A new comment on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1055
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1056
+ $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1057
+ $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
1058
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
1059
+ $notify_message .= sprintf( __('Whois : http://whois.arin.net/rest/ip/%s'), $comment->comment_author_IP ) . "\r\n";
1060
+ $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
1061
+ break;
1062
+ }
1063
+
1064
+ $notify_message .= sprintf( __('Approve it: %s'), admin_url("comment.php?action=approve&c=$comment_id") ) . "\r\n";
1065
+ if ( EMPTY_TRASH_DAYS )
1066
+ $notify_message .= sprintf( __('Trash it: %s'), admin_url("comment.php?action=trash&c=$comment_id") ) . "\r\n";
1067
+ else
1068
+ $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=delete&c=$comment_id") ) . "\r\n";
1069
+ $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=spam&c=$comment_id") ) . "\r\n";
1070
+
1071
+ $notify_message .= sprintf( _n('Currently %s comment is waiting for approval. Please visit the moderation panel:',
1072
+ 'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting), number_format_i18n($comments_waiting) ) . "\r\n";
1073
+ $notify_message .= admin_url("edit-comments.php?comment_status=moderated") . "\r\n";
1074
+
1075
+ $subject = sprintf( __('[%1$s] Please moderate: "%2$s"'), $blogname, $post->post_title );
1076
+ $message_headers = '';
1077
+
1078
+ $notify_message = apply_filters('comment_moderation_text', $notify_message, $comment_id);
1079
+ $subject = apply_filters('comment_moderation_subject', $subject, $comment_id);
1080
+ $message_headers = apply_filters('comment_moderation_headers', $message_headers);
1081
+
1082
+ foreach ( $email_to as $email )
1083
+ @wp_mail($email, $subject, $notify_message, $message_headers);
1084
+
1085
+ return true;
1086
+ }
1087
+ endif;
js/co-authors-plus.js CHANGED
@@ -10,7 +10,7 @@ jQuery(document).ready(function () {
10
  }
11
  return false;
12
  };
13
-
14
  function coauthors_delete( elem ) {
15
 
16
  var $coauthor_row = jQuery(elem).closest('.coauthor-row');
@@ -432,6 +432,11 @@ jQuery(document).ready(function () {
432
  // Show laoding cursor for autocomplete ajax requests
433
  jQuery(document).ajaxSend(function(e, xhr, settings) {
434
  if( settings.url.indexOf(coAuthorsPlus_ajax_suggest_link) != -1 ) {
 
 
 
 
 
435
  show_loading();
436
  }
437
  });
10
  }
11
  return false;
12
  };
13
+
14
  function coauthors_delete( elem ) {
15
 
16
  var $coauthor_row = jQuery(elem).closest('.coauthor-row');
432
  // Show laoding cursor for autocomplete ajax requests
433
  jQuery(document).ajaxSend(function(e, xhr, settings) {
434
  if( settings.url.indexOf(coAuthorsPlus_ajax_suggest_link) != -1 ) {
435
+ // Including existing authors on the AJAX suggest link
436
+ // allows us to filter them out of the search request
437
+ var existing_authors = jQuery('input[name="coauthors[]"]').map(function(){return jQuery(this).val();}).get();
438
+ settings.url = settings.url.split('&existing_authors')[0];
439
+ settings.url += '&existing_authors=' + existing_authors.join(',');
440
  show_loading();
441
  }
442
  });
readme.txt CHANGED
@@ -1,25 +1,34 @@
1
  === Co-Authors Plus ===
2
- Contributors: batmoo, danielbachhuber
3
  Donate link: http://digitalize.ca/donate
4
  Tags: authors, users, multiple authors, coauthors, multi-author, publishing
5
- Tested up to: 3.3
6
  Requires at least: 3.1
7
- Stable tag: 2.6.1
8
 
9
- Allows multiple authors to be assigned to any post type via a search-as-you-type input box
10
 
11
  == Description ==
12
 
13
- Allows multiple authors to be assigned to a Post, Pages, or Custom Post Types via the search-as-you-type inputs. Co-authored posts appear on a co-author's posts page and feed. New template tags allow listing of co-authors. Editors and Administrators may assign co-authors to a post. Additionally, co-authors may edit the posts they are associated with, and co-authors who are contributors may only edit posts if they have not been published (as is usual).
14
 
15
  This plugin is an almost complete rewrite of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/) (2007). The original plugin was inspired by the 'Multiple Authors' plugin by Mark Jaquith (2005).
16
 
17
- The extended version incorporates search-as-you-type functionality for adding users, which aims to make easy the task of adding multiple users to posts and pages, especially when dealing with a system with hundreds of users (typical of newspaper and magazine sites).
18
-
19
  > *See "Other Notes" section for Template Tags and usage information*
20
 
21
  == Changelog ==
22
 
 
 
 
 
 
 
 
 
 
 
 
23
  = 2011-12-30 / 2.6.1 =
24
 
25
  * Fix mangled usernames because of sanitize_key http://wordpress.org/support/topic/plugin-co-authors-plus-26-not-working-with-wp-33
@@ -128,8 +137,7 @@ The extended version incorporates search-as-you-type functionality for adding us
128
 
129
  == Basic Usage and Other Notes ==
130
 
131
- * Contributor-level and above can be added as co-authors. An option added as of 2.0 allows subscribers to be added as coauthors as well.
132
- * As per WordPress design, only Editor-level and above users can change Post Authors. Authors cannot change authors or add co-authors (yet).
133
  * As per WordPress design, when an editor creates a new Post or Page, they are by default added as an author. However, they can be replaced by clicking on their name and typing in the name of the new author.
134
  * The search-as-you-type box starts searching once two letters have been added, and executes a new search with every subsequent letter.
135
  * The search-as-you-type box searches through the following user fields: a) user login; b) user nicename; c) display name; d) user email; e) first name; f) last name; and g) nickname.
1
  === Co-Authors Plus ===
2
+ Contributors: batmoo, danielbachhuber, automattic
3
  Donate link: http://digitalize.ca/donate
4
  Tags: authors, users, multiple authors, coauthors, multi-author, publishing
5
+ Tested up to: 3.3.1
6
  Requires at least: 3.1
7
+ Stable tag: 2.6.2
8
 
9
+ Allows multiple authors to be assigned to posts, pages, and custom post types via a search-as-you-type input box
10
 
11
  == Description ==
12
 
13
+ Allows multiple authors to be assigned to posts, pagesges, or custom post types via the search-as-you-type inputs. Template tags allow listing of co-authors anywhere you'd normally list the author. Co-authored posts appear on a co-author's archive page and in their feed. Additionally, co-authors may edit the posts they are associated with, and co-authors who are contributors may only edit posts if they have not been published (as is core behavior).
14
 
15
  This plugin is an almost complete rewrite of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/) (2007). The original plugin was inspired by the 'Multiple Authors' plugin by Mark Jaquith (2005).
16
 
 
 
17
  > *See "Other Notes" section for Template Tags and usage information*
18
 
19
  == Changelog ==
20
 
21
+ = 2012-03-06 / 2.6.2 =
22
+ * AJAX user search matches against first name, last name, and nickname fields too, in addition to display name, user login, and email address
23
+ * Comment moderation and approved notifications are properly sent to all co-authors with the correct caps
24
+ * Filter required capability for user to be returned in an AJAX search with 'coauthors_edit_author_cap'
25
+ * Filter out administrators and other non-authors from AJAX search with 'coauthors_edit_ignored_authors'
26
+ * Automatically adds co-authors to Edit Flow's story budget and calendar views
27
+ * Bug fix: Don't set post_author value to current user when quick editing a post. This doesn't appear in the UI anywhere, but adds the post to the current user's list of posts
28
+ * Bug fix: Properly cc other co-authors on new comment email notifications
29
+ * Bug fix: If a user has already been added as an author to a post, don't show them in the AJAX search again
30
+ * Bug fix: Allow output constants to be defined in a theme's functions.php file and include filters you can use instead
31
+
32
  = 2011-12-30 / 2.6.1 =
33
 
34
  * Fix mangled usernames because of sanitize_key http://wordpress.org/support/topic/plugin-co-authors-plus-26-not-working-with-wp-33
137
 
138
  == Basic Usage and Other Notes ==
139
 
140
+ * Contributor-level and above can be added as co-authors.
 
141
  * As per WordPress design, when an editor creates a new Post or Page, they are by default added as an author. However, they can be replaced by clicking on their name and typing in the name of the new author.
142
  * The search-as-you-type box starts searching once two letters have been added, and executes a new search with every subsequent letter.
143
  * The search-as-you-type box searches through the following user fields: a) user login; b) user nicename; c) display name; d) user email; e) first name; f) last name; and g) nickname.
template-tags.php CHANGED
@@ -117,15 +117,23 @@ class CoAuthorsIterator {
117
 
118
  //Helper function for the following new template tags
119
  function coauthors__echo( $tag, $type = 'tag', $separators = array(), $tag_args = null, $echo = true ) {
 
 
 
 
 
 
 
 
 
 
120
  if( ! isset( $separators['between'] ) || $separators['between'] === NULL )
121
- $separators['between'] = COAUTHORS_DEFAULT_BETWEEN;
122
  if( ! isset( $separators['betweenLast'] ) || $separators['betweenLast'] === NULL )
123
- $separators['betweenLast'] = COAUTHORS_DEFAULT_BETWEEN_LAST;
124
- if( ! isset( $separators['before'] ) || $separators['before'] === NULL )
125
- $separators['before'] = COAUTHORS_DEFAULT_BEFORE;
126
  if( ! isset( $separators['after'] ) || $separators['after'] === NULL )
127
- $separators['after'] = COAUTHORS_DEFAULT_AFTER;
128
-
129
  $output = '';
130
 
131
  $i = new CoAuthorsIterator();
117
 
118
  //Helper function for the following new template tags
119
  function coauthors__echo( $tag, $type = 'tag', $separators = array(), $tag_args = null, $echo = true ) {
120
+
121
+ // Define the standard output separator. Constant support is for backwards compat.
122
+ // @see https://github.com/danielbachhuber/Co-Authors-Plus/issues/12
123
+ $default_before = ( defined( 'COAUTHORS_DEFAULT_BEFORE' ) ) ? COAUTHORS_DEFAULT_BEFORE : '';
124
+ $default_between = ( defined( 'COAUTHORS_DEFAULT_BETWEEN' ) ) ? COAUTHORS_DEFAULT_BETWEEN : ', ';
125
+ $default_between_last = ( defined( 'COAUTHORS_DEFAULT_BETWEEN_LAST' ) ) ? COAUTHORS_DEFAULT_BETWEEN_LAST : __( ' and ', 'co-authors-plus' );
126
+ $default_after = ( defined( 'COAUTHORS_DEFAULT_AFTER' ) ) ? COAUTHORS_DEFAULT_AFTER : '';
127
+
128
+ if( ! isset( $separators['before'] ) || $separators['before'] === NULL )
129
+ $separators['before'] = apply_filters( 'coauthors_default_before', $default_before );
130
  if( ! isset( $separators['between'] ) || $separators['between'] === NULL )
131
+ $separators['between'] = apply_filters( 'coauthors_default_between', $default_between );
132
  if( ! isset( $separators['betweenLast'] ) || $separators['betweenLast'] === NULL )
133
+ $separators['betweenLast'] = apply_filters( 'coauthors_default_between_last', $default_between_last );
 
 
134
  if( ! isset( $separators['after'] ) || $separators['after'] === NULL )
135
+ $separators['after'] = apply_filters( 'coauthors_default_after', $default_after );
136
+
137
  $output = '';
138
 
139
  $i = new CoAuthorsIterator();