Co-Authors Plus - Version 3.3.0

Version Description

("Rebecca") = * Fix private post viewing on front-end * Reduce amount of sleep * Author search UX issues * Remove associated guest user when mapped user id deleted. * Removed double left join on posts_join_filter * Fixed WP CLI create-terms-for-posts if no co-authors found * Pages archive now displays coauthors and quick edit works * Terminology updated throughout * Replace hardcoded 'author' with $this->$coauthor_taxonomy * Move parenthesis to fix esc_html and sprintf * Added progress to create-guest-authors so users have an idea of how long it will take * Deleting guest authors is less confusing * Guest author's featured image is avatar now * Removed extra image sizing * Remove duplicated byline * coauthors_wp_list_authors() has option to list only guest authors now * remove duplicates from linked accounts on coauthors_wp_list_authors() * Accurate Guest Author post count on linked accounts * New README.md * Filter author archive * Fix coauthors_links_single() * Added guest author hooks for create/delete * Fixes logic for DOING_AUTOSAVE check * user_login spaces problem when using add_coauthors * Adding details of filter for slow performance * Remove redundant test for 404 on Author Archive * Guest Author Counts are more accurate * Set $coauthors_loading * Fix the issue where guest authors with non-ASCII characters can't be used as co-authors * Fix the issue where incompatibility when coauthors_auto_apply_template_tags set to true * Unit tests/Fix warnings for template tags * Review and improve test coverage * Update class-wp-cli.php * Update .travis.yml file for PHPUnit tests * Changes to resolve issue #332 about missing coauthor meta

Download this release

Release Info

Developer philipjohn
Plugin Icon wp plugin Co-Authors Plus
Version 3.3.0
Comparing to
See all releases

Code changes from version 3.2.2 to 3.3.0

co-authors-plus.php CHANGED
@@ -3,7 +3,7 @@
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: 3.2.2
7
  Author: Mohammad Jangda, Daniel Bachhuber, Automattic
8
  Copyright: 2008-2015 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
@@ -22,9 +22,17 @@ You should have received a copy of the GNU General Public License
22
  along with this program; if not, write to the Free Software
23
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
 
 
 
 
 
 
 
 
 
25
  */
26
 
27
- define( 'COAUTHORS_PLUS_VERSION', '3.2.2' );
28
 
29
  require_once( dirname( __FILE__ ) . '/template-tags.php' );
30
  require_once( dirname( __FILE__ ) . '/deprecated.php' );
@@ -39,7 +47,7 @@ if ( defined( 'WP_CLI' ) && WP_CLI ) {
39
  class CoAuthors_Plus {
40
 
41
  // Name for the taxonomy we're using to store relationships
42
- // and the post type we're using to store co-authors
43
  var $coauthor_taxonomy = 'author';
44
 
45
  var $coreauthors_meta_box_name = 'authordiv';
@@ -68,38 +76,38 @@ class CoAuthors_Plus {
68
  // Load admin_init function
69
  add_action( 'admin_init', array( $this, 'admin_init' ) );
70
 
71
- // Modify SQL queries to include coauthors
72
  add_filter( 'posts_where', array( $this, 'posts_where_filter' ), 10, 2 );
73
  add_filter( 'posts_join', array( $this, 'posts_join_filter' ), 10, 2 );
74
  add_filter( 'posts_groupby', array( $this, 'posts_groupby_filter' ), 10, 2 );
75
 
76
- // Action to set users when a post is saved
77
  add_action( 'save_post', array( $this, 'coauthors_update_post' ), 10, 2 );
78
  // Filter to set the post_author field when wp_insert_post is called
79
  add_filter( 'wp_insert_post_data', array( $this, 'coauthors_set_post_author_field' ), 10, 2 );
80
 
81
- // Action to reassign posts when a user is deleted
82
  add_action( 'delete_user', array( $this, 'delete_user_action' ) );
83
 
84
  add_filter( 'get_usernumposts', array( $this, 'filter_count_user_posts' ), 10, 2 );
85
 
86
- // Action to set up author auto-suggest
87
  add_action( 'wp_ajax_coauthors_ajax_suggest', array( $this, 'ajax_suggest' ) );
88
 
89
- // Filter to allow coauthors to edit posts
90
  add_filter( 'user_has_cap', array( $this, 'filter_user_has_cap' ), 10, 3 );
91
 
92
- // Handle the custom author meta box
93
  add_action( 'add_meta_boxes', array( $this, 'add_coauthors_box' ) );
94
  add_action( 'add_meta_boxes', array( $this, 'remove_authors_box' ) );
95
 
96
- // Removes the author dropdown from the post quick edit
97
  add_action( 'admin_head', array( $this, 'remove_quick_edit_authors_box' ) );
98
 
99
  // Restricts WordPress from blowing away term order on bulk edit
100
  add_filter( 'wp_get_object_terms', array( $this, 'filter_wp_get_object_terms' ), 10, 4 );
101
 
102
- // Make sure we've correctly set author data on author pages
103
  add_filter( 'posts_selection', array( $this, 'fix_author_page' ) ); // use posts_selection since it's after WP_Query has built the request and before it's queried any posts
104
  add_action( 'the_post', array( $this, 'fix_author_page' ) );
105
 
@@ -110,16 +118,19 @@ class CoAuthors_Plus {
110
  // Support Jetpack Open Graph Tags
111
  add_filter( 'jetpack_open_graph_tags', array( $this, 'filter_jetpack_open_graph_tags' ), 10, 2 );
112
 
113
- // Filter to send comment moderation notification e-mail to multiple authors
114
  add_filter( 'comment_moderation_recipients', 'cap_filter_comment_moderation_email_recipients', 10, 2 );
115
 
116
  // Support infinite scroll for Guest Authors on author pages
117
  add_filter( 'infinite_scroll_js_settings', array( $this, 'filter_infinite_scroll_js_settings' ), 10, 2 );
118
 
119
- // Delete CoAuthor Cache on Post Save & Post Delete
120
  add_action( 'save_post', array( $this, 'clear_cache') );
121
  add_action( 'delete_post', array( $this, 'clear_cache') );
122
  add_action( 'set_object_terms', array( $this, 'clear_cache_on_terms_set' ), 10, 6 );
 
 
 
123
  }
124
 
125
  /**
@@ -174,7 +185,7 @@ class CoAuthors_Plus {
174
 
175
  $post_types_with_authors = array_values( get_post_types() );
176
  foreach ( $post_types_with_authors as $key => $name ) {
177
- if ( ! post_type_supports( $name, 'author' ) || in_array( $name, array( 'revision', 'attachment' ) ) ) {
178
  unset( $post_types_with_authors[ $key ] );
179
  }
180
  }
@@ -193,13 +204,13 @@ class CoAuthors_Plus {
193
  // Add necessary JS variables
194
  add_action( 'admin_head', array( $this, 'js_vars' ) );
195
 
196
- // Hooks to add additional coauthors to author column to Edit page
197
  add_filter( 'manage_posts_columns', array( $this, '_filter_manage_posts_columns' ) );
198
  add_filter( 'manage_pages_columns', array( $this, '_filter_manage_posts_columns' ) );
199
  add_action( 'manage_posts_custom_column', array( $this, '_filter_manage_posts_custom_column' ) );
200
  add_action( 'manage_pages_custom_column', array( $this, '_filter_manage_posts_custom_column' ) );
201
 
202
- // Add quick-edit author select field
203
  add_action( 'quick_edit_custom_box', array( $this, '_action_quick_edit_custom_box' ), 10, 2 );
204
 
205
  // Hooks to modify the published post number count on the Users WP List Table
@@ -225,7 +236,7 @@ class CoAuthors_Plus {
225
  }
226
 
227
  /**
228
- * Get a co-author object by a specific type of key
229
  *
230
  * @param string $key Key to search by (slug,email)
231
  * @param string $value Value to search for
@@ -294,14 +305,17 @@ class CoAuthors_Plus {
294
 
295
  if ( ! $post_type ) {
296
  $post_type = get_post_type();
 
 
 
297
  }
298
 
299
  return (bool) in_array( $post_type, $this->supported_post_types );
300
  }
301
 
302
  /**
303
- * Removes the standard WordPress Author box.
304
- * We don't need it because the Co-Authors one is way cooler.
305
  */
306
  public function remove_authors_box() {
307
 
@@ -311,7 +325,7 @@ class CoAuthors_Plus {
311
  }
312
 
313
  /**
314
- * Adds a custom Authors box
315
  */
316
  public function add_coauthors_box() {
317
 
@@ -321,7 +335,7 @@ class CoAuthors_Plus {
321
  }
322
 
323
  /**
324
- * Callback for adding the custom author box
325
  */
326
  public function coauthors_meta_box( $post ) {
327
  global $post, $coauthors_plus, $current_screen;
@@ -395,18 +409,18 @@ class CoAuthors_Plus {
395
  }
396
 
397
  /**
398
- * Removes the author dropdown from the post quick edit
399
  */
400
  function remove_quick_edit_authors_box() {
401
  global $pagenow;
402
 
403
  if ( 'edit.php' == $pagenow && $this->is_post_type_enabled() ) {
404
- remove_post_type_support( get_post_type(), 'author' );
405
  }
406
  }
407
 
408
  /**
409
- * Add coauthors to author column on edit pages
410
  *
411
  * @param array $post_columns
412
  */
@@ -423,7 +437,7 @@ class CoAuthors_Plus {
423
  $new_columns['coauthors'] = __( 'Authors', 'co-authors-plus' );
424
  }
425
 
426
- if ( 'author' === $key ) {
427
  unset( $new_columns[ $key ] );
428
  }
429
  }
@@ -431,7 +445,7 @@ class CoAuthors_Plus {
431
  }
432
 
433
  /**
434
- * Insert coauthors into post rows on Edit Page
435
  *
436
  * @param string $column_name
437
  */
@@ -518,7 +532,7 @@ class CoAuthors_Plus {
518
  }
519
 
520
  /**
521
- * When we update the terms at all, we should update the published post count for each author
522
  */
523
  function _update_users_posts_count( $tt_ids, $taxonomy ) {
524
  global $wpdb;
@@ -616,10 +630,9 @@ class CoAuthors_Plus {
616
 
617
  // Check to see that JOIN hasn't already been added. Props michaelingp and nbaxley
618
  $term_relationship_inner_join = " INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
619
- $term_relationship_left_join = " LEFT JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
620
 
621
- $term_taxonomy_join = " INNER JOIN {$wpdb->term_relationships} AS tr1 ON ({$wpdb->posts}.ID = tr1.object_id)";
622
- $term_taxonomy_join .= " INNER JOIN {$wpdb->term_taxonomy} ON ( tr1.term_taxonomy_id = {$wpdb->term_taxonomy}.term_taxonomy_id )";
623
 
624
  // 4.6+ uses a LEFT JOIN for tax queries so we need to check for both
625
  if ( false === strpos( $join, trim( $term_relationship_inner_join ) )
@@ -650,7 +663,7 @@ class CoAuthors_Plus {
650
  if ( $query->get( 'author_name' ) ) {
651
  $author_name = sanitize_title( $query->get( 'author_name' ) );
652
  } else {
653
- $author_data = get_userdata( $query->get( 'author' ) );
654
  if ( is_object( $author_data ) ) {
655
  $author_name = $author_data->user_nicename;
656
  } else {
@@ -663,7 +676,7 @@ class CoAuthors_Plus {
663
  if ( $author_term = $this->get_author_term( $coauthor ) ) {
664
  $terms[] = $author_term;
665
  }
666
- // If this coauthor has a linked account, we also need to get posts with those terms
667
  if ( ! empty( $coauthor->linked_account ) ) {
668
  $linked_account = get_user_by( 'login', $coauthor->linked_account );
669
  if ( $guest_author_term = $this->get_author_term( $linked_account ) ) {
@@ -689,8 +702,37 @@ class CoAuthors_Plus {
689
  $this->having_terms .= ' ' . $wpdb->term_taxonomy .'.term_id = \''. $term->term_id .'\' OR ';
690
  }
691
  $terms_implode = rtrim( $terms_implode, ' OR' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
  $this->having_terms = rtrim( $this->having_terms, ' OR' );
693
- $where = preg_replace( '/(\b(?:' . $wpdb->posts . '\.)?post_author\s*=\s*(\d+))/', '(' . $maybe_both_query . ' ' . $terms_implode . ')', $where, -1 ); #' . $wpdb->postmeta . '.meta_id IS NOT NULL AND
694
  }
695
  }
696
  return $where;
@@ -722,7 +764,7 @@ class CoAuthors_Plus {
722
  function coauthors_set_post_author_field( $data, $postarr ) {
723
 
724
  // Bail on autosave
725
- if ( defined( 'DOING_AUTOSAVE' ) && ! DOING_AUTOSAVE ) {
726
  return $data;
727
  }
728
 
@@ -733,7 +775,10 @@ class CoAuthors_Plus {
733
 
734
  // This action happens when a post is saved while editing a post
735
  if ( isset( $_REQUEST['coauthors-nonce'] ) && isset( $_POST['coauthors'] ) && is_array( $_POST['coauthors'] ) ) {
736
- $author = sanitize_text_field( $_POST['coauthors'][0] );
 
 
 
737
  if ( $author ) {
738
  $author_data = $this->get_coauthor_by( 'user_nicename', $author );
739
  // If it's a guest author and has a linked account, store that information in post_author
@@ -746,7 +791,7 @@ class CoAuthors_Plus {
746
  }
747
  }
748
 
749
- // If for some reason we don't have the coauthors fields set
750
  if ( ! isset( $data['post_author'] ) ) {
751
  $user = wp_get_current_user();
752
  $data['post_author'] = $user->ID;
@@ -765,7 +810,7 @@ class CoAuthors_Plus {
765
  */
766
  function coauthors_update_post( $post_id, $post ) {
767
 
768
- if ( defined( 'DOING_AUTOSAVE' ) && ! DOING_AUTOSAVE ) {
769
  return;
770
  }
771
 
@@ -779,7 +824,7 @@ class CoAuthors_Plus {
779
  check_admin_referer( 'coauthors-edit', 'coauthors-nonce' );
780
 
781
  $coauthors = (array) $_POST['coauthors'];
782
- $coauthors = array_map( 'sanitize_text_field', $coauthors );
783
  $this->add_coauthors( $post_id, $coauthors );
784
  }
785
  } else {
@@ -787,7 +832,7 @@ class CoAuthors_Plus {
787
  if ( ! $this->has_author_terms( $post_id ) ) {
788
  $user = get_userdata( $post->post_author );
789
  if ( $user ) {
790
- $this->add_coauthors( $post_id, array( $user->user_login ) );
791
  }
792
  }
793
  }
@@ -823,7 +868,7 @@ class CoAuthors_Plus {
823
  $coauthors = array( $current_user->user_login );
824
  }
825
 
826
- // Set the coauthors
827
  $coauthors = array_unique( array_merge( $existing_coauthors, $coauthors ) );
828
  $coauthor_objects = array();
829
  foreach ( $coauthors as &$author_name ) {
@@ -859,9 +904,9 @@ class CoAuthors_Plus {
859
  }
860
 
861
  /**
862
- * Action taken when user is deleted.
863
- * - User term is removed from all associated posts
864
- * - Option to specify alternate user in place for each post
865
  * @param delete_id
866
  */
867
  function delete_user_action( $delete_id ) {
@@ -873,13 +918,13 @@ class CoAuthors_Plus {
873
  if ( $reassign_id ) {
874
  // Get posts belonging to deleted author
875
  $reassign_user = get_user_by( 'id', $reassign_id );
876
- // Set to new author
877
  if ( is_object( $reassign_user ) ) {
878
  $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $delete_id ) );
879
 
880
  if ( $post_ids ) {
881
  foreach ( $post_ids as $post_id ) {
882
- $this->add_coauthors( $post_id, array( $reassign_user->user_login ), true );
883
  }
884
  }
885
  }
@@ -890,17 +935,27 @@ class CoAuthors_Plus {
890
  // Delete term
891
  wp_delete_term( $delete_user->user_login, $this->coauthor_taxonomy );
892
  }
 
 
 
 
 
 
 
 
 
 
 
893
  }
894
 
895
  /**
896
- * Restrict WordPress from blowing away author order when bulk editing terms
897
  *
898
  * @since 2.6
899
  * @props kingkool68, http://wordpress.org/support/topic/plugin-co-authors-plus-making-authors-sortable
900
  */
901
  function filter_wp_get_object_terms( $terms, $object_ids, $taxonomies, $args ) {
902
-
903
- if ( ! isset( $_REQUEST['bulk_edit'] ) || "'author'" !== $taxonomies ) {
904
  return $terms;
905
  }
906
 
@@ -943,8 +998,15 @@ class CoAuthors_Plus {
943
  $user = $this->get_coauthor_by( 'user_nicename', $user->user_nicename );
944
 
945
  $term = $this->get_author_term( $user );
946
- // Only modify the count if the author already exists as a term
947
- if ( $term && ! is_wp_error( $term ) ) {
 
 
 
 
 
 
 
948
  $count = $term->count;
949
  }
950
 
@@ -952,7 +1014,7 @@ class CoAuthors_Plus {
952
  }
953
 
954
  /**
955
- * Checks to see if the current user can set authors or not
956
  */
957
  function current_user_can_set_authors( $post = null ) {
958
  global $typenow;
@@ -960,11 +1022,17 @@ class CoAuthors_Plus {
960
  if ( ! $post ) {
961
  $post = get_post();
962
  if ( ! $post ) {
963
- return false;
 
 
 
 
 
964
  }
965
  }
966
-
967
- $post_type = $post->post_type;
 
968
 
969
  // TODO: need to fix this; shouldn't just say no if don't have post_type
970
  if ( ! $post_type ) {
@@ -989,12 +1057,12 @@ class CoAuthors_Plus {
989
  /**
990
  * Fix for author pages 404ing or not properly displaying on author pages
991
  *
992
- * If an author has no posts, we only want to force the queried object to be
993
- * the author if they're a member of the blog.
994
  *
995
- * If the author does have posts, it doesn't matter that they're not an author.
996
  *
997
- * Alternatively, on an author archive, if the first story has coauthors and
998
  * the first author is NOT the same as the author for the archive,
999
  * the query_var is changed.
1000
  *
@@ -1020,10 +1088,10 @@ class CoAuthors_Plus {
1020
  $term = $this->get_author_term( $authordata );
1021
  }
1022
 
1023
- if ( ( is_object( $authordata ) )
1024
- || ( ! empty( $term ) && $term->count ) ) {
1025
  $wp_query->queried_object = $authordata;
1026
  $wp_query->queried_object_id = $authordata->ID;
 
1027
  } else {
1028
  $wp_query->queried_object = $wp_query->queried_object_id = null;
1029
  $wp_query->is_author = $wp_query->is_archive = false;
@@ -1049,7 +1117,7 @@ class CoAuthors_Plus {
1049
  $author = get_queried_object();
1050
 
1051
  if ( $author && 'guest-author' == $author->type ) {
1052
- unset( $settings['query_args']['author'] );
1053
 
1054
  $settings['query_args']['author_name'] = $author->user_nicename;
1055
  }
@@ -1058,7 +1126,7 @@ class CoAuthors_Plus {
1058
  }
1059
 
1060
  /**
1061
- * Main function that handles search-as-you-type for adding authors
1062
  */
1063
  public function ajax_suggest() {
1064
 
@@ -1075,8 +1143,11 @@ class CoAuthors_Plus {
1075
 
1076
  $authors = $this->search_authors( $search, $ignore );
1077
 
 
 
 
1078
  foreach ( $authors as $author ) {
1079
- echo esc_html( $author->ID . ' | ' . $author->user_login . ' | ' . $author->display_name . ' | ' . $author->user_email . ' | ' . $author->user_nicename ) . "\n";
1080
  }
1081
 
1082
  die();
@@ -1084,7 +1155,7 @@ class CoAuthors_Plus {
1084
  }
1085
 
1086
  /**
1087
- * Get matching authors based on a search value
1088
  */
1089
  public function search_authors( $search = '', $ignored_authors = array() ) {
1090
 
@@ -1128,7 +1199,7 @@ class CoAuthors_Plus {
1128
  return array();
1129
  }
1130
 
1131
- // Get the co-author objects
1132
  $found_users = array();
1133
  foreach ( $found_terms as $found_term ) {
1134
  $found_user = $this->get_coauthor_by( 'user_nicename', $found_term->slug );
@@ -1153,7 +1224,7 @@ class CoAuthors_Plus {
1153
  /**
1154
  * Modify get_users() to search display_name instead of user_nicename
1155
  */
1156
- function action_pre_user_query( &$user_query ) {
1157
 
1158
  if ( is_object( $user_query ) ) {
1159
  $user_query->query_where = str_replace( 'user_nicename LIKE', 'display_name LIKE', $user_query->query_where );
@@ -1279,7 +1350,7 @@ class CoAuthors_Plus {
1279
  }
1280
 
1281
  /**
1282
- * Allows coauthors to edit the post they're coauthors of
1283
  */
1284
  function filter_user_has_cap( $allcaps, $caps, $args ) {
1285
 
@@ -1339,10 +1410,19 @@ class CoAuthors_Plus {
1339
  return $term;
1340
  }
1341
 
1342
- // See if the prefixed term is available, otherwise default to just the nicename
1343
- $term = get_term_by( 'slug', 'cap-' . $coauthor->user_nicename, $this->coauthor_taxonomy );
1344
- if ( ! $term ) {
1345
- $term = get_term_by( 'slug', $coauthor->user_nicename, $this->coauthor_taxonomy );
 
 
 
 
 
 
 
 
 
1346
  }
1347
  wp_cache_set( $cache_key, $term, 'co-authors-plus' );
1348
  return $term;
@@ -1398,19 +1478,19 @@ class CoAuthors_Plus {
1398
  function filter_ef_calendar_item_information_fields( $information_fields, $post_id ) {
1399
 
1400
  // Don't add the author row again if another plugin has removed
1401
- if ( ! array_key_exists( 'author', $information_fields ) ) {
1402
  return $information_fields;
1403
  }
1404
 
1405
  $co_authors = get_coauthors( $post_id );
1406
  if ( count( $co_authors ) > 1 ) {
1407
- $information_fields['author']['label'] = __( 'Authors', 'co-authors-plus' );
1408
  }
1409
  $co_authors_names = '';
1410
  foreach ( $co_authors as $co_author ) {
1411
  $co_authors_names .= $co_author->display_name . ', ';
1412
  }
1413
- $information_fields['author']['value'] = rtrim( $co_authors_names, ', ' );
1414
  return $information_fields;
1415
  }
1416
 
@@ -1427,7 +1507,7 @@ class CoAuthors_Plus {
1427
  function filter_ef_story_budget_term_column_value( $column_name, $post, $parent_term ) {
1428
 
1429
  // We only want to modify the 'author' column
1430
- if ( 'author' != $column_name ) {
1431
  return $column_name;
1432
  }
1433
 
@@ -1475,12 +1555,12 @@ class CoAuthors_Plus {
1475
  }
1476
 
1477
  /**
1478
- * Retrieve a list of coauthor terms for a single post.
1479
  *
1480
- * Grabs a correctly ordered list of authors for a single post, appropriately
1481
  * cached because it requires `wp_get_object_terms()` to succeed.
1482
  *
1483
- * @param int $post_id ID of the post for which to retrieve authors.
1484
  * @return array Array of coauthor WP_Term objects
1485
  */
1486
  public function get_coauthor_terms_for_post( $post_id ) {
@@ -1535,6 +1615,15 @@ class CoAuthors_Plus {
1535
 
1536
  }
1537
 
 
 
 
 
 
 
 
 
 
1538
  }
1539
 
1540
  global $coauthors_plus;
@@ -1680,7 +1769,7 @@ function cap_filter_comment_moderation_email_recipients( $recipients, $comment_i
1680
  }
1681
 
1682
  /**
1683
- * Retrieve a list of coauthor terms for a single post.
1684
  *
1685
  * Grabs a correctly ordered list of authors for a single post, appropriately
1686
  * cached because it requires `wp_get_object_terms()` to succeed.
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: 3.3.0
7
  Author: Mohammad Jangda, Daniel Bachhuber, Automattic
8
  Copyright: 2008-2015 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
22
  along with this program; if not, write to the Free Software
23
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
 
25
+ -----------------
26
+
27
+ Glossary:
28
+
29
+ User - a WordPress user account
30
+ Guest author - a CAP-created co-author
31
+ Co-author - in the context of a single post, a guest author or user assigned to the post alongside others
32
+ Author - user with the role of author
33
  */
34
 
35
+ define( 'COAUTHORS_PLUS_VERSION', '3.3.0' );
36
 
37
  require_once( dirname( __FILE__ ) . '/template-tags.php' );
38
  require_once( dirname( __FILE__ ) . '/deprecated.php' );
47
  class CoAuthors_Plus {
48
 
49
  // Name for the taxonomy we're using to store relationships
50
+ // and the post type we're using to store guest authors
51
  var $coauthor_taxonomy = 'author';
52
 
53
  var $coreauthors_meta_box_name = 'authordiv';
76
  // Load admin_init function
77
  add_action( 'admin_init', array( $this, 'admin_init' ) );
78
 
79
+ // Modify SQL queries to include guest authors
80
  add_filter( 'posts_where', array( $this, 'posts_where_filter' ), 10, 2 );
81
  add_filter( 'posts_join', array( $this, 'posts_join_filter' ), 10, 2 );
82
  add_filter( 'posts_groupby', array( $this, 'posts_groupby_filter' ), 10, 2 );
83
 
84
+ // Action to set co-authors when a post is saved
85
  add_action( 'save_post', array( $this, 'coauthors_update_post' ), 10, 2 );
86
  // Filter to set the post_author field when wp_insert_post is called
87
  add_filter( 'wp_insert_post_data', array( $this, 'coauthors_set_post_author_field' ), 10, 2 );
88
 
89
+ // Action to reassign posts when a guest author is deleted
90
  add_action( 'delete_user', array( $this, 'delete_user_action' ) );
91
 
92
  add_filter( 'get_usernumposts', array( $this, 'filter_count_user_posts' ), 10, 2 );
93
 
94
+ // Action to set up co-author auto-suggest
95
  add_action( 'wp_ajax_coauthors_ajax_suggest', array( $this, 'ajax_suggest' ) );
96
 
97
+ // Filter to allow co-authors to edit posts
98
  add_filter( 'user_has_cap', array( $this, 'filter_user_has_cap' ), 10, 3 );
99
 
100
+ // Handle the custom co-author meta box
101
  add_action( 'add_meta_boxes', array( $this, 'add_coauthors_box' ) );
102
  add_action( 'add_meta_boxes', array( $this, 'remove_authors_box' ) );
103
 
104
+ // Removes the co-author dropdown from the post quick edit
105
  add_action( 'admin_head', array( $this, 'remove_quick_edit_authors_box' ) );
106
 
107
  // Restricts WordPress from blowing away term order on bulk edit
108
  add_filter( 'wp_get_object_terms', array( $this, 'filter_wp_get_object_terms' ), 10, 4 );
109
 
110
+ // Make sure we've correctly set data on guest author pages
111
  add_filter( 'posts_selection', array( $this, 'fix_author_page' ) ); // use posts_selection since it's after WP_Query has built the request and before it's queried any posts
112
  add_action( 'the_post', array( $this, 'fix_author_page' ) );
113
 
118
  // Support Jetpack Open Graph Tags
119
  add_filter( 'jetpack_open_graph_tags', array( $this, 'filter_jetpack_open_graph_tags' ), 10, 2 );
120
 
121
+ // Filter to send comment moderation notification e-mail to multiple co-authors
122
  add_filter( 'comment_moderation_recipients', 'cap_filter_comment_moderation_email_recipients', 10, 2 );
123
 
124
  // Support infinite scroll for Guest Authors on author pages
125
  add_filter( 'infinite_scroll_js_settings', array( $this, 'filter_infinite_scroll_js_settings' ), 10, 2 );
126
 
127
+ // Delete Co-Author Cache on Post Save & Post Delete
128
  add_action( 'save_post', array( $this, 'clear_cache') );
129
  add_action( 'delete_post', array( $this, 'clear_cache') );
130
  add_action( 'set_object_terms', array( $this, 'clear_cache_on_terms_set' ), 10, 6 );
131
+
132
+ // Filter to correct author on author archive page
133
+ add_filter( 'get_the_archive_title', array( $this, 'filter_author_archive_title'), 10, 2 );
134
  }
135
 
136
  /**
185
 
186
  $post_types_with_authors = array_values( get_post_types() );
187
  foreach ( $post_types_with_authors as $key => $name ) {
188
+ if ( ! post_type_supports( $name, $this->coauthor_taxonomy ) || in_array( $name, array( 'revision', 'attachment' ) ) ) {
189
  unset( $post_types_with_authors[ $key ] );
190
  }
191
  }
204
  // Add necessary JS variables
205
  add_action( 'admin_head', array( $this, 'js_vars' ) );
206
 
207
+ // Hooks to add additional co-authors to 'authors' column to edit page
208
  add_filter( 'manage_posts_columns', array( $this, '_filter_manage_posts_columns' ) );
209
  add_filter( 'manage_pages_columns', array( $this, '_filter_manage_posts_columns' ) );
210
  add_action( 'manage_posts_custom_column', array( $this, '_filter_manage_posts_custom_column' ) );
211
  add_action( 'manage_pages_custom_column', array( $this, '_filter_manage_posts_custom_column' ) );
212
 
213
+ // Add quick-edit co-author select field
214
  add_action( 'quick_edit_custom_box', array( $this, '_action_quick_edit_custom_box' ), 10, 2 );
215
 
216
  // Hooks to modify the published post number count on the Users WP List Table
236
  }
237
 
238
  /**
239
+ * Get a guest author object by a specific type of key
240
  *
241
  * @param string $key Key to search by (slug,email)
242
  * @param string $value Value to search for
305
 
306
  if ( ! $post_type ) {
307
  $post_type = get_post_type();
308
+ if ( is_admin() && ! $post_type) {
309
+ $post_type = get_current_screen()->post_type;
310
+ }
311
  }
312
 
313
  return (bool) in_array( $post_type, $this->supported_post_types );
314
  }
315
 
316
  /**
317
+ * Removes the standard WordPress 'Author' box.
318
+ * We don't need it because the Co-Authors Plus one is way cooler.
319
  */
320
  public function remove_authors_box() {
321
 
325
  }
326
 
327
  /**
328
+ * Adds a custom 'Authors' box
329
  */
330
  public function add_coauthors_box() {
331
 
335
  }
336
 
337
  /**
338
+ * Callback for adding the custom 'Authors' box
339
  */
340
  public function coauthors_meta_box( $post ) {
341
  global $post, $coauthors_plus, $current_screen;
409
  }
410
 
411
  /**
412
+ * Removes the default 'author' dropdown from quick edit
413
  */
414
  function remove_quick_edit_authors_box() {
415
  global $pagenow;
416
 
417
  if ( 'edit.php' == $pagenow && $this->is_post_type_enabled() ) {
418
+ remove_post_type_support( get_post_type(), $this->coauthor_taxonomy );
419
  }
420
  }
421
 
422
  /**
423
+ * Add co-authors to 'authors' column on edit pages
424
  *
425
  * @param array $post_columns
426
  */
437
  $new_columns['coauthors'] = __( 'Authors', 'co-authors-plus' );
438
  }
439
 
440
+ if ( $this->coauthor_taxonomy === $key ) {
441
  unset( $new_columns[ $key ] );
442
  }
443
  }
445
  }
446
 
447
  /**
448
+ * Insert co-authors into post rows on Edit Page
449
  *
450
  * @param string $column_name
451
  */
532
  }
533
 
534
  /**
535
+ * When we update the terms at all, we should update the published post count for each user
536
  */
537
  function _update_users_posts_count( $tt_ids, $taxonomy ) {
538
  global $wpdb;
630
 
631
  // Check to see that JOIN hasn't already been added. Props michaelingp and nbaxley
632
  $term_relationship_inner_join = " INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
633
+ $term_relationship_left_join = " LEFT JOIN {$wpdb->term_relationships} AS tr1 ON ({$wpdb->posts}.ID = tr1.object_id)";
634
 
635
+ $term_taxonomy_join = " INNER JOIN {$wpdb->term_taxonomy} ON ( tr1.term_taxonomy_id = {$wpdb->term_taxonomy}.term_taxonomy_id )";
 
636
 
637
  // 4.6+ uses a LEFT JOIN for tax queries so we need to check for both
638
  if ( false === strpos( $join, trim( $term_relationship_inner_join ) )
663
  if ( $query->get( 'author_name' ) ) {
664
  $author_name = sanitize_title( $query->get( 'author_name' ) );
665
  } else {
666
+ $author_data = get_userdata( $query->get( $this->coauthor_taxonomy ) );
667
  if ( is_object( $author_data ) ) {
668
  $author_name = $author_data->user_nicename;
669
  } else {
676
  if ( $author_term = $this->get_author_term( $coauthor ) ) {
677
  $terms[] = $author_term;
678
  }
679
+ // If this co-author has a linked account, we also need to get posts with those terms
680
  if ( ! empty( $coauthor->linked_account ) ) {
681
  $linked_account = get_user_by( 'login', $coauthor->linked_account );
682
  if ( $guest_author_term = $this->get_author_term( $linked_account ) ) {
702
  $this->having_terms .= ' ' . $wpdb->term_taxonomy .'.term_id = \''. $term->term_id .'\' OR ';
703
  }
704
  $terms_implode = rtrim( $terms_implode, ' OR' );
705
+
706
+ $id = is_author() ? get_queried_object_id() : '\d+';
707
+
708
+ // When WordPress generates query as 'post_author IN (id)'.
709
+ if ( false !== strpos( $where, "{$wpdb->posts}.post_author IN " ) ) {
710
+
711
+ $maybe_both_query = $maybe_both ? '$0 OR' : '';
712
+
713
+ $where = preg_replace( '/\s\b(?:' . $wpdb->posts . '\.)?post_author\s*IN\s*(.*' . $id . '.)/', ' (' . $maybe_both_query . ' ' . $terms_implode . ')', $where, -1 ); #' . $wpdb->postmeta . '.meta_id IS NOT NULL AND
714
+
715
+ } else {
716
+ $where = preg_replace( '/(\b(?:' . $wpdb->posts . '\.)?post_author\s*=\s*(' . $id . '))/', '(' . $maybe_both_query . ' ' . $terms_implode . ')', $where, -1 ); #' . $wpdb->postmeta . '.meta_id IS NOT NULL AND
717
+ }
718
+
719
+ // the block targets the private posts clause (if it exists)
720
+ if (
721
+ is_user_logged_in() &&
722
+ is_author() &&
723
+ get_queried_object_id() != get_current_user_id()
724
+ ) {
725
+ $current_coauthor = $this->get_coauthor_by( 'user_nicename', wp_get_current_user()->user_nicename );
726
+ $current_coauthor_term = $this->get_author_term( $current_coauthor );
727
+
728
+ $current_user_query = $wpdb->term_taxonomy . '.taxonomy = \''. $this->coauthor_taxonomy.'\' AND '. $wpdb->term_taxonomy .'.term_id = \''. $current_coauthor_term->term_id .'\'';
729
+ $this->having_terms .= ' ' . $wpdb->term_taxonomy .'.term_id = \''. $current_coauthor_term->term_id .'\' OR ';
730
+
731
+ $where = preg_replace( '/(\b(?:' . $wpdb->posts . '\.)?post_author\s*=\s*(' . get_current_user_id() . '))/', $current_user_query, $where, -1 ); #' . $wpdb->postmeta . '.meta_id IS NOT NULL AND
732
+ }
733
+
734
  $this->having_terms = rtrim( $this->having_terms, ' OR' );
735
+
736
  }
737
  }
738
  return $where;
764
  function coauthors_set_post_author_field( $data, $postarr ) {
765
 
766
  // Bail on autosave
767
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
768
  return $data;
769
  }
770
 
775
 
776
  // This action happens when a post is saved while editing a post
777
  if ( isset( $_REQUEST['coauthors-nonce'] ) && isset( $_POST['coauthors'] ) && is_array( $_POST['coauthors'] ) ) {
778
+
779
+ // rawurlencode() is for encoding coauthor name with special characters to compare names when getting coauthor.
780
+ $author = rawurlencode( sanitize_text_field( $_POST['coauthors'][0] ) );
781
+
782
  if ( $author ) {
783
  $author_data = $this->get_coauthor_by( 'user_nicename', $author );
784
  // If it's a guest author and has a linked account, store that information in post_author
791
  }
792
  }
793
 
794
+ // If for some reason we don't have the co-authors fields set
795
  if ( ! isset( $data['post_author'] ) ) {
796
  $user = wp_get_current_user();
797
  $data['post_author'] = $user->ID;
810
  */
811
  function coauthors_update_post( $post_id, $post ) {
812
 
813
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
814
  return;
815
  }
816
 
824
  check_admin_referer( 'coauthors-edit', 'coauthors-nonce' );
825
 
826
  $coauthors = (array) $_POST['coauthors'];
827
+ $coauthors = array_map( 'sanitize_title', $coauthors );
828
  $this->add_coauthors( $post_id, $coauthors );
829
  }
830
  } else {
832
  if ( ! $this->has_author_terms( $post_id ) ) {
833
  $user = get_userdata( $post->post_author );
834
  if ( $user ) {
835
+ $this->add_coauthors( $post_id, array( $user->user_nicename ) );
836
  }
837
  }
838
  }
868
  $coauthors = array( $current_user->user_login );
869
  }
870
 
871
+ // Set the co-authors
872
  $coauthors = array_unique( array_merge( $existing_coauthors, $coauthors ) );
873
  $coauthor_objects = array();
874
  foreach ( $coauthors as &$author_name ) {
904
  }
905
 
906
  /**
907
+ * Action taken when co-author is deleted.
908
+ * - Co-Author term is removed from all associated posts
909
+ * - Option to specify alternate co-author in place for each post
910
  * @param delete_id
911
  */
912
  function delete_user_action( $delete_id ) {
918
  if ( $reassign_id ) {
919
  // Get posts belonging to deleted author
920
  $reassign_user = get_user_by( 'id', $reassign_id );
921
+ // Set to new guest author
922
  if ( is_object( $reassign_user ) ) {
923
  $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $delete_id ) );
924
 
925
  if ( $post_ids ) {
926
  foreach ( $post_ids as $post_id ) {
927
+ $this->add_coauthors( $post_id, array( $reassign_user->user_nicename ), true );
928
  }
929
  }
930
  }
935
  // Delete term
936
  wp_delete_term( $delete_user->user_login, $this->coauthor_taxonomy );
937
  }
938
+
939
+ // Get the deleted user data by user id.
940
+ $user_data = get_user_by( 'id', $delete_id );
941
+
942
+ // Get the associated user.
943
+ $associated_user = $this->guest_authors->get_guest_author_by( 'linked_account', $user_data->data->user_login );
944
+
945
+ if ( isset( $associated_user->ID ) ) {
946
+ // Delete associated guest user.
947
+ $this->guest_authors->delete( $associated_user->ID );
948
+ }
949
  }
950
 
951
  /**
952
+ * Restrict WordPress from blowing away co-author order when bulk editing terms
953
  *
954
  * @since 2.6
955
  * @props kingkool68, http://wordpress.org/support/topic/plugin-co-authors-plus-making-authors-sortable
956
  */
957
  function filter_wp_get_object_terms( $terms, $object_ids, $taxonomies, $args ) {
958
+ if ( ! isset( $_REQUEST['bulk_edit'] ) || $this->coauthor_taxonomy !== $taxonomies ) {
 
959
  return $terms;
960
  }
961
 
998
  $user = $this->get_coauthor_by( 'user_nicename', $user->user_nicename );
999
 
1000
  $term = $this->get_author_term( $user );
1001
+ $guest_term = get_term_by( 'slug', 'cap-' . $user->user_nicename, $this->coauthor_taxonomy );
1002
+ // Only modify the count if it has a linked account with posts or the author exists as a term
1003
+ if ( $user->linked_account && $guest_term->count ) {
1004
+ if ( $term && ! is_wp_error( $term )) {
1005
+ $count = $guest_term->count + $term->count;
1006
+ } else {
1007
+ $count = $guest_term->count;
1008
+ }
1009
+ } elseif ( $term && ! is_wp_error( $term ) ) {
1010
  $count = $term->count;
1011
  }
1012
 
1014
  }
1015
 
1016
  /**
1017
+ * Checks to see if the current user can set co-authors or not
1018
  */
1019
  function current_user_can_set_authors( $post = null ) {
1020
  global $typenow;
1022
  if ( ! $post ) {
1023
  $post = get_post();
1024
  if ( ! $post ) {
1025
+ // if user is on pages, you need to grab post type another way
1026
+ $current_screen = get_current_screen();
1027
+ $post_type = ( ! empty( $current_screen->post_type ) ) ? $current_screen->post_type : '';
1028
+ }
1029
+ else {
1030
+ $post_type = $post->post_type;
1031
  }
1032
  }
1033
+ else {
1034
+ $post_type = $post->post_type;
1035
+ }
1036
 
1037
  // TODO: need to fix this; shouldn't just say no if don't have post_type
1038
  if ( ! $post_type ) {
1057
  /**
1058
  * Fix for author pages 404ing or not properly displaying on author pages
1059
  *
1060
+ * If a guest author has no posts, we only want to force the queried object to be
1061
+ * the author if they're a user.
1062
  *
1063
+ * If the guest author does have posts, it doesn't matter that they're not an author.
1064
  *
1065
+ * Alternatively, on an author archive, if the first story has co-authors and
1066
  * the first author is NOT the same as the author for the archive,
1067
  * the query_var is changed.
1068
  *
1088
  $term = $this->get_author_term( $authordata );
1089
  }
1090
 
1091
+ if ( is_object( $authordata ) || ! empty( $term ) ) {
 
1092
  $wp_query->queried_object = $authordata;
1093
  $wp_query->queried_object_id = $authordata->ID;
1094
+ add_filter( 'pre_handle_404', '__return_true' );
1095
  } else {
1096
  $wp_query->queried_object = $wp_query->queried_object_id = null;
1097
  $wp_query->is_author = $wp_query->is_archive = false;
1117
  $author = get_queried_object();
1118
 
1119
  if ( $author && 'guest-author' == $author->type ) {
1120
+ unset( $settings['query_args'][$this->coauthor_taxonomy] );
1121
 
1122
  $settings['query_args']['author_name'] = $author->user_nicename;
1123
  }
1126
  }
1127
 
1128
  /**
1129
+ * Main function that handles search-as-you-type for adding co-authors
1130
  */
1131
  public function ajax_suggest() {
1132
 
1143
 
1144
  $authors = $this->search_authors( $search, $ignore );
1145
 
1146
+ // Return message if no authors found
1147
+ if( empty( $authors ) ) echo apply_filters( 'coauthors_no_matching_authors_message', 'Sorry, no matching authors found.');
1148
+
1149
  foreach ( $authors as $author ) {
1150
+ echo esc_html( $author->ID . ' | ' . $author->user_login . ' | ' . $author->display_name . ' | ' . $author->user_email . ' | ' . rawurldecode( $author->user_nicename ) ) . "\n";
1151
  }
1152
 
1153
  die();
1155
  }
1156
 
1157
  /**
1158
+ * Get matching co-authors based on a search value
1159
  */
1160
  public function search_authors( $search = '', $ignored_authors = array() ) {
1161
 
1199
  return array();
1200
  }
1201
 
1202
+ // Get the guest author objects
1203
  $found_users = array();
1204
  foreach ( $found_terms as $found_term ) {
1205
  $found_user = $this->get_coauthor_by( 'user_nicename', $found_term->slug );
1224
  /**
1225
  * Modify get_users() to search display_name instead of user_nicename
1226
  */
1227
+ function action_pre_user_query( $user_query ) {
1228
 
1229
  if ( is_object( $user_query ) ) {
1230
  $user_query->query_where = str_replace( 'user_nicename LIKE', 'display_name LIKE', $user_query->query_where );
1350
  }
1351
 
1352
  /**
1353
+ * Allows guest authors to edit the post they're co-authors of
1354
  */
1355
  function filter_user_has_cap( $allcaps, $caps, $args ) {
1356
 
1410
  return $term;
1411
  }
1412
 
1413
+ // use linked user for accurate post count
1414
+ if ( ! empty ( $coauthor->linked_account ) ) {
1415
+ $term = get_term_by( 'slug', 'cap-' . $coauthor->linked_account, $this->coauthor_taxonomy );
1416
+ if ( ! $term ) {
1417
+ $term = get_term_by( 'slug', $coauthor->linked_account, $this->coauthor_taxonomy );
1418
+ }
1419
+ }
1420
+ else {
1421
+ // See if the prefixed term is available, otherwise default to just the nicename
1422
+ $term = get_term_by( 'slug', 'cap-' . $coauthor->user_nicename, $this->coauthor_taxonomy );
1423
+ if ( ! $term ) {
1424
+ $term = get_term_by( 'slug', $coauthor->user_nicename, $this->coauthor_taxonomy );
1425
+ }
1426
  }
1427
  wp_cache_set( $cache_key, $term, 'co-authors-plus' );
1428
  return $term;
1478
  function filter_ef_calendar_item_information_fields( $information_fields, $post_id ) {
1479
 
1480
  // Don't add the author row again if another plugin has removed
1481
+ if ( ! array_key_exists( $this->coauthor_taxonomy, $information_fields ) ) {
1482
  return $information_fields;
1483
  }
1484
 
1485
  $co_authors = get_coauthors( $post_id );
1486
  if ( count( $co_authors ) > 1 ) {
1487
+ $information_fields[$this->coauthor_taxonomy]['label'] = __( 'Authors', 'co-authors-plus' );
1488
  }
1489
  $co_authors_names = '';
1490
  foreach ( $co_authors as $co_author ) {
1491
  $co_authors_names .= $co_author->display_name . ', ';
1492
  }
1493
+ $information_fields[$this->coauthor_taxonomy]['value'] = rtrim( $co_authors_names, ', ' );
1494
  return $information_fields;
1495
  }
1496
 
1507
  function filter_ef_story_budget_term_column_value( $column_name, $post, $parent_term ) {
1508
 
1509
  // We only want to modify the 'author' column
1510
+ if ( $this->coauthor_taxonomy != $column_name ) {
1511
  return $column_name;
1512
  }
1513
 
1555
  }
1556
 
1557
  /**
1558
+ * Retrieve a list of author terms for a single post.
1559
  *
1560
+ * Grabs a correctly ordered list of co-authors for a single post, appropriately
1561
  * cached because it requires `wp_get_object_terms()` to succeed.
1562
  *
1563
+ * @param int $post_id ID of the post for which to retrieve co-authors.
1564
  * @return array Array of coauthor WP_Term objects
1565
  */
1566
  public function get_coauthor_terms_for_post( $post_id ) {
1615
 
1616
  }
1617
 
1618
+ /**
1619
+ * Filter of the header of author archive pages to correctly display author.
1620
+ */
1621
+ public function filter_author_archive_title() {
1622
+ if ( is_author() ) {
1623
+ $author = sanitize_user( get_query_var( 'author_name' ) );
1624
+ return "Author: ". $author;
1625
+ }
1626
+ }
1627
  }
1628
 
1629
  global $coauthors_plus;
1769
  }
1770
 
1771
  /**
1772
+ * Retrieve a list of co-author terms for a single post.
1773
  *
1774
  * Grabs a correctly ordered list of authors for a single post, appropriately
1775
  * cached because it requires `wp_get_object_terms()` to succeed.
css/co-authors-plus.css CHANGED
@@ -42,7 +42,7 @@
42
  width:200px;
43
  }
44
  #coauthors-list .ui-sortable-helper .coauthor-tag {
45
- cursor: cursor:grabbing;
46
  cursor:-moz-grabbing;
47
  cursor:-webkit-grabbing;
48
  }
@@ -88,6 +88,7 @@
88
  }
89
  #coauthors-loading {
90
  margin: 10px 0px 5px 10px;
 
91
  }
92
 
93
  #coauthors-readonly {
@@ -107,4 +108,4 @@
107
  padding: 5px 3px;
108
  margin-left: 30px;
109
  font-size: 13px;
110
- }
42
  width:200px;
43
  }
44
  #coauthors-list .ui-sortable-helper .coauthor-tag {
45
+ cursor: grabbing;
46
  cursor:-moz-grabbing;
47
  cursor:-webkit-grabbing;
48
  }
88
  }
89
  #coauthors-loading {
90
  margin: 10px 0px 5px 10px;
91
+ float: left;
92
  }
93
 
94
  #coauthors-readonly {
108
  padding: 5px 3px;
109
  margin-left: 30px;
110
  font-size: 13px;
111
+ }
js/co-authors-plus.js CHANGED
@@ -11,7 +11,7 @@ jQuery( document ).ready(function () {
11
  return false;
12
  };
13
 
14
- var $coauthors_loading;
15
 
16
  function coauthors_delete( elem ) {
17
 
@@ -39,9 +39,9 @@ jQuery( document ).ready(function () {
39
  }
40
 
41
  /*
42
- * Save coauthor
43
- * @param int Author ID
44
- * @param string Author Name
45
  * @param object The autosuggest input box
46
  */
47
  function coauthors_save_coauthor( author, co ) {
@@ -59,8 +59,8 @@ jQuery( document ).ready(function () {
59
 
60
 
61
  /*
62
- * Add coauthor
63
- * @param string Author Name
64
  * @param object The autosuggest input box
65
  * @param boolean Initial set up or not?
66
  */
@@ -70,11 +70,11 @@ jQuery( document ).ready(function () {
70
  if ( co && co.siblings( '.coauthor-tag' ).length ) {
71
  coauthors_save_coauthor( author, co );
72
  } else {
73
- // Not editing, so we create a new author entry
74
  if ( count == 0 ) {
75
  var coName = ( count == 0 ) ? 'coauthors-main' : '';
76
- // Add new author to <select>
77
- //coauthors_select_author( author );
78
  }
79
  var options = { addDelete: true, addEdit: false };
80
 
@@ -98,8 +98,9 @@ jQuery( document ).ready(function () {
98
 
99
  co.bind( 'blur', coauthors_stop_editing );
100
 
101
- // Set the value for the auto-suggest box to the Author's name and hide it
102
- co.val( unescape( author.name ) )
 
103
  .hide()
104
  .unbind( 'focus' )
105
  ;
@@ -132,8 +133,8 @@ jQuery( document ).ready(function () {
132
  }
133
 
134
  /*
135
- * Adds a delete and edit button next to an author
136
- * @param object The row to which the new author should be added
137
  */
138
  function coauthors_insert_author_edit_cells( $div, options ){
139
 
@@ -156,7 +157,7 @@ jQuery( document ).ready(function () {
156
 
157
  /*
158
  * Creates autosuggest input box
159
- * @param string [optional] Name of the author
160
  * @param string [optional] Name to be applied to the input box
161
  */
162
  function coauthors_create_autosuggest( authorName, inputName ) {
@@ -178,7 +179,7 @@ jQuery( document ).ready(function () {
178
  ;
179
 
180
  if ( authorName )
181
- $co.attr( 'value', unescape( authorName ) );
182
  else
183
  $co.attr( 'value', coAuthorsPlusStrings.search_box_text )
184
  .focus( function(){ $co.val( '' ) } )
@@ -189,7 +190,7 @@ jQuery( document ).ready(function () {
189
 
190
  }
191
 
192
- // Callback for when a user selects an author
193
  function coauthors_autosuggest_select() {
194
  $this = jQuery( this );
195
  var vals = this.value.split( '|' );
@@ -199,7 +200,9 @@ jQuery( document ).ready(function () {
199
  author.login = jQuery.trim( vals[1] );
200
  author.name = jQuery.trim( vals[2] );
201
  author.email = jQuery.trim( vals[3] );
202
- author.nicename = jQuery.trim( vals[4] );
 
 
203
 
204
  if ( author.id=='New' ) {
205
  coauthors_new_author_display( name );
@@ -234,13 +237,13 @@ jQuery( document ).ready(function () {
234
  }
235
 
236
  /*
237
- * Creates the text tag for an author
238
- * @param string Name of the author
239
  */
240
  function coauthors_create_author_tag( author ) {
241
 
242
  var $tag = jQuery( '<span></span>' )
243
- .html( unescape( author.name ) )
244
  .attr( 'title', coAuthorsPlusStrings.input_box_title )
245
  .addClass( 'coauthor-tag' )
246
  // Add Click event to edit
@@ -278,8 +281,8 @@ jQuery( document ).ready(function () {
278
  }
279
 
280
  /*
281
- * Creates the text tag for an author
282
- * @param string Name of the author
283
  */
284
  function coauthors_create_author_hidden_input ( author ) {
285
  var input = jQuery( '<input />' )
@@ -287,7 +290,7 @@ jQuery( document ).ready(function () {
287
  'type': 'hidden',
288
  'id': 'coauthors_hidden_input',
289
  'name': 'coauthors[]',
290
- 'value': unescape( author.nicename )
291
  })
292
  ;
293
 
@@ -319,7 +322,7 @@ jQuery( document ).ready(function () {
319
  $coauthors_div.append( table );
320
  }
321
 
322
- // Select authors already added to the post
323
  var addedAlready = [];
324
  //jQuery('#the-list tr').each(function(){
325
  var count = 0;
@@ -337,11 +340,11 @@ jQuery( document ).ready(function () {
337
  var newCO = coauthors_create_autosuggest( '', false );
338
  coauthors_add_to_table( newCO );
339
 
340
- $coauthors_loading = jQuery( '#ajax-loading' ).clone().attr( 'id', 'coauthors-loading' );
341
  move_loading( newCO );
342
 
343
 
344
- // Make co-authors sortable so an editor can control the order of the authors
345
  jQuery( '#coauthors-edit' ).ready(function( $ ) {
346
  $( '#coauthors-list' ).sortable({
347
  axis: 'y',
@@ -398,7 +401,7 @@ jQuery( document ).ready(function () {
398
  });
399
  }
400
 
401
- // Remove the read-only coauthors so we don't get craziness
402
  jQuery( '#coauthors-readonly' ).remove();
403
  coauthors_initialize( post_coauthors );
404
  }
@@ -425,7 +428,7 @@ jQuery( document ).ready(function () {
425
  var el = jQuery( '.inline-edit-group.inline-edit-coauthors', '#edit-' + postId );
426
  el.detach().appendTo( '.quick-edit-row .inline-edit-col-left .inline-edit-col' ).show();
427
 
428
- // initialize coauthors
429
  var post_coauthors = jQuery.map( jQuery( '.column-coauthors a', $postRow ), function( el ) {
430
  return {
431
  login: jQuery( el ).data( 'user_login' ),
11
  return false;
12
  };
13
 
14
+ var $coauthors_loading = jQuery("<span id='ajax-loading'></span>");
15
 
16
  function coauthors_delete( elem ) {
17
 
39
  }
40
 
41
  /*
42
+ * Save co-author
43
+ * @param int Co-Author ID
44
+ * @param string Co-Author Name
45
  * @param object The autosuggest input box
46
  */
47
  function coauthors_save_coauthor( author, co ) {
59
 
60
 
61
  /*
62
+ * Add co-author
63
+ * @param string Co-Author Name
64
  * @param object The autosuggest input box
65
  * @param boolean Initial set up or not?
66
  */
70
  if ( co && co.siblings( '.coauthor-tag' ).length ) {
71
  coauthors_save_coauthor( author, co );
72
  } else {
73
+ // Not editing, so we create a new co-author entry
74
  if ( count == 0 ) {
75
  var coName = ( count == 0 ) ? 'coauthors-main' : '';
76
+ // Add new co-author to <select>
77
+ //coauthors_select_author( co-author );
78
  }
79
  var options = { addDelete: true, addEdit: false };
80
 
98
 
99
  co.bind( 'blur', coauthors_stop_editing );
100
 
101
+ // Set the value for the auto-suggest box to the co-author's name and hide it
102
+ // unescape() is deprecated, so replacing it with decodeURIComponent() here and every places.
103
+ co.val( decodeURIComponent( author.name ) )
104
  .hide()
105
  .unbind( 'focus' )
106
  ;
133
  }
134
 
135
  /*
136
+ * Adds a delete and edit button next to a co-author
137
+ * @param object The row to which the new co-author should be added
138
  */
139
  function coauthors_insert_author_edit_cells( $div, options ){
140
 
157
 
158
  /*
159
  * Creates autosuggest input box
160
+ * @param string [optional] Name of the co-author
161
  * @param string [optional] Name to be applied to the input box
162
  */
163
  function coauthors_create_autosuggest( authorName, inputName ) {
179
  ;
180
 
181
  if ( authorName )
182
+ $co.attr( 'value', decodeURIComponent( authorName ) );
183
  else
184
  $co.attr( 'value', coAuthorsPlusStrings.search_box_text )
185
  .focus( function(){ $co.val( '' ) } )
190
 
191
  }
192
 
193
+ // Callback for when a user selects a co-author
194
  function coauthors_autosuggest_select() {
195
  $this = jQuery( this );
196
  var vals = this.value.split( '|' );
200
  author.login = jQuery.trim( vals[1] );
201
  author.name = jQuery.trim( vals[2] );
202
  author.email = jQuery.trim( vals[3] );
203
+
204
+ // Decode user-nicename if it has special characters in it.
205
+ author.nicename = decodeURIComponent( jQuery.trim( vals[4] ) );
206
 
207
  if ( author.id=='New' ) {
208
  coauthors_new_author_display( name );
237
  }
238
 
239
  /*
240
+ * Creates the text tag for a co-author
241
+ * @param string Name of the co-author
242
  */
243
  function coauthors_create_author_tag( author ) {
244
 
245
  var $tag = jQuery( '<span></span>' )
246
+ .text( decodeURIComponent( author.name ) )
247
  .attr( 'title', coAuthorsPlusStrings.input_box_title )
248
  .addClass( 'coauthor-tag' )
249
  // Add Click event to edit
281
  }
282
 
283
  /*
284
+ * Creates the text tag for a co-author
285
+ * @param string Name of the co-author
286
  */
287
  function coauthors_create_author_hidden_input ( author ) {
288
  var input = jQuery( '<input />' )
290
  'type': 'hidden',
291
  'id': 'coauthors_hidden_input',
292
  'name': 'coauthors[]',
293
+ 'value': decodeURIComponent( author.nicename )
294
  })
295
  ;
296
 
322
  $coauthors_div.append( table );
323
  }
324
 
325
+ // Select co-authors already added to the post
326
  var addedAlready = [];
327
  //jQuery('#the-list tr').each(function(){
328
  var count = 0;
340
  var newCO = coauthors_create_autosuggest( '', false );
341
  coauthors_add_to_table( newCO );
342
 
343
+ $coauthors_loading = jQuery( '#publishing-action .spinner' ).clone().attr( 'id', 'coauthors-loading' );
344
  move_loading( newCO );
345
 
346
 
347
+ // Make co-authors sortable so an editor can control the order of the co-authors
348
  jQuery( '#coauthors-edit' ).ready(function( $ ) {
349
  $( '#coauthors-list' ).sortable({
350
  axis: 'y',
401
  });
402
  }
403
 
404
+ // Remove the read-only co-authors so we don't get craziness
405
  jQuery( '#coauthors-readonly' ).remove();
406
  coauthors_initialize( post_coauthors );
407
  }
428
  var el = jQuery( '.inline-edit-group.inline-edit-coauthors', '#edit-' + postId );
429
  el.detach().appendTo( '.quick-edit-row .inline-edit-col-left .inline-edit-col' ).show();
430
 
431
+ // initialize co-authors
432
  var post_coauthors = jQuery.map( jQuery( '.column-coauthors a', $postRow ), function( el ) {
433
  return {
434
  login: jQuery( el ).data( 'user_login' ),
php/class-coauthors-guest-authors.php CHANGED
@@ -89,9 +89,13 @@ class CoAuthors_Guest_Authors
89
  'not_found_in_trash' => __( 'No guest authors found in Trash', 'co-authors-plus' ),
90
  'update_item' => __( 'Update Guest Author', 'co-authors-plus' ),
91
  'metabox_about' => __( 'About the guest author', 'co-authors-plus' ),
 
 
 
 
92
  ) );
93
 
94
- // Register a post type to store our authors that aren't WP.com users
95
  $args = array(
96
  'label' => $this->labels['singular'],
97
  'labels' => array(
@@ -106,6 +110,10 @@ class CoAuthors_Guest_Authors
106
  'search_items' => $this->labels['search_items'],
107
  'not_found' => $this->labels['not_found'],
108
  'not_found_in_trash' => $this->labels['not_found_in_trash'],
 
 
 
 
109
  ),
110
  'public' => true,
111
  'publicly_queryable' => false,
@@ -123,17 +131,7 @@ class CoAuthors_Guest_Authors
123
  register_post_type( $this->post_type, $args );
124
 
125
  // Some of the common sizes used by get_avatar
126
- $this->avatar_sizes = array(
127
- 32,
128
- 50,
129
- 64,
130
- 96,
131
- 128,
132
- );
133
- $this->avatar_sizes = apply_filters( 'coauthors_guest_author_avatar_sizes', $this->avatar_sizes );
134
- foreach ( $this->avatar_sizes as $size ) {
135
- add_image_size( 'guest-author-' . $size, $size, $size, true );
136
- }
137
 
138
  // Hacky way to remove the title and the editor
139
  remove_post_type_support( $this->post_type, 'title' );
@@ -177,7 +175,7 @@ class CoAuthors_Guest_Authors
177
 
178
  /**
179
  * Handle the admin action to create a guest author based
180
- * on an existing WordPress user
181
  *
182
  * @since 3.0
183
  */
@@ -203,6 +201,8 @@ class CoAuthors_Guest_Authors
203
  wp_die( esc_html( $post_id->get_error_message() ) );
204
  }
205
 
 
 
206
  // Redirect to the edit Guest Author screen
207
  $edit_link = get_edit_post_link( $post_id, 'redirect' );
208
  $redirect_to = add_query_arg( 'message', 'guest-author-created', $edit_link );
@@ -273,6 +273,8 @@ class CoAuthors_Guest_Authors
273
  $args['message'] = 'delete-error';
274
  } else {
275
  $args['message'] = 'guest-author-deleted';
 
 
276
  }
277
 
278
  // Redirect to safety
@@ -463,36 +465,75 @@ class CoAuthors_Guest_Authors
463
  wp_die( esc_html( sprintf( __( "%s can't be deleted because it doesn't exist.", 'co-authors-plus' ), $this->labels['singular'] ) ) );
464
  }
465
 
 
 
 
 
 
 
 
 
 
466
  echo '<div class="wrap">';
467
  echo '<div class="icon32" id="icon-users"><br/></div>';
468
  echo '<h2>' . esc_html( sprintf( __( 'Delete %s', 'co-authors-plus ' ), $this->labels['plural'] ) ) . '</h2>';
469
  echo '<p>' . esc_html( sprintf( __( 'You have specified this %s for deletion:', 'co-authors-plus' ), strtolower( $this->labels['singular'] ) ) ) . '</p>';
470
  echo '<p>#' . esc_html( $guest_author->ID . ': ' . $guest_author->display_name ) . '</p>';
471
- echo '<p>' . esc_html( sprintf( __( 'What should be done with posts assigned to this %s?', 'co-authors-plus' ), strtolower( $this->labels['singular'] ) ) ) . '</p>';
472
- echo '<p class="description">' . esc_html( sprintf( __( "Note: If you'd like to delete the %s and all of their posts, you should delete their posts first and then come back to delete the %s.", 'co-authors-plus' ), strtolower( $this->labels['singular'] ), strtolower( $this->labels['singular'] ) ) ) . '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  echo '<form method="POST" action="' . esc_url( add_query_arg( 'page', 'view-guest-authors', admin_url( $this->parent_page ) ) ) . '">';
474
  // Hidden stuffs
475
  echo '<input type="hidden" name="action" value="delete-guest-author" />';
476
  wp_nonce_field( 'delete-guest-author' );
477
  echo '<input type="hidden" id="id" name="id" value="' . esc_attr( (int) $_GET['id'] ) . '" />';
478
  echo '<fieldset><ul style="list-style-type:none;">';
479
- // Reassign to another user
480
- echo '<li class="hide-if-no-js"><label for="reassign-another">';
481
- echo '<input type="radio" id="reassign-another" name="reassign" class="reassign-option" value="reassign-another" />&nbsp;&nbsp;' . esc_html__( 'Reassign to another co-author:', 'co-authors-plus' ) . '&nbsp;&nbsp;</label>';
482
- echo '<input type="hidden" id="leave-assigned-to" name="leave-assigned-to" style="width:200px;" />';
483
- echo '</li>';
484
- // Leave mapped to a linked account
485
- if ( get_user_by( 'login', $guest_author->linked_account ) ) {
486
- echo '<li><label for="leave-assigned">';
487
- echo '<input type="radio" id="leave-assigned" class="reassign-option" name="reassign" value="leave-assigned" />&nbsp;&nbsp;' . esc_html( sprintf( __( 'Leave posts assigned to the mapped user, %s.', 'co-authors-plus' ) ), $guest_author->linked_account );
 
 
 
 
 
 
 
488
  echo '</label></li>';
489
  }
490
- // Remove bylines from the posts
491
- echo '<li><label for="remove-byline">';
492
- echo '<input type="radio" id="remove-byline" class="reassign-option" name="reassign" value="remove-byline" />&nbsp;&nbsp;' . esc_html__( 'Remove byline from posts (but leave each post in its current status).', 'co-authors-plus' );
493
- echo '</label></li>';
494
  echo '</ul></fieldset>';
495
- submit_button( __( 'Confirm Deletion', 'co-authors-plus' ), 'secondary', 'submit', true, array( 'disabled' => 'disabled' ) );
 
 
 
 
 
 
496
  echo '</form>';
497
  echo '</div>';
498
  } else {
@@ -592,7 +633,7 @@ class CoAuthors_Guest_Authors
592
  }
593
 
594
  /**
595
- * Metabox to display all of the pertient names for a Guest Author without a user account
596
  *
597
  * @since 3.0
598
  */
@@ -627,7 +668,8 @@ class CoAuthors_Guest_Authors
627
  }
628
 
629
  /**
630
- * Metabox to display all of the pertient contact details for a Guest Author without a user account
 
631
  *
632
  * @since 3.0
633
  */
@@ -931,11 +973,8 @@ class CoAuthors_Guest_Authors
931
  $args = array(
932
  'class' => "avatar avatar-{$size} photo",
933
  );
934
- if ( in_array( $size, $this->avatar_sizes ) ) {
935
- $size = 'guest-author-' . $size;
936
- } else {
937
- $size = array( $size, $size );
938
- }
939
 
940
  $thumbnail = get_the_post_thumbnail( $guest_author->ID, $size, $args );
941
 
89
  'not_found_in_trash' => __( 'No guest authors found in Trash', 'co-authors-plus' ),
90
  'update_item' => __( 'Update Guest Author', 'co-authors-plus' ),
91
  'metabox_about' => __( 'About the guest author', 'co-authors-plus' ),
92
+ 'featured_image' => __( 'Avatar', 'co-authors-plus' ),
93
+ 'set_featured_image' => __( 'Set Avatar', 'co-authors-plus' ),
94
+ 'use_featured_image' => __( 'Use Avatar', 'co-authors-plus' ),
95
+ 'remove_featured_image' => __( 'Remove Avatar', 'co-authors-plus' ),
96
  ) );
97
 
98
+ // Register a post type to store our guest authors
99
  $args = array(
100
  'label' => $this->labels['singular'],
101
  'labels' => array(
110
  'search_items' => $this->labels['search_items'],
111
  'not_found' => $this->labels['not_found'],
112
  'not_found_in_trash' => $this->labels['not_found_in_trash'],
113
+ 'featured_image' => $this->labels['featured_image'],
114
+ 'set_featured_image' => $this->labels['set_featured_image'],
115
+ 'use_featured_image' => $this->labels['use_featured_image'],
116
+ 'remove_featured_image' => $this->labels['remove_featured_image']
117
  ),
118
  'public' => true,
119
  'publicly_queryable' => false,
131
  register_post_type( $this->post_type, $args );
132
 
133
  // Some of the common sizes used by get_avatar
134
+ $this->avatar_sizes = array();
 
 
 
 
 
 
 
 
 
 
135
 
136
  // Hacky way to remove the title and the editor
137
  remove_post_type_support( $this->post_type, 'title' );
175
 
176
  /**
177
  * Handle the admin action to create a guest author based
178
+ * on an existing user
179
  *
180
  * @since 3.0
181
  */
201
  wp_die( esc_html( $post_id->get_error_message() ) );
202
  }
203
 
204
+ do_action( 'cap_guest_author_create' );
205
+
206
  // Redirect to the edit Guest Author screen
207
  $edit_link = get_edit_post_link( $post_id, 'redirect' );
208
  $redirect_to = add_query_arg( 'message', 'guest-author-created', $edit_link );
273
  $args['message'] = 'delete-error';
274
  } else {
275
  $args['message'] = 'guest-author-deleted';
276
+
277
+ do_action( 'cap_guest_author_del' );
278
  }
279
 
280
  // Redirect to safety
465
  wp_die( esc_html( sprintf( __( "%s can't be deleted because it doesn't exist.", 'co-authors-plus' ), $this->labels['singular'] ) ) );
466
  }
467
 
468
+ // get post count
469
+ global $coauthors_plus;
470
+ $term = $coauthors_plus->get_author_term( $guest_author );
471
+ if ( $term ) {
472
+ $count = $term->count;
473
+ } else {
474
+ $count = 0;
475
+ }
476
+
477
  echo '<div class="wrap">';
478
  echo '<div class="icon32" id="icon-users"><br/></div>';
479
  echo '<h2>' . esc_html( sprintf( __( 'Delete %s', 'co-authors-plus ' ), $this->labels['plural'] ) ) . '</h2>';
480
  echo '<p>' . esc_html( sprintf( __( 'You have specified this %s for deletion:', 'co-authors-plus' ), strtolower( $this->labels['singular'] ) ) ) . '</p>';
481
  echo '<p>#' . esc_html( $guest_author->ID . ': ' . $guest_author->display_name ) . '</p>';
482
+ // display wording differently per post count
483
+ if ( 0 === $count ) {
484
+ $post_count_message = '<p>' . sprintf( __( 'There are no posts associated with this guest author.', 'co-authors-plus' ), strtolower( $this->labels['singular'] ) ) . '</p>';
485
+ }
486
+ else {
487
+ $note = '<p class="description">' . sprintf( __( "Note: If you'd like to delete the %s and all of their posts, you should delete their posts first and then come back to delete the %s.", 'co-authors-plus' ), strtolower( $this->labels['singular'] ), strtolower( $this->labels['singular'] ) ) . '</p>';
488
+ if ( 1 === $count ) {
489
+ $post_count_message = '<p>' . sprintf( __( 'There is %d post associated with this guest author. What should be done with the post assigned to this %s?', 'co-authors-plus' ), $count, strtolower( $this->labels['singular'] ) ) . '</p>';
490
+ }
491
+ else {
492
+ $post_count_message = '<p>' . sprintf( __( 'There are %d posts associated with this guest author. What should be done with the posts assigned to this %s?', 'co-authors-plus' ), $count, strtolower( $this->labels['singular'] ) ) . '</p>';
493
+ }
494
+ $post_count_message .= $note;
495
+ }
496
+ $allowed_html = array(
497
+ 'p' => array(
498
+ 'class' => array(),
499
+ ),
500
+ );
501
+ echo wp_kses( $post_count_message, $allowed_html );
502
  echo '<form method="POST" action="' . esc_url( add_query_arg( 'page', 'view-guest-authors', admin_url( $this->parent_page ) ) ) . '">';
503
  // Hidden stuffs
504
  echo '<input type="hidden" name="action" value="delete-guest-author" />';
505
  wp_nonce_field( 'delete-guest-author' );
506
  echo '<input type="hidden" id="id" name="id" value="' . esc_attr( (int) $_GET['id'] ) . '" />';
507
  echo '<fieldset><ul style="list-style-type:none;">';
508
+ // only show delete options if post count > 0
509
+ if ( $count > 0 ) {
510
+ // Reassign to another user
511
+ echo '<li class="hide-if-no-js"><label for="reassign-another">';
512
+ echo '<input type="radio" id="reassign-another" name="reassign" class="reassign-option" value="reassign-another" />&nbsp;&nbsp;' . esc_html__( 'Reassign to another co-author:', 'co-authors-plus' ) . '&nbsp;&nbsp;</label>';
513
+ echo '<input type="hidden" id="leave-assigned-to" name="leave-assigned-to" style="width:200px;" />';
514
+ echo '</li>';
515
+ // Leave mapped to a linked account
516
+ if ( get_user_by( 'login', $guest_author->linked_account ) ) {
517
+ echo '<li><label for="leave-assigned">';
518
+ echo '<input type="radio" id="leave-assigned" class="reassign-option" name="reassign" value="leave-assigned" />&nbsp;&nbsp;' . esc_html( sprintf( __( 'Leave posts assigned to the mapped user, %s.', 'co-authors-plus' ), $guest_author->linked_account ) );
519
+ echo '</label></li>';
520
+ }
521
+ // Remove bylines from the posts
522
+ echo '<li><label for="remove-byline">';
523
+ echo '<input type="radio" id="remove-byline" class="reassign-option" name="reassign" value="remove-byline" />&nbsp;&nbsp;' . esc_html__( 'Remove byline from posts (but leave each post in its current status).', 'co-authors-plus' );
524
  echo '</label></li>';
525
  }
526
+ else {
527
+ echo '<input type="hidden" id="remove-byline" class="reassign-option" name="reassign" value="remove-byline" checked="checked" />';
528
+ }
 
529
  echo '</ul></fieldset>';
530
+ // disable disabled submit button for 0 post count
531
+ if ( 0 === $count ) {
532
+ submit_button( __( 'Confirm Deletion', 'co-authors-plus' ), 'secondary', 'submit', true );
533
+ }
534
+ else {
535
+ submit_button( __( 'Confirm Deletion', 'co-authors-plus' ), 'secondary', 'submit', true, array( 'disabled' => 'disabled' ) );
536
+ }
537
  echo '</form>';
538
  echo '</div>';
539
  } else {
633
  }
634
 
635
  /**
636
+ * Metabox to display all of the pertient names for a Guest Author not linked to user account
637
  *
638
  * @since 3.0
639
  */
668
  }
669
 
670
  /**
671
+ * Metabox to display all of the pertient contact details for a Guest Author not linked to
672
+ * user account
673
  *
674
  * @since 3.0
675
  */
973
  $args = array(
974
  'class' => "avatar avatar-{$size} photo",
975
  );
976
+
977
+ $size = array( $size, $size );
 
 
 
978
 
979
  $thumbnail = get_the_post_thumbnail( $guest_author->ID, $size, $args );
980
 
php/class-coauthors-wp-list-table.php CHANGED
@@ -137,10 +137,10 @@ class CoAuthors_WP_List_Table extends WP_List_Table {
137
  }
138
 
139
  /**
140
- * Either there are no guest authors, or the search doesn't match any
141
  */
142
  function no_items() {
143
- esc_html_e( 'No matching guest authors were found.', 'co-authors-plus' );
144
  }
145
 
146
  /**
@@ -251,7 +251,10 @@ class CoAuthors_WP_List_Table extends WP_List_Table {
251
  function column_posts( $item ) {
252
  global $coauthors_plus;
253
  $term = $coauthors_plus->get_author_term( $item );
254
- if ( $term ) {
 
 
 
255
  $count = $term->count;
256
  } else {
257
  $count = 0;
137
  }
138
 
139
  /**
140
+ * Either there are no co-authors, or the search doesn't match any
141
  */
142
  function no_items() {
143
+ esc_html_e( 'No matching co-authors were found.', 'co-authors-plus' );
144
  }
145
 
146
  /**
251
  function column_posts( $item ) {
252
  global $coauthors_plus;
253
  $term = $coauthors_plus->get_author_term( $item );
254
+ $guest_term = get_term_by( 'slug', 'cap-' . $item->user_nicename, $coauthors_plus->coauthor_taxonomy );
255
+ if ( ! empty( $item->linked_account ) && $guest_term->count ) {
256
+ $count = count_user_posts( get_user_by( 'slug', $item->linked_account )->ID );
257
+ } elseif ( $term ) {
258
  $count = $term->count;
259
  } else {
260
  $count = 0;
php/class-wp-cli.php CHANGED
@@ -28,6 +28,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
28
  $users = get_users();
29
  $created = 0;
30
  $skipped = 0;
 
31
  foreach ( $users as $user ) {
32
 
33
  $result = $coauthors_plus->guest_authors->create_guest_author_from_user_id( $user->ID );
@@ -36,12 +37,12 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
36
  } else {
37
  $created++;
38
  }
 
39
  }
40
-
41
  WP_CLI::line( 'All done! Here are your results:' );
42
  WP_CLI::line( "- {$created} guest author profiles were created" );
43
  WP_CLI::line( "- {$skipped} users already had guest author profiles" );
44
-
45
  }
46
 
47
  /**
@@ -78,7 +79,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
78
 
79
  $terms = cap_get_coauthor_terms_for_post( $single_post->ID );
80
  if ( empty( $terms ) ) {
81
- WP_CLI::error( sprintf( 'No co-authors found for post #%d.', $single_post->ID ) );
82
  }
83
 
84
  if ( ! empty( $terms ) ) {
@@ -115,7 +116,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
115
  }
116
 
117
  /**
118
- * Subcommand to assign coauthors to a post based on a given meta key
119
  *
120
  * @since 3.0
121
  *
@@ -248,8 +249,8 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
248
  $coauthors_plus->add_coauthors( $post_id, array( $coauthor->user_login ) );
249
  WP_CLI::line( sprintf( __( "Updating - Adding %s's byline to post #%d", 'co-authors-plus' ), $coauthor->user_login, $post_id ) );
250
  $affected++;
251
- if ( $affected && 0 === $affected % 20 ) {
252
- sleep( 5 );
253
  }
254
  }
255
  WP_CLI::success( sprintf( __( 'All done! %d posts were affected.', 'co-authors-plus' ), $affected ) );
@@ -408,8 +409,8 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
408
  }
409
 
410
  /**
411
- * Swap one Co Author with another on all posts for which they are an author. Unlike rename-coauthor,
412
- * this leaves the original Co Author term intact and works when the 'to' user already has a co-author term.
413
  *
414
  * @subcommand swap-coauthors
415
  * @synopsis --from=<user-login> --to=<user-login> [--post_type=<ptype>] [--dry=<dry>]
@@ -611,7 +612,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
611
  }
612
 
613
  /**
614
- * Update the post count and description for each author
615
  *
616
  * @since 3.0
617
  *
@@ -734,7 +735,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
734
  }
735
 
736
  if ( ! class_exists( 'WXR_Parser' ) ) {
737
- require_once( WP_CONTENT_DIR . '/admin-plugins/wordpress-importer/parsers.php' );
738
  }
739
 
740
  $parser = new WXR_Parser();
28
  $users = get_users();
29
  $created = 0;
30
  $skipped = 0;
31
+ $progress = \WP_CLI\Utils\make_progress_bar( 'Processing guest authors...', count ( $users ) );
32
  foreach ( $users as $user ) {
33
 
34
  $result = $coauthors_plus->guest_authors->create_guest_author_from_user_id( $user->ID );
37
  } else {
38
  $created++;
39
  }
40
+ $progress->tick();
41
  }
42
+ $progress->finish();
43
  WP_CLI::line( 'All done! Here are your results:' );
44
  WP_CLI::line( "- {$created} guest author profiles were created" );
45
  WP_CLI::line( "- {$skipped} users already had guest author profiles" );
 
46
  }
47
 
48
  /**
79
 
80
  $terms = cap_get_coauthor_terms_for_post( $single_post->ID );
81
  if ( empty( $terms ) ) {
82
+ WP_CLI::line( sprintf( 'No co-authors found for post #%d.', $single_post->ID ) );
83
  }
84
 
85
  if ( ! empty( $terms ) ) {
116
  }
117
 
118
  /**
119
+ * Subcommand to assign co-authors to a post based on a given meta key
120
  *
121
  * @since 3.0
122
  *
249
  $coauthors_plus->add_coauthors( $post_id, array( $coauthor->user_login ) );
250
  WP_CLI::line( sprintf( __( "Updating - Adding %s's byline to post #%d", 'co-authors-plus' ), $coauthor->user_login, $post_id ) );
251
  $affected++;
252
+ if ( $affected && 0 === $affected % 100 ) {
253
+ sleep( 2 );
254
  }
255
  }
256
  WP_CLI::success( sprintf( __( 'All done! %d posts were affected.', 'co-authors-plus' ), $affected ) );
409
  }
410
 
411
  /**
412
+ * Swap one co-author with another on all posts for which they are a co-author. Unlike rename-coauthor,
413
+ * this leaves the original co-author term intact and works when the 'to' user already has a co-author term.
414
  *
415
  * @subcommand swap-coauthors
416
  * @synopsis --from=<user-login> --to=<user-login> [--post_type=<ptype>] [--dry=<dry>]
612
  }
613
 
614
  /**
615
+ * Update the post count and description for each author and guest author
616
  *
617
  * @since 3.0
618
  *
735
  }
736
 
737
  if ( ! class_exists( 'WXR_Parser' ) ) {
738
+ require_once( WP_CONTENT_DIR . '/plugins/wordpress-importer/parsers.php' );
739
  }
740
 
741
  $parser = new WXR_Parser();
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Co-Authors Plus ===
2
  Contributors: batmoo, danielbachhuber, automattic
3
  Tags: authors, users, multiple authors, coauthors, multi-author, publishing
4
- Tested up to: 4.8
5
  Requires at least: 4.1
6
- Stable tag: 3.2.2
7
 
8
  Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box
9
 
@@ -57,6 +57,43 @@ Bug fixes and minor enhancements
57
 
58
  == Changelog ==
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  = 3.2.2 =
61
  * Fix broken author ordering in 4.7+ (props mslinnea)
62
  * Fix no moderation e-mail bug (props RobjS)
1
  === Co-Authors Plus ===
2
  Contributors: batmoo, danielbachhuber, automattic
3
  Tags: authors, users, multiple authors, coauthors, multi-author, publishing
4
+ Tested up to: 4.9.5
5
  Requires at least: 4.1
6
+ Stable tag: 3.3.0
7
 
8
  Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box
9
 
57
 
58
  == Changelog ==
59
 
60
+ = 3.3.0 ("Rebecca") =
61
+ * Fix private post viewing on front-end
62
+ * Reduce amount of sleep
63
+ * Author search UX issues
64
+ * Remove associated guest user when mapped user id deleted.
65
+ * Removed double left join on posts_join_filter
66
+ * Fixed WP CLI create-terms-for-posts if no co-authors found
67
+ * Pages archive now displays coauthors and quick edit works
68
+ * Terminology updated throughout
69
+ * Replace hardcoded 'author' with $this->$coauthor_taxonomy
70
+ * Move parenthesis to fix esc_html and sprintf
71
+ * Added progress to create-guest-authors so users have an idea of how long it will take
72
+ * Deleting guest authors is less confusing
73
+ * Guest author's featured image is avatar now
74
+ * Removed extra image sizing
75
+ * Remove duplicated byline
76
+ * coauthors_wp_list_authors() has option to list only guest authors now
77
+ * remove duplicates from linked accounts on coauthors_wp_list_authors()
78
+ * Accurate Guest Author post count on linked accounts
79
+ * New README.md
80
+ * Filter author archive
81
+ * Fix coauthors_links_single()
82
+ * Added guest author hooks for create/delete
83
+ * Fixes logic for DOING_AUTOSAVE check
84
+ * user_login spaces problem when using add_coauthors
85
+ * Adding details of filter for slow performance
86
+ * Remove redundant test for 404 on Author Archive
87
+ * Guest Author Counts are more accurate
88
+ * Set $coauthors_loading
89
+ * Fix the issue where guest authors with non-ASCII characters can't be used as co-authors
90
+ * Fix the issue where incompatibility when `coauthors_auto_apply_template_tags` set to true
91
+ * Unit tests/Fix warnings for template tags
92
+ * Review and improve test coverage
93
+ * Update class-wp-cli.php
94
+ * Update .travis.yml file for PHPUnit tests
95
+ * Changes to resolve issue #332 about missing coauthor meta
96
+
97
  = 3.2.2 =
98
  * Fix broken author ordering in 4.7+ (props mslinnea)
99
  * Fix no moderation e-mail bug (props RobjS)
template-tags.php CHANGED
@@ -35,6 +35,8 @@ function get_coauthors( $post_id = 0 ) {
35
  }
36
  } // the empty else case is because if we force guest authors, we don't ever care what value wp_posts.post_author has.
37
  }
 
 
38
  return $coauthors;
39
  }
40
 
@@ -234,12 +236,33 @@ function coauthors( $between = null, $betweenLast = null, $before = null, $after
234
  * @param bool $echo Whether the co-authors should be echoed or returned. Defaults to true.
235
  */
236
  function coauthors_posts_links( $between = null, $betweenLast = null, $before = null, $after = null, $echo = true ) {
237
- return coauthors__echo('coauthors_posts_links_single', 'callback', array(
238
- 'between' => $between,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  'betweenLast' => $betweenLast,
240
- 'before' => $before,
241
- 'after' => $after,
242
  ), null, $echo );
 
 
 
 
 
 
243
  }
244
 
245
  /**
@@ -343,12 +366,33 @@ function coauthors_nicknames( $between = null, $betweenLast = null, $before = nu
343
  * @param bool $echo Whether the co-authors should be echoed or returned. Defaults to true.
344
  */
345
  function coauthors_links( $between = null, $betweenLast = null, $before = null, $after = null, $echo = true ) {
346
- return coauthors__echo( 'coauthors_links_single', 'callback', array(
347
- 'between' => $between,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  'betweenLast' => $betweenLast,
349
- 'before' => $before,
350
- 'after' => $after,
351
  ), null, $echo );
 
 
 
 
 
 
352
  }
353
 
354
  /**
@@ -376,14 +420,24 @@ function coauthors_emails( $between = null, $betweenLast = null, $before = null,
376
  * @return string
377
  */
378
  function coauthors_links_single( $author ) {
379
- if ( get_the_author_meta( 'url' ) ) {
380
- return sprintf( '<a href="%s" title="%s" rel="external">%s</a>',
381
- get_the_author_meta( 'url' ),
382
- esc_attr( sprintf( __( 'Visit %s&#8217;s website' ), get_the_author() ) ),
383
- get_the_author()
 
 
 
 
 
 
 
 
 
384
  );
385
- } else {
386
- return get_the_author();
 
387
  }
388
  }
389
 
@@ -405,22 +459,64 @@ function coauthors_ids( $between = null, $betweenLast = null, $before = null, $a
405
  ), null, $echo );
406
  }
407
 
408
- function get_the_coauthor_meta( $field ) {
409
- global $wp_query, $post;
410
-
411
- $coauthors = get_coauthors();
412
- $meta = array();
413
-
414
- foreach ( $coauthors as $coauthor ) {
415
- $user_id = $coauthor->ID;
416
- $meta[ $user_id ] = get_the_author_meta( $field, $user_id );
417
- }
418
- return $meta;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  }
420
 
 
421
  function the_coauthor_meta( $field, $user_id = 0 ) {
422
- // TODO: need before after options
423
- echo get_the_coauthor_meta( $field, $user_id );
 
 
 
424
  }
425
 
426
  /**
@@ -438,16 +534,17 @@ function coauthors_wp_list_authors( $args = array() ) {
438
  global $coauthors_plus;
439
 
440
  $defaults = array(
441
- 'optioncount' => false,
442
- 'show_fullname' => false,
443
- 'hide_empty' => true,
444
- 'feed' => '',
445
- 'feed_image' => '',
446
- 'feed_type' => '',
447
- 'echo' => true,
448
- 'style' => 'list',
449
- 'html' => true,
450
- 'number' => 20, // A sane limit to start to avoid breaking all the things
 
451
  );
452
 
453
  $args = wp_parse_args( $args, $defaults );
@@ -459,6 +556,7 @@ function coauthors_wp_list_authors( $args = array() ) {
459
  'number' => (int) $args['number'],
460
  );
461
  $author_terms = get_terms( $coauthors_plus->coauthor_taxonomy, $term_args );
 
462
  $authors = array();
463
  foreach ( $author_terms as $author_term ) {
464
  // Something's wrong in the state of Denmark
@@ -468,11 +566,23 @@ function coauthors_wp_list_authors( $args = array() ) {
468
 
469
  $authors[ $author_term->name ] = $coauthor;
470
 
471
- $authors[ $author_term->name ]->post_count = $author_term->count;
 
 
 
 
 
 
472
  }
473
 
474
  $authors = apply_filters( 'coauthors_wp_list_authors_array', $authors );
475
 
 
 
 
 
 
 
476
  foreach ( (array) $authors as $author ) {
477
 
478
  $link = '';
@@ -511,12 +621,16 @@ function coauthors_wp_list_authors( $args = array() ) {
511
  if ( empty( $args['feed_image'] ) ) {
512
  $link .= '(';
513
  }
514
- $link .= '<a href="' . get_author_feed_link( $author->ID ) . '"';
 
 
 
515
 
516
  if ( ! empty( $args['feed'] ) ) {
 
517
  $title = ' title="' . esc_attr( $args['feed'] ) . '"';
518
- $alt = ' alt="' . esc_attr( $args['feed'] ) . '"';
519
- $name = $feed;
520
  $link .= $title;
521
  }
522
 
35
  }
36
  } // the empty else case is because if we force guest authors, we don't ever care what value wp_posts.post_author has.
37
  }
38
+ // remove duplicate $coauthors objects from mapping user accounts to guest authors accounts
39
+ $coauthors = array_unique( $coauthors, SORT_REGULAR );
40
  return $coauthors;
41
  }
42
 
236
  * @param bool $echo Whether the co-authors should be echoed or returned. Defaults to true.
237
  */
238
  function coauthors_posts_links( $between = null, $betweenLast = null, $before = null, $after = null, $echo = true ) {
239
+
240
+ global $coauthors_plus_template_filters;
241
+
242
+ $modify_filter = ! empty( $coauthors_plus_template_filters ) && $coauthors_plus_template_filters instanceof CoAuthors_Template_Filters;
243
+
244
+ if ( $modify_filter ) {
245
+
246
+ /**
247
+ * Removing "the_author" filter so that it won't get called in loop and append names for each author.
248
+ *
249
+ * Ref : https://github.com/Automattic/Co-Authors-Plus/issues/279
250
+ */
251
+ remove_filter( 'the_author', array( $coauthors_plus_template_filters, 'filter_the_author' ) );
252
+ }
253
+
254
+ $coauthors_posts_links = coauthors__echo( 'coauthors_posts_links_single', 'callback', array(
255
+ 'between' => $between,
256
  'betweenLast' => $betweenLast,
257
+ 'before' => $before,
258
+ 'after' => $after,
259
  ), null, $echo );
260
+
261
+ if ( $modify_filter ) {
262
+ add_filter( 'the_author', array( $coauthors_plus_template_filters, 'filter_the_author' ) );
263
+ }
264
+
265
+ return $coauthors_posts_links;
266
  }
267
 
268
  /**
366
  * @param bool $echo Whether the co-authors should be echoed or returned. Defaults to true.
367
  */
368
  function coauthors_links( $between = null, $betweenLast = null, $before = null, $after = null, $echo = true ) {
369
+
370
+ global $coauthors_plus_template_filters;
371
+
372
+ $modify_filter = ! empty( $coauthors_plus_template_filters ) && $coauthors_plus_template_filters instanceof CoAuthors_Template_Filters;
373
+
374
+ if ( $modify_filter ) {
375
+
376
+ /**
377
+ * Removing "the_author" filter so that it won't get called in loop and append names for each author.
378
+ *
379
+ * Ref : https://github.com/Automattic/Co-Authors-Plus/issues/279
380
+ */
381
+ remove_filter( 'the_author', array( $coauthors_plus_template_filters, 'filter_the_author' ) );
382
+ }
383
+
384
+ $coauthors_links = coauthors__echo( 'coauthors_links_single', 'callback', array(
385
+ 'between' => $between,
386
  'betweenLast' => $betweenLast,
387
+ 'before' => $before,
388
+ 'after' => $after,
389
  ), null, $echo );
390
+
391
+ if ( $modify_filter ) {
392
+ add_filter( 'the_author', array( $coauthors_plus_template_filters, 'filter_the_author' ) );
393
+ }
394
+
395
+ return $coauthors_links;
396
  }
397
 
398
  /**
420
  * @return string
421
  */
422
  function coauthors_links_single( $author ) {
423
+ if ( 'guest-author' === $author->type ) {
424
+ if ( get_the_author_meta( 'website' ) ) {
425
+ return sprintf( '<a href="%s" title="%s" rel="external" target="_blank">%s</a>',
426
+ esc_url( get_the_author_meta( 'website' ) ),
427
+ esc_attr( sprintf( __( 'Visit %s&#8217;s website' ), esc_html( get_the_author() ) ) ),
428
+ esc_html( get_the_author() )
429
+ );
430
+ }
431
+ }
432
+ elseif ( get_the_author_meta( 'url' ) ) {
433
+ return sprintf( '<a href="%s" title="%s" rel="external" target="_blank">%s</a>',
434
+ esc_url( get_the_author_meta( 'url' ) ),
435
+ esc_attr( sprintf( __( 'Visit %s&#8217;s website' ), esc_html( get_the_author() ) ) ),
436
+ esc_html( get_the_author() )
437
  );
438
+ }
439
+ else {
440
+ return esc_html( get_the_author() );
441
  }
442
  }
443
 
459
  ), null, $echo );
460
  }
461
 
462
+ /**
463
+ * Outputs the co-authors Meta Data
464
+ *
465
+ * @param string $field Required The user field to retrieve.[login, email, nicename, display_name, url, type]
466
+ * @param string $user_id Optional The user ID for meta
467
+ *
468
+ * @return array $meta Value of the user field
469
+ */
470
+ function get_the_coauthor_meta( $field, $user_id = false ) {
471
+ global $coauthors_plus;
472
+
473
+ if ( ! $user_id ) {
474
+ $coauthors = get_coauthors();
475
+ }
476
+ else {
477
+ $coauthor_data = $coauthors_plus->get_coauthor_by( 'id', $user_id );
478
+ $coauthors = array();
479
+ if ( ! empty( $coauthor_data ) ) {
480
+ $coauthors[] = $coauthor_data;
481
+ }
482
+ }
483
+
484
+ $meta = array();
485
+
486
+ if ( in_array( $field, array( 'login', 'pass', 'nicename', 'email', 'url', 'registered', 'activation_key', 'status' ) ) ) {
487
+ $field = 'user_' . $field;
488
+ }
489
+
490
+ foreach ( $coauthors as $coauthor ) {
491
+ $user_id = $coauthor->ID;
492
+
493
+ if ( isset( $coauthor->type ) && 'user_url' === $field ) {
494
+ if ( 'guest-author' === $coauthor->type ) {
495
+ $field = 'website';
496
+ }
497
+ }
498
+ else if ( 'website' === $field ) {
499
+ $field = 'user_url';
500
+ }
501
+
502
+ if ( isset( $coauthor->$field ) ) {
503
+ $meta[ $user_id ] = $coauthor->$field;
504
+ }
505
+ else {
506
+ $meta[ $user_id ] = '';
507
+ }
508
+ }
509
+
510
+ return $meta;
511
  }
512
 
513
+
514
  function the_coauthor_meta( $field, $user_id = 0 ) {
515
+ // TODO: need before after options
516
+ $coauthor_meta = get_the_coauthor_meta( $field, $user_id );
517
+ foreach ( $coauthor_meta as $meta ) {
518
+ echo esc_html( $meta );
519
+ }
520
  }
521
 
522
  /**
534
  global $coauthors_plus;
535
 
536
  $defaults = array(
537
+ 'optioncount' => false,
538
+ 'show_fullname' => false,
539
+ 'hide_empty' => true,
540
+ 'feed' => '',
541
+ 'feed_image' => '',
542
+ 'feed_type' => '',
543
+ 'echo' => true,
544
+ 'style' => 'list',
545
+ 'html' => true,
546
+ 'number' => 20, // A sane limit to start to avoid breaking all the things
547
+ 'guest_authors_only' => false
548
  );
549
 
550
  $args = wp_parse_args( $args, $defaults );
556
  'number' => (int) $args['number'],
557
  );
558
  $author_terms = get_terms( $coauthors_plus->coauthor_taxonomy, $term_args );
559
+
560
  $authors = array();
561
  foreach ( $author_terms as $author_term ) {
562
  // Something's wrong in the state of Denmark
566
 
567
  $authors[ $author_term->name ] = $coauthor;
568
 
569
+ // only show guest authors if the $args is set to true
570
+ if ( ! $args['guest_authors_only'] || $authors[ $author_term->name ]->type === 'guest-author' ) {
571
+ $authors[ $author_term->name ]->post_count = $author_term->count;
572
+ }
573
+ else {
574
+ unset( $authors[ $author_term->name ] );
575
+ }
576
  }
577
 
578
  $authors = apply_filters( 'coauthors_wp_list_authors_array', $authors );
579
 
580
+ // remove duplicates from linked accounts
581
+ $linked_accounts = array_unique( array_column( $authors, 'linked_account' ) );
582
+ foreach ( $linked_accounts as $linked_account ) {
583
+ unset( $authors[$linked_account] );
584
+ }
585
+
586
  foreach ( (array) $authors as $author ) {
587
 
588
  $link = '';
621
  if ( empty( $args['feed_image'] ) ) {
622
  $link .= '(';
623
  }
624
+ $link .= '<a href="' . esc_url( get_author_feed_link( $author->ID, $args['feed_type'] ) ) . '"';
625
+
626
+ $alt = '';
627
+ $title = '';
628
 
629
  if ( ! empty( $args['feed'] ) ) {
630
+
631
  $title = ' title="' . esc_attr( $args['feed'] ) . '"';
632
+ $alt = ' alt="' . esc_attr( $args['feed'] ) . '"';
633
+ $name = $args['feed'];
634
  $link .= $title;
635
  }
636
 
tests/test-author-queried-object.php CHANGED
@@ -52,12 +52,6 @@ class Test_Author_Queried_Object extends CoAuthorsPlus_TestCase {
52
  $this->go_to( get_author_posts_url( $author1 ) );
53
  $this->assertQueryTrue( 'is_author', 'is_archive' );
54
 
55
- /**
56
- * Author 2 is not yet an author on the blog
57
- */
58
- $this->go_to( get_author_posts_url( $author2 ) );
59
- $this->assertQueryTrue( 'is_404' );
60
-
61
  // Add the user to the blog
62
  add_user_to_blog( $blog2, $author2, 'author' );
63
 
@@ -93,7 +87,6 @@ class Test_Author_Queried_Object extends CoAuthorsPlus_TestCase {
93
  * Author 2 is no more
94
  */
95
  $this->go_to( get_author_posts_url( $author2 ) );
96
- $this->assertQueryTrue( 'is_404' );
97
  $this->assertEquals( false, get_user_by( 'id', $author2 ) );
98
 
99
  restore_current_blog();
52
  $this->go_to( get_author_posts_url( $author1 ) );
53
  $this->assertQueryTrue( 'is_author', 'is_archive' );
54
 
 
 
 
 
 
 
55
  // Add the user to the blog
56
  add_user_to_blog( $blog2, $author2, 'author' );
57
 
87
  * Author 2 is no more
88
  */
89
  $this->go_to( get_author_posts_url( $author2 ) );
 
90
  $this->assertEquals( false, get_user_by( 'id', $author2 ) );
91
 
92
  restore_current_blog();
tests/test-coauthors-guest-authors.php ADDED
@@ -0,0 +1,890 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_CoAuthors_Guest_Authors extends CoAuthorsPlus_TestCase {
4
+
5
+ public function setUp() {
6
+
7
+ parent::setUp();
8
+
9
+ $this->admin1 = $this->factory->user->create_and_get( array( 'role' => 'administrator', 'user_login' => 'admin1' ) );
10
+ $this->author1 = $this->factory->user->create_and_get( array( 'role' => 'author', 'user_login' => 'author1' ) );
11
+ $this->editor1 = $this->factory->user->create_and_get( array( 'role' => 'editor', 'user_login' => 'editor1' ) );
12
+
13
+ $this->post = $this->factory->post->create_and_get( array(
14
+ 'post_author' => $this->author1->ID,
15
+ 'post_status' => 'publish',
16
+ 'post_content' => rand_str(),
17
+ 'post_title' => rand_str(),
18
+ 'post_type' => 'post',
19
+ ) );
20
+ }
21
+
22
+ /**
23
+ * Checks a simulated WP_User object based on the post ID when key or value is empty.
24
+ *
25
+ * @covers CoAuthors_Guest_Authors::get_guest_author_by()
26
+ */
27
+ public function test_get_guest_author_by_with_empty_key_or_value() {
28
+
29
+ global $coauthors_plus;
30
+
31
+ $guest_author_obj = $coauthors_plus->guest_authors;
32
+
33
+ // Fetch guest author without forcefully.
34
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( '', '' ) );
35
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( 'ID', '' ) );
36
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( '', $this->author1->ID ) );
37
+
38
+ // Fetch guest author forcefully.
39
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( '', '', true ) );
40
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( 'ID', '', true ) );
41
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( '', $this->author1->ID, true ) );
42
+ }
43
+
44
+ /**
45
+ * Checks a simulated WP_User object based on the post ID using cache.
46
+ *
47
+ * @covers CoAuthors_Guest_Authors::get_guest_author_by()
48
+ */
49
+ public function test_get_guest_author_by_using_cache() {
50
+
51
+ global $coauthors_plus;
52
+
53
+ $guest_author_obj = $coauthors_plus->guest_authors;
54
+
55
+ $guest_author_id = $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
56
+
57
+ $cache_key = $guest_author_obj->get_cache_key( 'ID', $guest_author_id );
58
+
59
+ // Checks when guest author does not exist in cache.
60
+ $this->assertFalse( wp_cache_get( $cache_key, $guest_author_obj::$cache_group ) );
61
+
62
+ // Checks when guest author exists in cache.
63
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
64
+ $guest_author_cached = wp_cache_get( $cache_key, $guest_author_obj::$cache_group );
65
+
66
+ $this->assertInstanceOf( stdClass::class, $guest_author );
67
+ $this->assertEquals( $guest_author, $guest_author_cached );
68
+ }
69
+
70
+ /**
71
+ * Checks a simulated WP_User object based on the post ID using different key/value.
72
+ *
73
+ * @covers CoAuthors_Guest_Authors::get_guest_author_by()
74
+ */
75
+ public function test_get_guest_author_by_with_different_keys() {
76
+
77
+ global $coauthors_plus;
78
+
79
+ $guest_author_obj = $coauthors_plus->guest_authors;
80
+
81
+ // Checks when user is not a guest author.
82
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( 'ID', $this->author1->ID ) );
83
+ $this->assertFalse( $guest_author_obj->get_guest_author_by( 'ID', $this->author1->ID, true ) );
84
+
85
+ $guest_author_id = $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
86
+
87
+ // Checks guest author using ID.
88
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
89
+
90
+ $this->assertInstanceOf( stdClass::class, $guest_author );
91
+ $this->assertEquals( $guest_author_id, $guest_author->ID );
92
+ $this->assertEquals( $guest_author_obj->post_type, $guest_author->type );
93
+
94
+ // Checks guest author using user_nicename.
95
+ $guest_author = $guest_author_obj->get_guest_author_by( 'user_nicename', $this->editor1->user_nicename );
96
+
97
+ $this->assertInstanceOf( stdClass::class, $guest_author );
98
+ $this->assertEquals( $guest_author_obj->post_type, $guest_author->type );
99
+
100
+ // Checks guest author using linked_account.
101
+ $guest_author = $guest_author_obj->get_guest_author_by( 'linked_account', $this->editor1->user_login );
102
+
103
+ $this->assertInstanceOf( stdClass::class, $guest_author );
104
+ $this->assertEquals( $guest_author_obj->post_type, $guest_author->type );
105
+ }
106
+
107
+ /**
108
+ * Checks thumbnail for a guest author object.
109
+ *
110
+ * @covers CoAuthors_Guest_Authors::get_guest_author_thumbnail()
111
+ */
112
+ public function test_get_guest_author_thumbnail() {
113
+
114
+ global $coauthors_plus;
115
+
116
+ $guest_author_obj = $coauthors_plus->guest_authors;
117
+
118
+ // Checks when guest author does not have any thumbnail.
119
+ $guest_author_id = $guest_author_obj->create( array(
120
+ 'user_login' => 'author2',
121
+ 'display_name' => 'author2',
122
+ ) );
123
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
124
+
125
+ $this->assertNull( $guest_author_obj->get_guest_author_thumbnail( $guest_author, 0 ) );
126
+
127
+ // Checks when guest author has thumbnail.
128
+ $filename = rand_str() . '.jpg';
129
+ $contents = rand_str();
130
+ $upload = wp_upload_bits( $filename, null, $contents );
131
+
132
+ $this->assertTrue( empty( $upload['error'] ) );
133
+
134
+ $attachment_id = $this->_make_attachment( $upload );
135
+
136
+ set_post_thumbnail( $guest_author->ID, $attachment_id );
137
+
138
+ $thumbnail = $guest_author_obj->get_guest_author_thumbnail( $guest_author, 0 );
139
+
140
+ $this->assertContains( 'avatar-0', $thumbnail );
141
+ $this->assertContains( $filename, $thumbnail );
142
+ $this->assertContains( 'src="' . wp_get_attachment_url( $attachment_id ) . '"', $thumbnail );
143
+ }
144
+
145
+ /**
146
+ * Checks all of the meta fields that can be associated with a guest author.
147
+ *
148
+ * @covers CoAuthors_Guest_Authors::get_guest_author_fields()
149
+ */
150
+ public function test_get_guest_author_fields() {
151
+
152
+ global $coauthors_plus;
153
+
154
+ $guest_author_obj = $coauthors_plus->guest_authors;
155
+
156
+ // Checks all the meta fields.
157
+ $fields = $guest_author_obj->get_guest_author_fields();
158
+
159
+ $this->assertNotEmpty( $fields );
160
+ $this->assertInternalType( 'array', $fields );
161
+
162
+ $keys = wp_list_pluck( $fields, 'key' );
163
+
164
+ $global_fields = array(
165
+ 'display_name',
166
+ 'first_name',
167
+ 'last_name',
168
+ 'user_login',
169
+ 'user_email',
170
+ 'linked_account',
171
+ 'website',
172
+ 'aim',
173
+ 'yahooim',
174
+ 'jabber',
175
+ 'description',
176
+ );
177
+
178
+ $this->assertEquals( $global_fields, $keys );
179
+
180
+ // Checks all the meta fields with group that does not exist.
181
+ $fields = $guest_author_obj->get_guest_author_fields( 'test' );
182
+
183
+ $this->assertEmpty( $fields );
184
+
185
+ // Checks all the meta fields with group "name".
186
+ $fields = $guest_author_obj->get_guest_author_fields( 'name' );
187
+ $keys = wp_list_pluck( $fields, 'key' );
188
+
189
+ $this->assertEquals( array( 'display_name', 'first_name', 'last_name' ), $keys );
190
+
191
+ // Checks all the meta fields with group "slug".
192
+ $fields = $guest_author_obj->get_guest_author_fields( 'slug' );
193
+ $keys = wp_list_pluck( $fields, 'key' );
194
+
195
+ $this->assertEquals( array( 'user_login', 'linked_account' ), $keys );
196
+
197
+ // Checks all the meta fields with group "contact-info".
198
+ $fields = $guest_author_obj->get_guest_author_fields( 'contact-info' );
199
+ $keys = wp_list_pluck( $fields, 'key' );
200
+
201
+ $this->assertEquals( array( 'user_email', 'website', 'aim', 'yahooim', 'jabber' ), $keys );
202
+
203
+ // Checks all the meta fields with group "about".
204
+ $fields = $guest_author_obj->get_guest_author_fields( 'about' );
205
+ $keys = wp_list_pluck( $fields, 'key' );
206
+
207
+ $this->assertEquals( array( 'description' ), $keys );
208
+ }
209
+
210
+ /**
211
+ * Checks all of the user accounts that have been linked.
212
+ *
213
+ * @covers CoAuthors_Guest_Authors::get_all_linked_accounts()
214
+ */
215
+ public function test_get_all_linked_accounts() {
216
+
217
+ global $coauthors_plus;
218
+
219
+ $guest_author_obj = $coauthors_plus->guest_authors;
220
+
221
+ $this->assertEmpty( $guest_author_obj->get_all_linked_accounts() );
222
+
223
+ // Checks when guest author ( not linked account ) exists.
224
+ $guest_author_obj->create( array(
225
+ 'user_login' => 'author2',
226
+ 'display_name' => 'author2',
227
+ ) );
228
+
229
+ $this->assertEmpty( $guest_author_obj->get_all_linked_accounts() );
230
+
231
+ // Create guest author from existing user and check.
232
+ $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
233
+
234
+ $linked_accounts = $guest_author_obj->get_all_linked_accounts();
235
+ $linked_account_ids = wp_list_pluck( $linked_accounts, 'ID' );
236
+
237
+ $this->assertNotEmpty( $linked_accounts );
238
+ $this->assertInternalType( 'array', $linked_accounts );
239
+ $this->assertTrue( in_array( $this->editor1->ID, $linked_account_ids, true ) );
240
+ }
241
+
242
+ /**
243
+ * Checks all of the user accounts that have been linked using cache.
244
+ *
245
+ * @covers CoAuthors_Guest_Authors::get_all_linked_accounts()
246
+ */
247
+ public function test_get_all_linked_accounts_with_cache() {
248
+
249
+ global $coauthors_plus;
250
+
251
+ $guest_author_obj = $coauthors_plus->guest_authors;
252
+
253
+ $cache_key = 'all-linked-accounts';
254
+
255
+ // Checks when guest author does not exist in cache.
256
+ $this->assertFalse( wp_cache_get( $cache_key, $guest_author_obj::$cache_group ) );
257
+
258
+ // Checks when guest author exists in cache.
259
+ $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
260
+
261
+ $linked_accounts = $guest_author_obj->get_all_linked_accounts();
262
+ $linked_accounts_cache = wp_cache_get( $cache_key, $guest_author_obj::$cache_group );
263
+
264
+ $this->assertEquals( $linked_accounts, $linked_accounts_cache );
265
+ }
266
+
267
+ /**
268
+ * Checks guest author from an existing WordPress user.
269
+ *
270
+ * @covers CoAuthors_Guest_Authors::create_guest_author_from_user_id()
271
+ */
272
+ public function test_create_guest_author_from_user_id() {
273
+
274
+ global $coauthors_plus;
275
+
276
+ $guest_author_obj = $coauthors_plus->guest_authors;
277
+
278
+ // Checks create guest author when user don't exist.
279
+ $response = $guest_author_obj->create_guest_author_from_user_id( 0 );
280
+
281
+ $this->assertInstanceOf( 'WP_Error', $response );
282
+ $this->assertEquals( 'invalid-user', $response->get_error_code() );
283
+
284
+ // Checks create guest author when user exist.
285
+ $guest_author_id = $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
286
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
287
+
288
+ $this->assertInstanceOf( stdClass::class, $guest_author );
289
+ }
290
+
291
+ /**
292
+ * Checks delete guest author action when $_POST args are not set.
293
+ *
294
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
295
+ */
296
+ public function test_handle_delete_guest_author_action_when_post_args_not_as_expected() {
297
+
298
+ global $coauthors_plus;
299
+
300
+ $guest_author_obj = $coauthors_plus->guest_authors;
301
+
302
+ // Checks when nothing is set.
303
+ $this->assertNull( $guest_author_obj->handle_delete_guest_author_action() );
304
+
305
+ // Back up $_POST.
306
+ $_post_backup = $_POST;
307
+
308
+ // Checks when action is set but not expected.
309
+ $_POST['action'] = 'test';
310
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
311
+
312
+ $this->assertNull( $guest_author_obj->handle_delete_guest_author_action() );
313
+
314
+ // Get guest author and check that is should not be removed.
315
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $_POST['id'] );
316
+
317
+ $this->assertNotEmpty( $guest_author );
318
+
319
+ // Checks when _wpnonce and id not set.
320
+ $_POST['action'] = 'delete-guest-author';
321
+ $_POST['reassign'] = 'test';
322
+
323
+ $this->assertNull( $guest_author_obj->handle_delete_guest_author_action() );
324
+
325
+ // Get guest author and check that is should not be removed.
326
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $_POST['id'] );
327
+
328
+ $this->assertNotEmpty( $guest_author );
329
+
330
+ // Checks when all args set for $_POST but action is not as expected.
331
+ $_POST['action'] = 'test';
332
+ $_POST['reassign'] = 'test';
333
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author-1' );
334
+
335
+ $this->assertNull( $guest_author_obj->handle_delete_guest_author_action() );
336
+
337
+ // Get guest author and check that is should not be removed.
338
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $_POST['id'] );
339
+
340
+ $this->assertNotEmpty( $guest_author );
341
+
342
+ // Restore $_POST from back up.
343
+ $_POST = $_post_backup;
344
+ }
345
+
346
+ /**
347
+ * Checks delete guest author action with nonce.
348
+ *
349
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
350
+ */
351
+ public function test_handle_delete_guest_author_action_with_nonce() {
352
+
353
+ global $coauthors_plus;
354
+
355
+ $guest_author_obj = $coauthors_plus->guest_authors;
356
+
357
+ // Back up $_POST.
358
+ $_post_backup = $_POST;
359
+
360
+ $expected = __( "Doin' something fishy, huh?", 'co-authors-plus' );
361
+
362
+ $_POST['action'] = 'delete-guest-author';
363
+ $_POST['reassign'] = 'test';
364
+ $_POST['id'] = '0';
365
+
366
+ // Checks when nonce is not as expected.
367
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author-1' );
368
+
369
+ try {
370
+ $guest_author_obj->handle_delete_guest_author_action();
371
+ } catch ( Exception $e ) {
372
+ $exception = $e;
373
+ }
374
+
375
+ $this->assertInstanceOf( 'WPDieException', $exception );
376
+ $this->assertContains( esc_html( $expected ), $exception->getMessage() );
377
+
378
+ // Checks when nonce is as expected.
379
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
380
+
381
+ try {
382
+ $guest_author_obj->handle_delete_guest_author_action();
383
+ } catch ( Exception $e ) {
384
+ $exception = $e;
385
+ }
386
+
387
+ $this->assertNotContains( esc_html( $expected ), $exception->getMessage() );
388
+
389
+ // Restore $_POST from back up.
390
+ $_POST = $_post_backup;
391
+ }
392
+
393
+ /**
394
+ * Checks delete guest author action with list_author capability.
395
+ *
396
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
397
+ */
398
+ public function test_handle_delete_guest_author_action_with_list_users_capability() {
399
+
400
+ global $coauthors_plus;
401
+
402
+ $guest_author_obj = $coauthors_plus->guest_authors;
403
+
404
+ // Back up $_POST.
405
+ $_post_backup = $_POST;
406
+
407
+ $expected = __( "You don't have permission to perform this action.", 'co-authors-plus' );
408
+
409
+ // Back up current user.
410
+ $current_user = get_current_user_id();
411
+
412
+ wp_set_current_user( $this->editor1->ID );
413
+
414
+ $_POST['action'] = 'delete-guest-author';
415
+ $_POST['reassign'] = 'test';
416
+
417
+ // Checks when current user can not have list_users capability.
418
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
419
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->editor1->ID );
420
+
421
+ try {
422
+ $guest_author_obj->handle_delete_guest_author_action();
423
+ } catch ( Exception $e ) {
424
+ $exception = $e;
425
+ }
426
+
427
+ $this->assertInstanceOf( 'WPDieException', $exception );
428
+ $this->assertContains( esc_html( $expected ), $exception->getMessage() );
429
+
430
+ // Checks when current user has list_users capability.
431
+ wp_set_current_user( $this->admin1->ID );
432
+
433
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
434
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
435
+
436
+ try {
437
+ $guest_author_obj->handle_delete_guest_author_action();
438
+ } catch ( Exception $e ) {
439
+ $exception = $e;
440
+ }
441
+
442
+ $this->assertNotContains( esc_html( $expected ), $exception->getMessage() );
443
+
444
+ // Restore current user from backup.
445
+ wp_set_current_user( $current_user );
446
+
447
+ // Restore $_POST from back up.
448
+ $_POST = $_post_backup;
449
+ }
450
+
451
+ /**
452
+ * Checks delete guest author action with guest author.
453
+ *
454
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
455
+ */
456
+ public function test_handle_delete_guest_author_action_with_guest_author_existence() {
457
+
458
+ global $coauthors_plus;
459
+
460
+ $guest_author_obj = $coauthors_plus->guest_authors;
461
+
462
+ // Back up $_POST.
463
+ $_post_backup = $_POST;
464
+
465
+ $expected = sprintf( __( "%s can't be deleted because it doesn't exist.", 'co-authors-plus' ), $guest_author_obj->labels['singular'] );
466
+
467
+ // Back up current user.
468
+ $current_user = get_current_user_id();
469
+
470
+ wp_set_current_user( $this->admin1->ID );
471
+
472
+ $_POST['action'] = 'delete-guest-author';
473
+ $_POST['reassign'] = 'test';
474
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
475
+ $_POST['id'] = $this->admin1->ID;
476
+
477
+ // Checks when guest author does not exist.
478
+ try {
479
+ $guest_author_obj->handle_delete_guest_author_action();
480
+ } catch ( Exception $e ) {
481
+ $exception = $e;
482
+ }
483
+
484
+ $this->assertInstanceOf( 'WPDieException', $exception );
485
+ $this->assertContains( esc_html( $expected ), $exception->getMessage() );
486
+
487
+ // Checks when guest author exists.
488
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
489
+
490
+ try {
491
+ $guest_author_obj->handle_delete_guest_author_action();
492
+ } catch ( Exception $e ) {
493
+ $exception = $e;
494
+ }
495
+
496
+ $this->assertNotContains( esc_html( $expected ), $exception->getMessage() );
497
+
498
+ // Restore current user from backup.
499
+ wp_set_current_user( $current_user );
500
+
501
+ // Restore $_POST from back up.
502
+ $_POST = $_post_backup;
503
+ }
504
+
505
+ /**
506
+ * Checks delete guest author action with reassign not as expected.
507
+ *
508
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
509
+ */
510
+ public function test_handle_delete_guest_author_action_with_reassign_not_as_expected() {
511
+
512
+ global $coauthors_plus;
513
+
514
+ $guest_author_obj = $coauthors_plus->guest_authors;
515
+
516
+ // Back up $_POST.
517
+ $_post_backup = $_POST;
518
+
519
+ $expected = __( 'Please make sure to pick an option.', 'co-authors-plus' );
520
+
521
+ // Back up current user.
522
+ $current_user = get_current_user_id();
523
+
524
+ wp_set_current_user( $this->admin1->ID );
525
+
526
+ $_POST['action'] = 'delete-guest-author';
527
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
528
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
529
+
530
+ // Checks when reassign is not as expected.
531
+ $_POST['reassign'] = 'test';
532
+
533
+ try {
534
+ $guest_author_obj->handle_delete_guest_author_action();
535
+ } catch ( Exception $e ) {
536
+ $exception = $e;
537
+ }
538
+
539
+ $this->assertInstanceOf( 'WPDieException', $exception );
540
+ $this->assertContains( esc_html( $expected ), $exception->getMessage() );
541
+
542
+ // Restore current user from backup.
543
+ wp_set_current_user( $current_user );
544
+
545
+ // Restore $_POST from back up.
546
+ $_POST = $_post_backup;
547
+ }
548
+
549
+ /**
550
+ * Checks delete guest author action when reassign is leave-assigned.
551
+ *
552
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
553
+ */
554
+ public function test_handle_delete_guest_author_action_with_reassign_is_leave_assigned() {
555
+
556
+ global $coauthors_plus;
557
+
558
+ $guest_author_obj = $coauthors_plus->guest_authors;
559
+
560
+ // Back up $_POST.
561
+ $_post_backup = $_POST;
562
+
563
+ // Back up current user.
564
+ $current_user = get_current_user_id();
565
+
566
+ wp_set_current_user( $this->admin1->ID );
567
+
568
+ $_POST['action'] = 'delete-guest-author';
569
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
570
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
571
+ $_POST['reassign'] = 'leave-assigned';
572
+
573
+ add_filter( 'wp_redirect', array( $this, 'catch_redirect_destination' ), 99, 2 );
574
+
575
+ try {
576
+
577
+ $guest_author_obj->handle_delete_guest_author_action();
578
+
579
+ } catch( Exception $e ) {
580
+
581
+ $this->assertContains( $guest_author_obj->parent_page, $e->getMessage() );
582
+ $this->assertContains( 'page=view-guest-authors', $e->getMessage() );
583
+ $this->assertContains( 'message=guest-author-deleted', $e->getMessage() );
584
+ }
585
+
586
+ remove_filter( 'wp_redirect', array( $this, 'catch_redirect_destination' ), 99 );
587
+
588
+ // Restore current user from backup.
589
+ wp_set_current_user( $current_user );
590
+
591
+ // Restore $_POST from back up.
592
+ $_POST = $_post_backup;
593
+ }
594
+
595
+ /**
596
+ * Checks delete guest author action when reassign is reassign-another.
597
+ *
598
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
599
+ */
600
+ public function test_handle_delete_guest_author_action_with_reassign_is_reassign_another() {
601
+
602
+ global $coauthors_plus;
603
+
604
+ $guest_author_obj = $coauthors_plus->guest_authors;
605
+
606
+ // Back up $_POST.
607
+ $_post_backup = $_POST;
608
+
609
+ // Back up current user.
610
+ $current_user = get_current_user_id();
611
+
612
+ $expected = __( 'Co-author does not exists. Try again?', 'co-authors-plus' );
613
+
614
+ wp_set_current_user( $this->admin1->ID );
615
+
616
+ $_POST['action'] = 'delete-guest-author';
617
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
618
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
619
+ $_POST['reassign'] = 'reassign-another';
620
+
621
+ // When coauthor does not exist.
622
+ $_POST['leave-assigned-to'] = 'test';
623
+
624
+ try {
625
+ $guest_author_obj->handle_delete_guest_author_action();
626
+ } catch ( Exception $e ) {
627
+ $exception = $e;
628
+ }
629
+
630
+ $this->assertInstanceOf( 'WPDieException', $exception );
631
+ $this->assertContains( esc_html( $expected ), $exception->getMessage() );
632
+
633
+ // When coauthor exists.
634
+ $_POST['leave-assigned-to'] = $this->author1->user_nicename;
635
+
636
+ add_filter( 'wp_redirect', array( $this, 'catch_redirect_destination' ), 99, 2 );
637
+
638
+ try {
639
+
640
+ $guest_author_obj->handle_delete_guest_author_action();
641
+
642
+ } catch ( Exception $e ) {
643
+
644
+ //$this->assertContains( $guest_author_obj->parent_page, $e->getMessage() );
645
+ $this->assertContains( 'page=view-guest-authors', $e->getMessage() );
646
+ $this->assertContains( 'message=guest-author-deleted', $e->getMessage() );
647
+ }
648
+
649
+ remove_filter( 'wp_redirect', array( $this, 'catch_redirect_destination' ), 99 );
650
+
651
+ // Restore current user from backup.
652
+ wp_set_current_user( $current_user );
653
+
654
+ // Restore $_POST from back up.
655
+ $_POST = $_post_backup;
656
+ }
657
+
658
+ /**
659
+ * Checks delete guest author action when reassign is remove-byline.
660
+ *
661
+ * @covers CoAuthors_Guest_Authors::handle_delete_guest_author_action()
662
+ */
663
+ public function test_handle_delete_guest_author_action_with_reassign_is_remove_byline() {
664
+
665
+ global $coauthors_plus;
666
+
667
+ $guest_author_obj = $coauthors_plus->guest_authors;
668
+
669
+ // Back up $_POST.
670
+ $_post_backup = $_POST;
671
+
672
+ // Back up current user.
673
+ $current_user = get_current_user_id();
674
+
675
+ wp_set_current_user( $this->admin1->ID );
676
+
677
+ $_POST['action'] = 'delete-guest-author';
678
+ $_POST['_wpnonce'] = wp_create_nonce( 'delete-guest-author' );
679
+ $_POST['id'] = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
680
+ $_POST['reassign'] = 'remove-byline';
681
+
682
+ add_filter( 'wp_redirect', array( $this, 'catch_redirect_destination' ), 99, 2 );
683
+
684
+ try {
685
+
686
+ $guest_author_obj->handle_delete_guest_author_action();
687
+
688
+ } catch ( Exception $e ) {
689
+
690
+ $this->assertContains( $guest_author_obj->parent_page, $e->getMessage() );
691
+ $this->assertContains( 'page=view-guest-authors', $e->getMessage() );
692
+ $this->assertContains( 'message=guest-author-deleted', $e->getMessage() );
693
+ }
694
+
695
+ remove_filter( 'wp_redirect', array( $this, 'catch_redirect_destination' ), 99 );
696
+
697
+ // Restore current user from backup.
698
+ wp_set_current_user( $current_user );
699
+
700
+ // Restore $_POST from back up.
701
+ $_POST = $_post_backup;
702
+ }
703
+
704
+ /**
705
+ * To catch any redirection and throw location and status in Exception.
706
+ *
707
+ * Note : Destination location can be get from Exception Message and
708
+ * status can be get from Exception code.
709
+ *
710
+ * @param string $location Redirected location.
711
+ * @param int $status Status.
712
+ *
713
+ * @throws \Exception Redirection data.
714
+ *
715
+ * @return void
716
+ **/
717
+ public function catch_redirect_destination( $location, $status ) {
718
+
719
+ throw new Exception( $location, $status );
720
+ }
721
+
722
+ /**
723
+ * Checks delete guest author when he/she does not exist.
724
+ *
725
+ * @covers CoAuthors_Guest_Authors::delete()
726
+ */
727
+ public function test_delete_when_guest_author_not_exist() {
728
+
729
+ global $coauthors_plus;
730
+
731
+ $guest_author_obj = $coauthors_plus->guest_authors;
732
+
733
+ $response = $guest_author_obj->delete( $this->admin1->ID );
734
+
735
+ $this->assertInstanceOf( 'WP_Error', $response );
736
+ $this->assertEquals( 'guest-author-missing', $response->get_error_code() );
737
+ }
738
+
739
+ /**
740
+ * Checks delete guest author without reassign author.
741
+ *
742
+ * @covers CoAuthors_Guest_Authors::delete()
743
+ */
744
+ public function test_delete_without_reassign() {
745
+
746
+ global $coauthors_plus;
747
+
748
+ $guest_author_obj = $coauthors_plus->guest_authors;
749
+
750
+ $author2 = $this->factory->user->create_and_get();
751
+ $guest_author_id = $guest_author_obj->create_guest_author_from_user_id( $author2->ID );
752
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
753
+ $guest_author_term = $coauthors_plus->get_author_term( $guest_author );
754
+
755
+ $response = $guest_author_obj->delete( $guest_author_id );
756
+
757
+ $this->assertTrue( $response );
758
+ $this->assertFalse( get_term_by( 'id', $guest_author_term->term_id, $coauthors_plus->coauthor_taxonomy ) );
759
+ $this->assertNull( get_post( $guest_author_id ) );
760
+ }
761
+
762
+ /**
763
+ * Checks delete guest author with reassign author but he/she does not exist.
764
+ *
765
+ * @covers CoAuthors_Guest_Authors::delete()
766
+ */
767
+ public function test_delete_with_reassign_author_not_exist() {
768
+
769
+ global $coauthors_plus;
770
+
771
+ $guest_author_obj = $coauthors_plus->guest_authors;
772
+
773
+ // Checks when reassign author is not exist.
774
+ $author2 = $this->factory->user->create_and_get();
775
+ $guest_author_id = $guest_author_obj->create_guest_author_from_user_id( $author2->ID );
776
+
777
+ $response = $guest_author_obj->delete( $guest_author_id, 'test' );
778
+
779
+ $this->assertInstanceOf( 'WP_Error', $response );
780
+ $this->assertEquals( 'reassign-to-missing', $response->get_error_code() );
781
+ }
782
+
783
+ /**
784
+ * Checks delete guest author with reassign author when linked account and author are same user.
785
+ *
786
+ * @covers CoAuthors_Guest_Authors::delete()
787
+ */
788
+ public function test_delete_with_reassign_when_linked_account_and_author_are_same_user() {
789
+
790
+ global $coauthors_plus;
791
+
792
+ $guest_author_obj = $coauthors_plus->guest_authors;
793
+
794
+ $author2 = $this->factory->user->create_and_get();
795
+ $guest_author2_id = $guest_author_obj->create_guest_author_from_user_id( $author2->ID );
796
+ $guest_author2 = $guest_author_obj->get_guest_author_by( 'ID', $guest_author2_id );
797
+ $guest_author2_term = $coauthors_plus->get_author_term( $guest_author2 );
798
+
799
+ $response = $guest_author_obj->delete( $guest_author2_id, $guest_author2->linked_account );
800
+
801
+ $this->assertTrue( $response );
802
+ $this->assertNotEmpty( get_term_by( 'id', $guest_author2_term->term_id, $coauthors_plus->coauthor_taxonomy ) );
803
+ $this->assertNull( get_post( $guest_author2_id ) );
804
+ }
805
+
806
+ /**
807
+ * Checks delete guest author with reassign author when linked account and author are different user.
808
+ *
809
+ * @covers CoAuthors_Guest_Authors::delete()
810
+ */
811
+ public function test_delete_with_reassign_when_linked_account_and_author_are_different_user() {
812
+
813
+ global $coauthors_plus;
814
+
815
+ $guest_author_obj = $coauthors_plus->guest_authors;
816
+
817
+ $guest_admin_id = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
818
+ $guest_admin = $guest_author_obj->get_guest_author_by( 'ID', $guest_admin_id );
819
+
820
+ $author2 = $this->factory->user->create_and_get();
821
+ $guest_author_id2 = $guest_author_obj->create_guest_author_from_user_id( $author2->ID );
822
+ $guest_author2 = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id2 );
823
+ $guest_author_term2 = $coauthors_plus->get_author_term( $guest_author2 );
824
+
825
+ $post = $this->factory->post->create_and_get( array(
826
+ 'post_author' => $author2->ID,
827
+ ) );
828
+
829
+ $response = $guest_author_obj->delete( $guest_author_id2, $guest_admin->linked_account );
830
+
831
+ // Checks post author, it should be reassigned to new author.
832
+ $this->assertEquals( array( $guest_admin->linked_account ), wp_list_pluck( get_coauthors( $post->ID ), 'linked_account' ) );
833
+ $this->assertTrue( $response );
834
+ $this->assertFalse( get_term_by( 'id', $guest_author_term2->term_id, $coauthors_plus->coauthor_taxonomy ) );
835
+ $this->assertNull( get_post( $guest_author_id2 ) );
836
+ }
837
+
838
+ /**
839
+ * Checks delete guest author with reassign author and without linked account and author is the same user.
840
+ *
841
+ * @covers CoAuthors_Guest_Authors::delete()
842
+ */
843
+ public function test_delete_with_reassign_without_linked_account_and_author_is_same_user() {
844
+
845
+ global $coauthors_plus;
846
+
847
+ $guest_author_obj = $coauthors_plus->guest_authors;
848
+
849
+ $guest_author_id = $guest_author_obj->create( array(
850
+ 'user_login' => 'guest_author',
851
+ 'display_name' => 'guest_author',
852
+ ) );
853
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
854
+ $guest_author_term = $coauthors_plus->get_author_term( $guest_author );
855
+
856
+ $response = $guest_author_obj->delete( $guest_author_id, $guest_author->user_login );
857
+
858
+ $this->assertTrue( $response );
859
+ $this->assertNotEmpty( get_term_by( 'id', $guest_author_term->term_id, $coauthors_plus->coauthor_taxonomy ) );
860
+ $this->assertNull( get_post( $guest_author_id ) );
861
+ }
862
+
863
+ /**
864
+ * Checks delete guest author with reassign author and without linked account and author is other user.
865
+ *
866
+ * @covers CoAuthors_Guest_Authors::delete()
867
+ */
868
+ public function test_delete_with_reassign_without_linked_account_and_author_is_other_user() {
869
+
870
+ global $coauthors_plus;
871
+
872
+ $guest_author_obj = $coauthors_plus->guest_authors;
873
+
874
+ $guest_admin_id = $guest_author_obj->create_guest_author_from_user_id( $this->admin1->ID );
875
+ $guest_admin = $guest_author_obj->get_guest_author_by( 'ID', $guest_admin_id );
876
+
877
+ $guest_author_id = $guest_author_obj->create( array(
878
+ 'user_login' => 'guest_author',
879
+ 'display_name' => 'guest_author',
880
+ ) );
881
+ $guest_author = $guest_author_obj->get_guest_author_by( 'ID', $guest_author_id );
882
+ $guest_author_term = $coauthors_plus->get_author_term( $guest_author );
883
+
884
+ $response = $guest_author_obj->delete( $guest_author_id, $guest_admin->user_login );
885
+
886
+ $this->assertTrue( $response );
887
+ $this->assertFalse( get_term_by( 'id', $guest_author_term->term_id, $coauthors_plus->coauthor_taxonomy ) );
888
+ $this->assertNull( get_post( $guest_author_id ) );
889
+ }
890
+ }
tests/test-coauthors-plus.php ADDED
@@ -0,0 +1,679 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_CoAuthors_Plus extends CoAuthorsPlus_TestCase {
4
+
5
+ public function setUp() {
6
+
7
+ parent::setUp();
8
+
9
+ $this->author1 = $this->factory->user->create_and_get( array( 'role' => 'author', 'user_login' => 'author1' ) );
10
+ $this->editor1 = $this->factory->user->create_and_get( array( 'role' => 'editor', 'user_login' => 'editor1' ) );
11
+
12
+ $this->post = $this->factory->post->create_and_get( array(
13
+ 'post_author' => $this->author1->ID,
14
+ 'post_status' => 'publish',
15
+ 'post_content' => rand_str(),
16
+ 'post_title' => rand_str(),
17
+ 'post_type' => 'post',
18
+ ) );
19
+ }
20
+
21
+ /**
22
+ * Checks whether the guest authors functionality is enabled or not.
23
+ *
24
+ * @covers CoAuthors_Plus::is_guest_authors_enabled()
25
+ */
26
+ public function test_is_guest_authors_enabled() {
27
+
28
+ global $coauthors_plus;
29
+
30
+ $this->assertTrue( $coauthors_plus->is_guest_authors_enabled() );
31
+
32
+ add_filter( 'coauthors_guest_authors_enabled', '__return_false' );
33
+
34
+ $this->assertFalse( $coauthors_plus->is_guest_authors_enabled() );
35
+
36
+ remove_filter( 'coauthors_guest_authors_enabled', '__return_false' );
37
+
38
+ $this->assertTrue( $coauthors_plus->is_guest_authors_enabled() );
39
+ }
40
+
41
+ /**
42
+ * Checks coauthor object when he/she is a guest author.
43
+ *
44
+ * @covers CoAuthors_Plus::get_coauthor_by()
45
+ */
46
+ public function test_get_coauthor_by_when_guest_author() {
47
+
48
+ global $coauthors_plus;
49
+
50
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
51
+ 'user_login' => 'author2',
52
+ 'display_name' => 'author2',
53
+ ) );
54
+
55
+ $coauthor = $coauthors_plus->get_coauthor_by( 'id', $guest_author_id );
56
+
57
+ $this->assertInstanceOf( stdClass::class, $coauthor );
58
+ $this->assertObjectHasAttribute( 'ID', $coauthor );
59
+ $this->assertEquals( $guest_author_id, $coauthor->ID );
60
+ $this->assertEquals( 'guest-author', $coauthor->type );
61
+ }
62
+
63
+ /**
64
+ * Checks coauthor object when he/she is a wp author.
65
+ *
66
+ * @covers CoAuthors_Plus::get_coauthor_by()
67
+ */
68
+ public function test_get_coauthor_by_when_guest_authors_not_enabled() {
69
+
70
+ global $coauthors_plus;
71
+
72
+ add_filter( 'coauthors_guest_authors_enabled', '__return_false' );
73
+
74
+ $this->assertFalse( $coauthors_plus->get_coauthor_by( '', '' ) );
75
+
76
+ $coauthor = $coauthors_plus->get_coauthor_by( 'id', $this->author1->ID );
77
+
78
+ $this->assertInstanceOf( WP_User::class, $coauthor );
79
+ $this->assertObjectHasAttribute( 'ID', $coauthor );
80
+ $this->assertEquals( $this->author1->ID, $coauthor->ID );
81
+ $this->assertEquals( 'wpuser', $coauthor->type );
82
+
83
+ $coauthor = $coauthors_plus->get_coauthor_by( 'user_login', $this->author1->user_login );
84
+
85
+ $this->assertInstanceOf( WP_User::class, $coauthor );
86
+ $this->assertObjectHasAttribute( 'user_login', $coauthor->data );
87
+ $this->assertEquals( $this->author1->user_login, $coauthor->user_login );
88
+
89
+ $coauthor = $coauthors_plus->get_coauthor_by( 'user_nicename', $this->author1->user_nicename );
90
+
91
+ $this->assertInstanceOf( WP_User::class, $coauthor );
92
+ $this->assertObjectHasAttribute( 'user_nicename', $coauthor->data );
93
+ $this->assertEquals( $this->author1->user_nicename, $coauthor->user_nicename );
94
+
95
+ $coauthor = $coauthors_plus->get_coauthor_by( 'user_email', $this->author1->user_email );
96
+
97
+ $this->assertInstanceOf( WP_User::class, $coauthor );
98
+ $this->assertObjectHasAttribute( 'user_email', $coauthor->data );
99
+ $this->assertEquals( $this->author1->user_email, $coauthor->user_email );
100
+
101
+ remove_filter( 'coauthors_guest_authors_enabled', '__return_false' );
102
+
103
+ $coauthors_plus->guest_authors->create_guest_author_from_user_id( $this->editor1->ID );
104
+
105
+ $coauthor = $coauthors_plus->get_coauthor_by( 'id', $this->editor1->ID );
106
+
107
+ $this->assertInstanceOf( stdClass::class, $coauthor );
108
+ $this->assertObjectHasAttribute( 'linked_account', $coauthor );
109
+ $this->assertEquals( $this->editor1->user_login, $coauthor->linked_account );
110
+ }
111
+
112
+ /**
113
+ * Checks coauthors plus is enabled for this post type.
114
+ *
115
+ * @covers CoAuthors_Plus::is_post_type_enabled()
116
+ */
117
+ public function test_is_post_type_enabled() {
118
+
119
+ global $coauthors_plus, $post;
120
+
121
+ // Backing up global post.
122
+ $post_backup = $post;
123
+
124
+ // Checks when post type is null.
125
+ $this->assertFalse( $coauthors_plus->is_post_type_enabled() );
126
+
127
+ // Checks when post type is post.
128
+ $this->assertTrue( $coauthors_plus->is_post_type_enabled( 'post' ) );
129
+
130
+ // Checks when post type is page.
131
+ $this->assertTrue( $coauthors_plus->is_post_type_enabled( 'page' ) );
132
+
133
+ // Checks when post type is attachment.
134
+ $this->assertFalse( $coauthors_plus->is_post_type_enabled( 'attachment' ) );
135
+
136
+ // Checks when post type is revision.
137
+ $this->assertFalse( $coauthors_plus->is_post_type_enabled( 'revision' ) );
138
+
139
+ $post = $this->post;
140
+
141
+ // Checks when post type set using global post.
142
+ $this->assertTrue( $coauthors_plus->is_post_type_enabled() );
143
+
144
+ $post = '';
145
+ $screen = get_current_screen();
146
+
147
+ // Set the edit post current screen.
148
+ set_current_screen( 'edit-post' );
149
+ $this->assertTrue( $coauthors_plus->is_post_type_enabled() );
150
+
151
+ $GLOBALS['current_screen'] = $screen;
152
+
153
+ // Restore global post from backup.
154
+ $post = $post_backup;
155
+ }
156
+
157
+ /**
158
+ * Checks if the current user can set co-authors or not using current screen.
159
+ *
160
+ * @covers CoAuthors_Plus::current_user_can_set_authors()
161
+ */
162
+ public function test_current_user_can_set_authors_using_current_screen() {
163
+
164
+ global $coauthors_plus;
165
+
166
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
167
+
168
+ $screen = get_current_screen();
169
+
170
+ // Set the edit post current screen.
171
+ set_current_screen( 'edit-post' );
172
+
173
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
174
+
175
+ $GLOBALS['current_screen'] = $screen;
176
+
177
+ // Backing up current user.
178
+ $current_user = get_current_user_id();
179
+
180
+ // Checks when current user is author.
181
+ wp_set_current_user( $this->author1->ID );
182
+
183
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
184
+
185
+ set_current_screen( 'edit-post' );
186
+
187
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
188
+
189
+ $GLOBALS['current_screen'] = $screen;
190
+
191
+ // Checks when current user is editor.
192
+ wp_set_current_user( $this->editor1->ID );
193
+
194
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
195
+
196
+ set_current_screen( 'edit-post' );
197
+
198
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors() );
199
+
200
+ $GLOBALS['current_screen'] = $screen;
201
+
202
+ // Checks when current user is admin.
203
+ $admin1 = $this->factory->user->create_and_get( array(
204
+ 'role' => 'administrator',
205
+ ) );
206
+
207
+ wp_set_current_user( $admin1->ID );
208
+
209
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
210
+
211
+ set_current_screen( 'edit-post' );
212
+
213
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors() );
214
+
215
+ $GLOBALS['current_screen'] = $screen;
216
+
217
+ // Restore current user from backup.
218
+ wp_set_current_user( $current_user );
219
+ }
220
+
221
+ /**
222
+ * Checks if the current user can set co-authors or not using global post.
223
+ *
224
+ * @covers CoAuthors_Plus::current_user_can_set_authors()
225
+ */
226
+ public function test_current_user_can_set_authors_using_global_post() {
227
+
228
+ global $coauthors_plus, $post;
229
+
230
+ // Backing up global post.
231
+ $post_backup = $post;
232
+
233
+ $post = $this->post;
234
+
235
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
236
+
237
+ // Backing up current user.
238
+ $current_user = get_current_user_id();
239
+
240
+ // Checks when current user is author.
241
+ wp_set_current_user( $this->author1->ID );
242
+
243
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors() );
244
+
245
+ // Checks when current user is editor.
246
+ wp_set_current_user( $this->editor1->ID );
247
+
248
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors() );
249
+
250
+ // Checks when current user is super admin.
251
+ $admin1 = $this->factory->user->create_and_get( array(
252
+ 'role' => 'administrator',
253
+ ) );
254
+
255
+ grant_super_admin( $admin1->ID );
256
+ wp_set_current_user( $admin1->ID );
257
+
258
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors() );
259
+
260
+ // Restore current user from backup.
261
+ wp_set_current_user( $current_user );
262
+
263
+ // Restore global post from backup.
264
+ $post = $post_backup;
265
+ }
266
+
267
+ /**
268
+ * Checks if the current user can set co-authors or not using normal post.
269
+ *
270
+ * @covers CoAuthors_Plus::current_user_can_set_authors()
271
+ */
272
+ public function test_current_user_can_set_authors_using_normal_post() {
273
+
274
+ global $coauthors_plus;
275
+
276
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors( $this->post ) );
277
+
278
+ // Backing up current user.
279
+ $current_user = get_current_user_id();
280
+
281
+ // Checks when current user is author.
282
+ wp_set_current_user( $this->author1->ID );
283
+
284
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors( $this->post ) );
285
+
286
+ // Checks when current user is editor.
287
+ wp_set_current_user( $this->editor1->ID );
288
+
289
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors( $this->post ) );
290
+
291
+ // Checks when current user is super admin.
292
+ $admin1 = $this->factory->user->create_and_get( array(
293
+ 'role' => 'administrator',
294
+ ) );
295
+
296
+ grant_super_admin( $admin1->ID );
297
+ wp_set_current_user( $admin1->ID );
298
+
299
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors( $this->post ) );
300
+
301
+ // Restore current user from backup.
302
+ wp_set_current_user( $current_user );
303
+ }
304
+
305
+ /**
306
+ * Checks if the current user can set co-authors or not using coauthors_plus_edit_authors filter.
307
+ *
308
+ * @covers CoAuthors_Plus::current_user_can_set_authors()
309
+ */
310
+ public function test_current_user_can_set_authors_using_coauthors_plus_edit_authors_filter() {
311
+
312
+ global $coauthors_plus;
313
+
314
+ // Backing up current user.
315
+ $current_user = get_current_user_id();
316
+
317
+ // Checking when current user is subscriber and filter is true/false.
318
+ $subscriber1 = $this->factory->user->create_and_get( array(
319
+ 'role' => 'subscriber',
320
+ ) );
321
+
322
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors( $this->post ) );
323
+
324
+ add_filter( 'coauthors_plus_edit_authors', '__return_true' );
325
+
326
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors( $this->post ) );
327
+
328
+ remove_filter( 'coauthors_plus_edit_authors', '__return_true' );
329
+
330
+ // Checks when current user is editor.
331
+ wp_set_current_user( $this->editor1->ID );
332
+
333
+ $this->assertTrue( $coauthors_plus->current_user_can_set_authors( $this->post ) );
334
+
335
+ add_filter( 'coauthors_plus_edit_authors', '__return_false' );
336
+
337
+ $this->assertFalse( $coauthors_plus->current_user_can_set_authors( $this->post ) );
338
+
339
+ remove_filter( 'coauthors_plus_edit_authors', '__return_false' );
340
+
341
+ // Restore current user from backup.
342
+ wp_set_current_user( $current_user );
343
+ }
344
+
345
+ /**
346
+ * Checks matching co-authors based on a search value when no arguments provided.
347
+ *
348
+ * @covers CoAuthors_Plus::search_authors()
349
+ */
350
+ public function test_search_authors_no_args() {
351
+
352
+ global $coauthors_plus;
353
+
354
+ // Checks when search term is empty.
355
+ $authors = $coauthors_plus->search_authors();
356
+
357
+ $this->assertNotEmpty( $authors );
358
+ $this->assertArrayHasKey( 'admin', $authors );
359
+ $this->assertArrayHasKey( $this->author1->user_login, $authors );
360
+ $this->assertArrayHasKey( $this->editor1->user_login, $authors );
361
+
362
+ // Checks when search term is empty and any subscriber exists.
363
+ $subscriber1 = $this->factory->user->create_and_get( array(
364
+ 'role' => 'subscriber',
365
+ ) );
366
+
367
+ $authors = $coauthors_plus->search_authors();
368
+
369
+ $this->assertNotEmpty( $authors );
370
+ $this->assertNotContains( $subscriber1->user_login, $authors );
371
+
372
+ // Checks when search term is empty and any contributor exists.
373
+ $contributor1 = $this->factory->user->create_and_get( array(
374
+ 'role' => 'contributor',
375
+ ) );
376
+
377
+ $authors = $coauthors_plus->search_authors();
378
+
379
+ $this->assertNotEmpty( $authors );
380
+ $this->assertArrayHasKey( $contributor1->user_login, $authors );
381
+ }
382
+
383
+ /**
384
+ * Checks matching co-authors based on a search value when only search keyword is provided.
385
+ *
386
+ * @covers CoAuthors_Plus::search_authors()
387
+ */
388
+ public function test_search_authors_when_search_keyword_provided() {
389
+
390
+ global $coauthors_plus;
391
+
392
+ // Checks when author does not exist with searched term.
393
+ $this->assertEmpty( $coauthors_plus->search_authors( 'test' ) );
394
+
395
+ // Checks when author searched using ID.
396
+ $authors = $coauthors_plus->search_authors( $this->author1->ID );
397
+
398
+ $this->assertNotEmpty( $authors );
399
+ $this->assertArrayHasKey( $this->author1->user_login, $authors );
400
+ $this->assertNotContains( $this->editor1->user_login, $authors );
401
+ $this->assertNotContains( 'admin', $authors );
402
+
403
+ // Checks when author searched using display_name.
404
+ $authors = $coauthors_plus->search_authors( $this->author1->display_name );
405
+
406
+ $this->assertNotEmpty( $authors );
407
+ $this->assertArrayHasKey( $this->author1->user_login, $authors );
408
+ $this->assertNotContains( $this->editor1->user_login, $authors );
409
+ $this->assertNotContains( 'admin', $authors );
410
+
411
+ // Checks when author searched using user_email.
412
+ $authors = $coauthors_plus->search_authors( $this->author1->user_email );
413
+
414
+ $this->assertNotEmpty( $authors );
415
+ $this->assertArrayHasKey( $this->author1->user_login, $authors );
416
+ $this->assertNotContains( $this->editor1->user_login, $authors );
417
+ $this->assertNotContains( 'admin', $authors );
418
+
419
+ // Checks when author searched using user_login.
420
+ $authors = $coauthors_plus->search_authors( $this->author1->user_login );
421
+
422
+ $this->assertNotEmpty( $authors );
423
+ $this->assertArrayHasKey( $this->author1->user_login, $authors );
424
+ $this->assertNotContains( $this->editor1->user_login, $authors );
425
+ $this->assertNotContains( 'admin', $authors );
426
+
427
+ // Checks when any subscriber exists using ID but not author.
428
+ $subscriber1 = $this->factory->user->create_and_get( array(
429
+ 'role' => 'subscriber',
430
+ ) );
431
+
432
+ $this->assertEmpty( $coauthors_plus->search_authors( $subscriber1->ID ) );
433
+ }
434
+
435
+ /**
436
+ * Checks matching co-authors based on a search value when only ignore authors are provided.
437
+ *
438
+ * @covers CoAuthors_Plus::search_authors()
439
+ */
440
+ public function test_search_authors_when_ignored_authors_provided() {
441
+
442
+ global $coauthors_plus;
443
+
444
+ // Ignoring single author.
445
+ $ignored_authors = array( $this->author1->user_login );
446
+
447
+ $authors = $coauthors_plus->search_authors( '', $ignored_authors );
448
+
449
+ $this->assertNotEmpty( $authors );
450
+ $this->assertNotContains( $this->author1->user_login, $authors );
451
+
452
+ // Checks when ignoring author1 but also exists one more author with similar kind of data.
453
+ $author2 = $this->factory->user->create_and_get( array(
454
+ 'role' => 'author',
455
+ ) );
456
+
457
+ $authors = $coauthors_plus->search_authors( '', $ignored_authors );
458
+
459
+ $this->assertNotEmpty( $authors );
460
+ $this->assertNotContains( $this->author1->user_login, $authors );
461
+ $this->assertArrayHasKey( $author2->user_login, $authors );
462
+
463
+ // Ignoring multiple authors.
464
+ $authors = $coauthors_plus->search_authors( '', array( $this->author1->user_login, $author2->user_login ) );
465
+
466
+ $this->assertNotEmpty( $authors );
467
+ $this->assertNotContains( $this->author1->user_login, $authors );
468
+ $this->assertNotContains( $author2->user_login, $authors );
469
+ }
470
+
471
+ /**
472
+ * Checks matching co-authors based on a search value when search keyword as well as ignore authors are provided.
473
+ *
474
+ * @covers CoAuthors_Plus::search_authors()
475
+ */
476
+ public function test_search_authors_when_search_keyword_and_ignored_authors_provided() {
477
+
478
+ global $coauthors_plus;
479
+
480
+ // Checks when ignoring author1.
481
+ $ignored_authors = array( $this->author1->user_login );
482
+
483
+ $this->assertEmpty( $coauthors_plus->search_authors( $this->author1->ID, $ignored_authors ) );
484
+
485
+ // Checks when ignoring author1 but also exists one more author with similar kind of data.
486
+ $author2 = $this->factory->user->create_and_get( array(
487
+ 'role' => 'author',
488
+ 'user_login' => 'author2',
489
+ ) );
490
+
491
+ $authors = $coauthors_plus->search_authors( 'author', $ignored_authors );
492
+
493
+ $this->assertNotEmpty( $authors );
494
+ $this->assertNotContains( $this->author1->user_login, $authors );
495
+ $this->assertArrayHasKey( $author2->user_login, $authors );
496
+ }
497
+
498
+ /**
499
+ * Checks the author term for a given co-author when passed coauthor is not an object.
500
+ *
501
+ * @covers CoAuthors_Plus::get_author_term()
502
+ */
503
+ public function test_get_author_term_when_coauthor_is_not_object() {
504
+
505
+ global $coauthors_plus;
506
+
507
+ $this->assertEmpty( $coauthors_plus->get_author_term( '' ) );
508
+ $this->assertEmpty( $coauthors_plus->get_author_term( $this->author1->ID ) );
509
+ $this->assertEmpty( $coauthors_plus->get_author_term( (array) $this->author1 ) );
510
+ }
511
+
512
+ /**
513
+ * Checks the author term for a given co-author using cache.
514
+ *
515
+ * @covers CoAuthors_Plus::get_author_term()
516
+ */
517
+ public function test_get_author_term_using_caching() {
518
+
519
+ global $coauthors_plus;
520
+
521
+ $cache_key = 'author-term-' . $this->author1->user_nicename;
522
+
523
+ // Checks when term does not exist in cache.
524
+ $this->assertFalse( wp_cache_get( $cache_key, 'co-authors-plus' ) );
525
+
526
+ // Checks when term exists in cache.
527
+ $author_term = $coauthors_plus->get_author_term( $this->author1 );
528
+ $author_term_cached = wp_cache_get( $cache_key, 'co-authors-plus' );
529
+
530
+ $this->assertInstanceOf( WP_Term::class, $author_term );
531
+ $this->assertEquals( $author_term, $author_term_cached );
532
+ }
533
+
534
+ /**
535
+ * Checks the author term for a given co-author with having linked account.
536
+ *
537
+ * @covers CoAuthors_Plus::get_author_term()
538
+ */
539
+ public function test_get_author_term_when_author_has_linked_account() {
540
+
541
+ global $coauthors_plus;
542
+
543
+ // Checks when term exists using linked account.
544
+ $coauthor_id = $coauthors_plus->guest_authors->create_guest_author_from_user_id( $this->editor1->ID );
545
+ $coauthor = $coauthors_plus->get_coauthor_by( 'id', $coauthor_id );
546
+
547
+ $author_term = $coauthors_plus->get_author_term( $coauthor );
548
+
549
+ $this->assertInstanceOf( WP_Term::class, $author_term );
550
+
551
+ // Checks when term does not exist or deleted somehow.
552
+ wp_delete_term( $author_term->term_id, $author_term->taxonomy );
553
+
554
+ $this->assertFalse( $coauthors_plus->get_author_term( $coauthor ) );
555
+ }
556
+
557
+ /**
558
+ * Checks the author term for a given co-author without having linked account.
559
+ *
560
+ * @covers CoAuthors_Plus::get_author_term()
561
+ */
562
+ public function test_get_author_term_when_author_has_not_linked_account() {
563
+
564
+ global $coauthors_plus;
565
+
566
+ // Checks when term exists without linked account.
567
+ $coauthor_id = $coauthors_plus->guest_authors->create( array(
568
+ 'display_name' => 'guest',
569
+ 'user_login' => 'guest',
570
+ ) );
571
+ $coauthor = $coauthors_plus->get_coauthor_by( 'id', $coauthor_id );
572
+
573
+ $author_term = $coauthors_plus->get_author_term( $coauthor );
574
+
575
+ $this->assertInstanceOf( WP_Term::class, $author_term );
576
+
577
+ // Checks when term does not exist or deleted somehow.
578
+ wp_delete_term( $author_term->term_id, $author_term->taxonomy );
579
+
580
+ $this->assertFalse( $coauthors_plus->get_author_term( $coauthor ) );
581
+ }
582
+
583
+ /**
584
+ * Checks update author term when passed coauthor is not an object.
585
+ *
586
+ * @covers CoAuthors_Plus::update_author_term()
587
+ */
588
+ public function test_update_author_term_when_coauthor_is_not_object() {
589
+
590
+ global $coauthors_plus;
591
+
592
+ $this->assertEmpty( $coauthors_plus->update_author_term( '' ) );
593
+ $this->assertEmpty( $coauthors_plus->update_author_term( $this->author1->ID ) );
594
+ $this->assertEmpty( $coauthors_plus->update_author_term( (array) $this->author1 ) );
595
+ }
596
+
597
+ /**
598
+ * Checks update author term when author term exists for passed coauthor.
599
+ *
600
+ * @covers CoAuthors_Plus::update_author_term()
601
+ */
602
+ public function test_update_author_term_when_author_term_exists() {
603
+
604
+ global $coauthors_plus;
605
+
606
+ // Checks term description.
607
+ $author_term = $coauthors_plus->update_author_term( $this->author1 );
608
+
609
+ // In "update_author_term()", only description is being updated, so asserting that only ( here and everywhere ).
610
+ $this->assertEquals( $this->author1->display_name . ' ' . $this->author1->first_name . ' ' . $this->author1->last_name . ' ' . $this->author1->user_login . ' ' . $this->author1->ID . ' ' . $this->author1->user_email, $author_term->description );
611
+
612
+ // Checks term description after updating user.
613
+ wp_update_user( array(
614
+ 'ID' => $this->author1->ID,
615
+ 'first_name' => 'author1',
616
+ ) );
617
+
618
+ $author_term = $coauthors_plus->update_author_term( $this->author1 );
619
+
620
+ $this->assertEquals( $this->author1->display_name . ' ' . $this->author1->first_name . ' ' . $this->author1->last_name . ' ' . $this->author1->user_login . ' ' . $this->author1->ID . ' ' . $this->author1->user_email, $author_term->description );
621
+
622
+ // Backup coauthor taxonomy.
623
+ $taxonomy_backup = $coauthors_plus->coauthor_taxonomy;
624
+
625
+ wp_update_user( array(
626
+ 'ID' => $this->author1->ID,
627
+ 'last_name' => 'author1',
628
+ ) );
629
+
630
+ // Checks with different taxonomy.
631
+ $coauthors_plus->coauthor_taxonomy = 'abcd';
632
+
633
+ $this->assertFalse( $coauthors_plus->update_author_term( $this->author1 ) );
634
+
635
+ // Restore coauthor taxonomy from backup.
636
+ $coauthors_plus->coauthor_taxonomy = $taxonomy_backup;
637
+ }
638
+
639
+ /**
640
+ * Checks update author term when author term does not exist for passed coauthor.
641
+ *
642
+ * @covers CoAuthors_Plus::update_author_term()
643
+ */
644
+ public function test_update_author_term_when_author_term_not_exist() {
645
+
646
+ global $coauthors_plus;
647
+
648
+ // Checks term description.
649
+ $author_term = $coauthors_plus->update_author_term( $this->editor1 );
650
+
651
+ $this->assertEquals( $this->editor1->display_name . ' ' . $this->editor1->first_name . ' ' . $this->editor1->last_name . ' ' . $this->editor1->user_login . ' ' . $this->editor1->ID . ' ' . $this->editor1->user_email, $author_term->description );
652
+
653
+ // Checks term description after updating user.
654
+ wp_update_user( array(
655
+ 'ID' => $this->editor1->ID,
656
+ 'first_name' => 'editor1',
657
+ ) );
658
+
659
+ $author_term = $coauthors_plus->update_author_term( $this->editor1 );
660
+
661
+ $this->assertEquals( $this->editor1->display_name . ' ' . $this->editor1->first_name . ' ' . $this->editor1->last_name . ' ' . $this->editor1->user_login . ' ' . $this->editor1->ID . ' ' . $this->editor1->user_email, $author_term->description );
662
+
663
+ // Backup coauthor taxonomy.
664
+ $taxonomy_backup = $coauthors_plus->coauthor_taxonomy;
665
+
666
+ wp_update_user( array(
667
+ 'ID' => $this->editor1->ID,
668
+ 'last_name' => 'editor1',
669
+ ) );
670
+
671
+ // Checks with different taxonomy.
672
+ $coauthors_plus->coauthor_taxonomy = 'abcd';
673
+
674
+ $this->assertFalse( $coauthors_plus->update_author_term( $this->editor1 ) );
675
+
676
+ // Restore coauthor taxonomy from backup.
677
+ $coauthors_plus->coauthor_taxonomy = $taxonomy_backup;
678
+ }
679
+ }
tests/test-manage-coauthors.php CHANGED
@@ -5,6 +5,7 @@ class Test_Manage_CoAuthors extends CoAuthorsPlus_TestCase {
5
  public function setUp() {
6
  parent::setUp();
7
 
 
8
  $this->author1 = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'author1' ) );
9
  $this->editor1 = $this->factory->user->create( array( 'role' => 'editor', 'user_login' => 'editor2' ) );
10
 
@@ -145,4 +146,283 @@ class Test_Manage_CoAuthors extends CoAuthorsPlus_TestCase {
145
  $this->assertEquals( 1, count_user_posts( $editor1->ID ) );
146
 
147
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
5
  public function setUp() {
6
  parent::setUp();
7
 
8
+ $this->admin1 = $this->factory->user->create( array( 'role' => 'administrator', 'user_login' => 'admin1' ) );
9
  $this->author1 = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'author1' ) );
10
  $this->editor1 = $this->factory->user->create( array( 'role' => 'editor', 'user_login' => 'editor2' ) );
11
 
146
  $this->assertEquals( 1, count_user_posts( $editor1->ID ) );
147
 
148
  }
149
+
150
+ /**
151
+ * Returns data as it is when post type is not allowed.
152
+ *
153
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
154
+ *
155
+ * @covers ::coauthors_set_post_author_field()
156
+ */
157
+ public function test_coauthors_set_post_author_field_when_post_type_is_attachment() {
158
+
159
+ global $coauthors_plus;
160
+
161
+ $this->assertEquals( 10, has_filter( 'wp_insert_post_data', array(
162
+ $coauthors_plus,
163
+ 'coauthors_set_post_author_field',
164
+ ) ) );
165
+
166
+ $post_id = $this->factory->post->create( array(
167
+ 'post_author' => $this->author1,
168
+ 'post_type' => 'attachment',
169
+ ) );
170
+
171
+ $post = get_post( $post_id );
172
+
173
+ $data = $post_array = array(
174
+ 'ID' => $post->ID,
175
+ 'post_type' => $post->post_type,
176
+ 'post_author' => $post->post_author,
177
+ );
178
+
179
+ $new_data = $coauthors_plus->coauthors_set_post_author_field( $data, $post_array );
180
+
181
+ $this->assertEquals( $data, $new_data );
182
+ }
183
+
184
+ /**
185
+ * Compares data when coauthor is not set in the post array.
186
+ *
187
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
188
+ *
189
+ * @covers ::coauthors_set_post_author_field()
190
+ */
191
+ public function test_coauthors_set_post_author_field_when_coauthor_is_not_set() {
192
+
193
+ global $coauthors_plus;
194
+
195
+ $author1_post1 = get_post( $this->author1_post1 );
196
+
197
+ $data = $post_array = array(
198
+ 'ID' => $author1_post1->ID,
199
+ 'post_type' => $author1_post1->post_type,
200
+ 'post_author' => $author1_post1->post_author,
201
+ );
202
+
203
+ $new_data = $coauthors_plus->coauthors_set_post_author_field( $data, $post_array );
204
+
205
+ $this->assertEquals( $data, $new_data );
206
+ }
207
+
208
+ /**
209
+ * Compares data when coauthor is set in the post array.
210
+ *
211
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
212
+ *
213
+ * @covers ::coauthors_set_post_author_field()
214
+ */
215
+ public function test_coauthors_set_post_author_field_when_coauthor_is_set() {
216
+
217
+ global $coauthors_plus;
218
+
219
+ $user_id = $this->factory->user->create( array(
220
+ 'user_login' => 'test_admin',
221
+ 'user_nicename' => 'test_admiи',
222
+ ) );
223
+
224
+ $user = get_user_by( 'id', $user_id );
225
+
226
+ // Backing up global variables.
227
+ $post_backup = $_POST;
228
+ $request_backup = $_REQUEST;
229
+
230
+ $_REQUEST['coauthors-nonce'] = wp_create_nonce( 'coauthors-edit' );;
231
+ $_POST['coauthors'] = array(
232
+ $user->user_nicename,
233
+ );
234
+
235
+ $post_id = $this->factory->post->create( array(
236
+ 'post_author' => $user_id,
237
+ ) );
238
+
239
+ $post = get_post( $post_id );
240
+
241
+ $data = $post_array = array(
242
+ 'ID' => $post->ID,
243
+ 'post_type' => $post->post_type,
244
+ 'post_author' => $post->post_author,
245
+ );
246
+
247
+ $new_data = $coauthors_plus->coauthors_set_post_author_field( $data, $post_array );
248
+
249
+ $this->assertEquals( $data, $new_data );
250
+
251
+ // Store global variables from backup.
252
+ $_POST = $post_backup;
253
+ $_REQUEST = $request_backup;
254
+ }
255
+
256
+ /**
257
+ * Compares data when coauthor is set and it is linked with main wp user.
258
+ *
259
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
260
+ *
261
+ * @covers ::coauthors_set_post_author_field()
262
+ */
263
+ public function test_coauthors_set_post_author_field_when_guest_author_is_linked_with_wp_user() {
264
+
265
+ global $coauthors_plus;
266
+
267
+ $author1 = get_user_by( 'id', $this->author1 );
268
+
269
+ $author1_post1 = get_post( $this->author1_post1 );
270
+
271
+ $data = $post_array = array(
272
+ 'ID' => $author1_post1->ID,
273
+ 'post_type' => $author1_post1->post_type,
274
+ 'post_author' => $author1_post1->post_author,
275
+ );
276
+
277
+ // Backing up global variables.
278
+ $post_backup = $_POST;
279
+ $request_backup = $_REQUEST;
280
+
281
+ $_REQUEST['coauthors-nonce'] = wp_create_nonce( 'coauthors-edit' );;
282
+ $_POST['coauthors'] = array(
283
+ $author1->user_nicename,
284
+ );
285
+
286
+ // Create guest author with linked account with user.
287
+ $coauthors_plus->guest_authors = new CoAuthors_Guest_Authors;
288
+ $coauthors_plus->guest_authors->create_guest_author_from_user_id( $this->author1 );
289
+
290
+ $new_data = $coauthors_plus->coauthors_set_post_author_field( $data, $post_array );
291
+
292
+ $this->assertEquals( $data, $new_data );
293
+
294
+ // Store global variables from backup.
295
+ $_POST = $post_backup;
296
+ $_REQUEST = $request_backup;
297
+ }
298
+
299
+ /**
300
+ * Compares post author when it is not set in the main data array somehow.
301
+ *
302
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
303
+ *
304
+ * @covers ::coauthors_set_post_author_field()
305
+ */
306
+ public function test_coauthors_set_post_author_field_when_post_author_is_not_set() {
307
+
308
+ global $coauthors_plus;
309
+
310
+ wp_set_current_user( $this->author1 );
311
+
312
+ // Backing up global variables.
313
+ $post_backup = $_POST;
314
+ $request_backup = $_REQUEST;
315
+
316
+ $_REQUEST = $_POST = array();
317
+
318
+ $author1_post1 = get_post( $this->author1_post1 );
319
+
320
+ $data = $post_array = array(
321
+ 'ID' => $author1_post1->ID,
322
+ 'post_type' => $author1_post1->post_type,
323
+ 'post_author' => $author1_post1->post_author,
324
+ );
325
+
326
+ unset( $data['post_author'] );
327
+
328
+ $new_data = $coauthors_plus->coauthors_set_post_author_field( $data, $post_array );
329
+
330
+ $this->assertEquals( $this->author1, $new_data['post_author'] );
331
+
332
+ // Store global variables from backup.
333
+ $_POST = $post_backup;
334
+ $_REQUEST = $request_backup;
335
+ }
336
+
337
+ /**
338
+ * Bypass coauthors_update_post() when post type is not allowed.
339
+ *
340
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
341
+ *
342
+ * @covers ::coauthors_update_post()
343
+ */
344
+ public function test_coauthors_update_post_when_post_type_is_attachment() {
345
+
346
+ global $coauthors_plus;
347
+
348
+ $this->assertEquals( 10, has_action( 'save_post', array(
349
+ $coauthors_plus,
350
+ 'coauthors_update_post',
351
+ ) ) );
352
+
353
+ $post_id = $this->factory->post->create( array(
354
+ 'post_author' => $this->author1,
355
+ 'post_type' => 'attachment',
356
+ ) );
357
+
358
+ $post = get_post( $post_id );
359
+ $return = $coauthors_plus->coauthors_update_post( $post_id, $post );
360
+
361
+ $this->assertNull( $return );
362
+ }
363
+
364
+ /**
365
+ * Checks coauthors when current user can set authors.
366
+ *
367
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
368
+ *
369
+ * @covers ::coauthors_update_post()
370
+ */
371
+ public function test_coauthors_update_post_when_current_user_can_set_authors() {
372
+
373
+ global $coauthors_plus;
374
+
375
+ wp_set_current_user( $this->admin1 );
376
+
377
+ $admin1 = get_user_by( 'id', $this->admin1 );
378
+ $author1 = get_user_by( 'id', $this->author1 );
379
+
380
+ $post_id = $this->factory->post->create( array(
381
+ 'post_author' => $this->admin1,
382
+ ) );
383
+
384
+ $post = get_post( $post_id );
385
+
386
+ // Backing up global variables.
387
+ $post_backup = $_POST;
388
+ $request_backup = $_REQUEST;
389
+
390
+ $_POST['coauthors-nonce'] = $_REQUEST['coauthors-nonce'] = wp_create_nonce( 'coauthors-edit' );
391
+ $_POST['coauthors'] = array(
392
+ $admin1->user_nicename,
393
+ $author1->user_nicename,
394
+ );
395
+
396
+ $coauthors_plus->coauthors_update_post( $post_id, $post );
397
+
398
+ $coauthors = get_coauthors( $post_id );
399
+
400
+ $this->assertEquals( array( $this->admin1, $this->author1 ), wp_list_pluck( $coauthors, 'ID' ) );
401
+
402
+ // Store global variables from backup.
403
+ $_POST = $post_backup;
404
+ $_REQUEST = $request_backup;
405
+ }
406
+
407
+ /**
408
+ * Coauthors should be empty if post does not have any author terms
409
+ * and current user can not set authors for the post.
410
+ *
411
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/198
412
+ *
413
+ * @covers ::coauthors_update_post()
414
+ */
415
+ public function test_coauthors_update_post_when_post_has_not_author_terms() {
416
+
417
+ global $coauthors_plus;
418
+
419
+ $post_id = $this->factory->post->create();
420
+ $post = get_post( $post_id );
421
+
422
+ $coauthors_plus->coauthors_update_post( $post_id, $post );
423
+
424
+ $coauthors = get_coauthors( $post_id );
425
+
426
+ $this->assertEmpty( $coauthors );
427
+ }
428
  }
tests/test-template-tags.php ADDED
@@ -0,0 +1,1068 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_Template_Tags extends CoAuthorsPlus_TestCase {
4
+
5
+ public function setUp() {
6
+
7
+ parent::setUp();
8
+
9
+ /**
10
+ * When 'coauthors_auto_apply_template_tags' is set to true,
11
+ * we need CoAuthors_Template_Filters object to check 'the_author' filter.
12
+ */
13
+ global $coauthors_plus_template_filters;
14
+ $coauthors_plus_template_filters = new CoAuthors_Template_Filters;
15
+
16
+ $this->author1 = $this->factory->user->create_and_get( array( 'role' => 'author', 'user_login' => 'author1' ) );
17
+ $this->editor1 = $this->factory->user->create_and_get( array( 'role' => 'editor', 'user_login' => 'editor1' ) );
18
+
19
+ $this->post = $this->factory->post->create_and_get( array(
20
+ 'post_author' => $this->author1->ID,
21
+ 'post_status' => 'publish',
22
+ 'post_content' => rand_str(),
23
+ 'post_title' => rand_str(),
24
+ 'post_type' => 'post',
25
+ ) );
26
+ }
27
+
28
+ /**
29
+ * Tests for co-authors display names, with links to their posts.
30
+ *
31
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/279
32
+ *
33
+ * @covers ::coauthors_posts_links()
34
+ */
35
+ public function test_coauthors_posts_links() {
36
+
37
+ global $coauthors_plus, $coauthors_plus_template_filters;
38
+
39
+ // Backing up global post.
40
+ $post_backup = $GLOBALS['post'];
41
+
42
+ $GLOBALS['post'] = $this->post;
43
+
44
+ // Checks for single post author.
45
+ $single_cpl = coauthors_posts_links( null, null, null, null, false );
46
+
47
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $single_cpl, 'Author link not found.' );
48
+ $this->assertContains( $this->author1->display_name, $single_cpl, 'Author name not found.' );
49
+
50
+ // Checks for multiple post author.
51
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
52
+
53
+ $multiple_cpl = coauthors_posts_links( null, null, null, null, false );
54
+
55
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $multiple_cpl, 'Main author link not found.' );
56
+ $this->assertContains( $this->author1->display_name, $multiple_cpl, 'Main author name not found.' );
57
+
58
+ // Here we are checking author name should not be more then one time.
59
+ // Asserting ">{$this->author1->display_name}<" because "$this->author1->display_name" can be multiple times like in href, title, etc.
60
+ $this->assertEquals( 1, substr_count( $multiple_cpl, ">{$this->author1->display_name}<" ) );
61
+ $this->assertContains( ' and ', $multiple_cpl, 'Coauthors name separator is not matched.' );
62
+ $this->assertContains( 'href="' . get_author_posts_url( $this->editor1->ID, $this->editor1->user_nicename ) . '"', $multiple_cpl, 'Coauthor link not found.' );
63
+ $this->assertContains( $this->editor1->display_name, $multiple_cpl, 'Coauthor name not found.' );
64
+
65
+ // Here we are checking editor name should not be more then one time.
66
+ // Asserting ">{$this->editor1->display_name}<" because "$this->editor1->display_name" can be multiple times like in href, title, etc.
67
+ $this->assertEquals( 1, substr_count( $multiple_cpl, ">{$this->editor1->display_name}<" ) );
68
+
69
+ $multiple_cpl = coauthors_links( null, ' or ', null, null, false );
70
+
71
+ $this->assertContains( ' or ', $multiple_cpl, 'Coauthors name separator is not matched.' );
72
+
73
+ $this->assertEquals( 10, has_filter( 'the_author', array(
74
+ $coauthors_plus_template_filters,
75
+ 'filter_the_author',
76
+ ) ) );
77
+
78
+ // Restore backed up post to global.
79
+ $GLOBALS['post'] = $post_backup;
80
+ }
81
+
82
+ /**
83
+ * Tests for co-authors display names.
84
+ *
85
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/279
86
+ *
87
+ * @covers ::coauthors_links()
88
+ */
89
+ public function test_coauthors_links() {
90
+
91
+ global $coauthors_plus, $coauthors_plus_template_filters;
92
+
93
+ // Backing up global post.
94
+ $post_backup = $GLOBALS['post'];
95
+
96
+ $GLOBALS['post'] = $this->post;
97
+
98
+ // Checks for single post author.
99
+ $single_cpl = coauthors_links( null, null, null, null, false );
100
+
101
+ $this->assertEquals( $this->author1->display_name, $single_cpl, 'Author name not found.' );
102
+
103
+ // Checks for multiple post author.
104
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
105
+
106
+ $multiple_cpl = coauthors_links( null, null, null, null, false );
107
+
108
+ $this->assertContains( $this->author1->display_name, $multiple_cpl, 'Main author name not found.' );
109
+ $this->assertEquals( 1, substr_count( $multiple_cpl, $this->author1->display_name ) );
110
+ $this->assertContains( ' and ', $multiple_cpl, 'Coauthors name separator is not matched.' );
111
+ $this->assertContains( $this->editor1->display_name, $multiple_cpl, 'Coauthor name not found.' );
112
+ $this->assertEquals( 1, substr_count( $multiple_cpl, $this->editor1->display_name ) );
113
+
114
+ $multiple_cpl = coauthors_links( null, ' or ', null, null, false );
115
+
116
+ $this->assertContains( ' or ', $multiple_cpl, 'Coauthors name separator is not matched.' );
117
+
118
+ $this->assertEquals( 10, has_filter( 'the_author', array(
119
+ $coauthors_plus_template_filters,
120
+ 'filter_the_author',
121
+ ) ) );
122
+
123
+ // Restore backed up post to global.
124
+ $GLOBALS['post'] = $post_backup;
125
+ }
126
+
127
+ /**
128
+ * Checks coauthors when post not exist.
129
+ *
130
+ * @covers ::get_coauthors()
131
+ */
132
+ public function test_get_coauthors_when_post_not_exists() {
133
+
134
+ $this->assertEmpty( get_coauthors() );
135
+ }
136
+
137
+ /**
138
+ * Checks coauthors when post exist (not global).
139
+ *
140
+ * @covers ::get_coauthors()
141
+ */
142
+ public function test_get_coauthors_when_post_exists() {
143
+
144
+ global $coauthors_plus;
145
+
146
+ // Compare single author.
147
+ $this->assertEquals( array( $this->author1->ID ), wp_list_pluck( get_coauthors( $this->post->ID ), 'ID' ) );
148
+
149
+ // Compare multiple authors.
150
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
151
+ $this->assertEquals( array(
152
+ $this->author1->ID,
153
+ $this->editor1->ID,
154
+ ), wp_list_pluck( get_coauthors( $this->post->ID ), 'ID' ) );
155
+ }
156
+
157
+ /**
158
+ * Checks coauthors when terms for post not exist.
159
+ *
160
+ * @covers ::get_coauthors()
161
+ */
162
+ public function test_get_coauthors_when_terms_for_post_not_exists() {
163
+
164
+ $post_id = $this->factory->post->create();
165
+ $this->assertEmpty( get_coauthors( $post_id ) );
166
+ }
167
+
168
+ /**
169
+ * Checks coauthors when post not exist.
170
+ *
171
+ * @covers ::get_coauthors()
172
+ */
173
+ public function test_get_coauthors_when_global_post_exists() {
174
+
175
+ global $post;
176
+
177
+ // Backing up global post.
178
+ $post_backup = $post;
179
+
180
+ $post = $this->factory->post->create_and_get();
181
+
182
+ $this->assertEmpty( get_coauthors() );
183
+
184
+ $user_id = $this->factory->user->create();
185
+ $post = $this->factory->post->create_and_get( array(
186
+ 'post_author' => $user_id,
187
+ ) );
188
+
189
+ $this->assertEquals( array( $user_id ), wp_list_pluck( get_coauthors(), 'ID' ) );
190
+
191
+ // Restore global post from backup.
192
+ $post = $post_backup;
193
+ }
194
+
195
+ /**
196
+ * Checks coauthors order.
197
+ *
198
+ * @covers ::get_coauthors()
199
+ */
200
+ public function test_coauthors_order() {
201
+
202
+ global $coauthors_plus;
203
+
204
+ $post_id = $this->factory->post->create();
205
+
206
+ // Checks when no author exist.
207
+ $this->assertEmpty( get_coauthors( $post_id ) );
208
+
209
+ // Checks coauthors order.
210
+ $coauthors_plus->add_coauthors( $post_id, array( $this->author1->user_login ), true );
211
+ $coauthors_plus->add_coauthors( $post_id, array( $this->editor1->user_login ), true );
212
+
213
+ $expected = array( $this->author1->user_login, $this->editor1->user_login );
214
+
215
+ $this->assertEquals( $expected, wp_list_pluck( get_coauthors( $post_id ), 'user_login' ) );
216
+
217
+ // Checks coauthors order after modifying.
218
+ $post_id = $this->factory->post->create();
219
+
220
+ $coauthors_plus->add_coauthors( $post_id, array( $this->editor1->user_login ), true );
221
+ $coauthors_plus->add_coauthors( $post_id, array( $this->author1->user_login ), true );
222
+
223
+ $expected = array( $this->editor1->user_login, $this->author1->user_login );
224
+
225
+ $this->assertEquals( $expected, wp_list_pluck( get_coauthors( $post_id ), 'user_login' ) );
226
+ }
227
+
228
+ /**
229
+ * Checks whether user is a coauthor of the post when user or post not exists.
230
+ *
231
+ * @covers ::is_coauthor_for_post()
232
+ */
233
+ public function test_is_coauthor_for_post_when_user_or_post_not_exists() {
234
+
235
+ global $post;
236
+
237
+ // Backing up global post.
238
+ $post_backup = $post;
239
+
240
+ $this->assertFalse( is_coauthor_for_post( '' ) );
241
+ $this->assertFalse( is_coauthor_for_post( '', $this->post->ID ) );
242
+ $this->assertFalse( is_coauthor_for_post( $this->author1->ID ) );
243
+
244
+ $post = $this->post;
245
+
246
+ $this->assertFalse( is_coauthor_for_post( '' ) );
247
+
248
+ // Restore global post from backup.
249
+ $post = $post_backup;
250
+ }
251
+
252
+ /**
253
+ * Checks whether user is a coauthor of the post when user is not expected as ID,
254
+ * or user_login is not set in user object.
255
+ *
256
+ * @covers ::is_coauthor_for_post()
257
+ */
258
+ public function test_is_coauthor_for_post_when_user_not_numeric_or_user_login_not_set() {
259
+
260
+ $this->assertFalse( is_coauthor_for_post( 'test' ) );
261
+ }
262
+
263
+ /**
264
+ * Checks whether user is a coauthor of the post when user is set in either way,
265
+ * as user_id or user object but he/she is not coauthor of the post.
266
+ *
267
+ * @covers ::is_coauthor_for_post()
268
+ */
269
+ public function test_is_coauthor_for_post_when_user_numeric_or_user_login_set_but_not_coauthor() {
270
+
271
+ $this->assertFalse( is_coauthor_for_post( $this->editor1->ID, $this->post->ID ) );
272
+ $this->assertFalse( is_coauthor_for_post( $this->editor1, $this->post->ID ) );
273
+ }
274
+
275
+ /**
276
+ * Checks whether user is a coauthor of the post.
277
+ *
278
+ * @covers ::is_coauthor_for_post()
279
+ */
280
+ public function test_is_coauthor_for_post_when_user_is_coauthor() {
281
+
282
+ global $post, $coauthors_plus;
283
+
284
+ // Backing up global post.
285
+ $post_backup = $post;
286
+
287
+ // Checking with specific post and user_id as well ass user object.
288
+ $this->assertTrue( is_coauthor_for_post( $this->author1->ID, $this->post->ID ) );
289
+ $this->assertTrue( is_coauthor_for_post( $this->author1, $this->post->ID ) );
290
+
291
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
292
+
293
+ $this->assertTrue( is_coauthor_for_post( $this->editor1->ID, $this->post->ID ) );
294
+ $this->assertTrue( is_coauthor_for_post( $this->editor1, $this->post->ID ) );
295
+
296
+ // Now checking with global post and user_id as well ass user object.
297
+ $post = $this->post;
298
+
299
+ $this->assertTrue( is_coauthor_for_post( $this->author1->ID ) );
300
+ $this->assertTrue( is_coauthor_for_post( $this->author1 ) );
301
+
302
+ $this->assertTrue( is_coauthor_for_post( $this->editor1->ID ) );
303
+ $this->assertTrue( is_coauthor_for_post( $this->editor1 ) );
304
+
305
+ // Restore global post from backup.
306
+ $post = $post_backup;
307
+ }
308
+
309
+ /**
310
+ * Tests for co-authors display names, without links to their posts.
311
+ *
312
+ * @covers ::coauthors()
313
+ * @covers ::coauthors__echo()
314
+ **/
315
+ public function test_coauthors() {
316
+
317
+ global $post, $coauthors_plus;
318
+
319
+ // Backing up global post.
320
+ $post_backup = $post;
321
+
322
+ $post = $this->post;
323
+
324
+ // Checks for single post author.
325
+ $coauthors = coauthors( null, null, null, null, false );
326
+
327
+ $this->assertEquals( $this->author1->display_name, $coauthors );
328
+
329
+ $coauthors = coauthors( '</span><span>', '</span><span>', '<span>', '</span>', false );
330
+
331
+ $this->assertEquals( '<span>' . $this->author1->display_name . '</span>', $coauthors );
332
+
333
+ // Checks for multiple post author.
334
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
335
+
336
+ $coauthors = coauthors( null, null, null, null, false );
337
+
338
+ $this->assertEquals( $this->author1->display_name . ' and ' . $this->editor1->display_name, $coauthors );
339
+
340
+ $coauthors = coauthors( '</span><span>', '</span><span>', '<span>', '</span>', false );
341
+
342
+ $this->assertEquals( '<span>' . $this->author1->display_name . '</span><span>' . $this->editor1->display_name . '</span>', $coauthors );
343
+
344
+ // Restore global post from backup.
345
+ $post = $post_backup;
346
+ }
347
+
348
+ /**
349
+ * Checks single co-author linked to their post archive.
350
+ *
351
+ * @covers ::coauthors_posts_links_single()
352
+ */
353
+ public function test_coauthors_posts_links_single() {
354
+
355
+ global $post;
356
+
357
+ // Backing up global post.
358
+ $post_backup = $post;
359
+
360
+ $post = $this->post;
361
+
362
+ $author_link = coauthors_posts_links_single( $this->author1 );
363
+
364
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $author_link, 'Author link not found.' );
365
+ $this->assertContains( $this->author1->display_name, $author_link, 'Author name not found.' );
366
+
367
+ // Here we are checking author name should not be more then one time.
368
+ // Asserting ">{$this->author1->display_name}<" because "$this->author1->display_name" can be multiple times like in href, title, etc.
369
+ $this->assertEquals( 1, substr_count( $author_link, ">{$this->author1->display_name}<" ) );
370
+
371
+ // Restore global post from backup.
372
+ $post = $post_backup;
373
+ }
374
+
375
+ /**
376
+ * Checks co-authors first names, without links to their posts.
377
+ *
378
+ * @covers ::coauthors_firstnames()
379
+ * @covers ::coauthors__echo()
380
+ */
381
+ public function test_coauthors_firstnames() {
382
+
383
+ global $post, $coauthors_plus;
384
+
385
+ // Backing up global post.
386
+ $post_backup = $post;
387
+
388
+ $post = $this->post;
389
+
390
+ // Checking when first name is not set for user, so it should match with user_login.
391
+ $first_names = coauthors_firstnames( null, null, null, null, false );
392
+
393
+ $this->assertEquals( $this->author1->user_login, $first_names );
394
+
395
+ $first_names = coauthors_firstnames( '</span><span>', '</span><span>', '<span>', '</span>', false );
396
+
397
+ $this->assertEquals( '<span>' . $this->author1->user_login . '</span>', $first_names );
398
+
399
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
400
+
401
+ $first_names = coauthors_firstnames( null, null, null, null, false );
402
+
403
+ $this->assertEquals( $this->author1->user_login . ' and ' . $this->editor1->user_login, $first_names );
404
+
405
+ $first_names = coauthors_firstnames( '</span><span>', '</span><span>', '<span>', '</span>', false );
406
+
407
+ $this->assertEquals( '<span>' . $this->author1->user_login . '</span><span>' . $this->editor1->user_login . '</span>', $first_names );
408
+
409
+ // Checking when first name is set for user.
410
+ $first_name = 'Test';
411
+ $user_id = $this->factory->user->create( array(
412
+ 'first_name' => $first_name,
413
+ ) );
414
+ $post = $this->factory->post->create_and_get( array(
415
+ 'post_author' => $user_id,
416
+ ) );
417
+
418
+ $first_names = coauthors_firstnames( null, null, null, null, false );
419
+
420
+ $this->assertEquals( $first_name, $first_names );
421
+
422
+ // Restore global post from backup.
423
+ $post = $post_backup;
424
+ }
425
+
426
+ /**
427
+ * Checks co-authors last names, without links to their posts.
428
+ *
429
+ * @covers ::coauthors_lastnames()
430
+ * @covers ::coauthors__echo()
431
+ */
432
+ public function test_coauthors_lastnames() {
433
+
434
+ global $post, $coauthors_plus;
435
+
436
+ // Backing up global post.
437
+ $post_backup = $post;
438
+
439
+ $post = $this->post;
440
+
441
+ // Checking when last name is not set for user, so it should match with user_login.
442
+ $last_names = coauthors_lastnames( null, null, null, null, false );
443
+
444
+ $this->assertEquals( $this->author1->user_login, $last_names );
445
+
446
+ $last_names = coauthors_lastnames( '</span><span>', '</span><span>', '<span>', '</span>', false );
447
+
448
+ $this->assertEquals( '<span>' . $this->author1->user_login . '</span>', $last_names );
449
+
450
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
451
+
452
+ $last_names = coauthors_lastnames( null, null, null, null, false );
453
+
454
+ $this->assertEquals( $this->author1->user_login . ' and ' . $this->editor1->user_login, $last_names );
455
+
456
+ $last_names = coauthors_lastnames( '</span><span>', '</span><span>', '<span>', '</span>', false );
457
+
458
+ $this->assertEquals( '<span>' . $this->author1->user_login . '</span><span>' . $this->editor1->user_login . '</span>', $last_names );
459
+
460
+ // Checking when last name is set for user.
461
+ $last_name = 'Test';
462
+ $user_id = $this->factory->user->create( array(
463
+ 'last_name' => $last_name,
464
+ ) );
465
+ $post = $this->factory->post->create_and_get( array(
466
+ 'post_author' => $user_id,
467
+ ) );
468
+
469
+ $last_names = coauthors_lastnames( null, null, null, null, false );
470
+
471
+ $this->assertEquals( $last_name, $last_names );
472
+
473
+ // Restore global post from backup.
474
+ $post = $post_backup;
475
+ }
476
+
477
+ /**
478
+ * Checks co-authors nicknames, without links to their posts.
479
+ *
480
+ * @covers ::coauthors_nicknames()
481
+ * @covers ::coauthors__echo()
482
+ */
483
+ public function test_coauthors_nicknames() {
484
+
485
+ global $post, $coauthors_plus;
486
+
487
+ // Backing up global post.
488
+ $post_backup = $post;
489
+
490
+ $post = $this->post;
491
+
492
+ // Checking when nickname is not set for user, so it should match with user_login.
493
+ $nick_names = coauthors_nicknames( null, null, null, null, false );
494
+
495
+ $this->assertEquals( $this->author1->user_login, $nick_names );
496
+
497
+ $nick_names = coauthors_nicknames( '</span><span>', '</span><span>', '<span>', '</span>', false );
498
+
499
+ $this->assertEquals( '<span>' . $this->author1->user_login . '</span>', $nick_names );
500
+
501
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
502
+
503
+ $nick_names = coauthors_nicknames( null, null, null, null, false );
504
+
505
+ $this->assertEquals( $this->author1->user_login . ' and ' . $this->editor1->user_login, $nick_names );
506
+
507
+ $nick_names = coauthors_nicknames( '</span><span>', '</span><span>', '<span>', '</span>', false );
508
+
509
+ $this->assertEquals( '<span>' . $this->author1->user_login . '</span><span>' . $this->editor1->user_login . '</span>', $nick_names );
510
+
511
+ // Checking when nickname is set for user.
512
+ $nick_name = 'Test';
513
+ $user_id = $this->factory->user->create( array(
514
+ 'nickname' => $nick_name,
515
+ ) );
516
+ $post = $this->factory->post->create_and_get( array(
517
+ 'post_author' => $user_id,
518
+ ) );
519
+
520
+ $nick_names = coauthors_nicknames( null, null, null, null, false );
521
+
522
+ $this->assertEquals( $nick_name, $nick_names );
523
+
524
+ // Restore global post from backup.
525
+ $post = $post_backup;
526
+ }
527
+
528
+ /**
529
+ * Checks co-authors email addresses.
530
+ *
531
+ * @covers ::coauthors_emails()
532
+ * @covers ::coauthors__echo()
533
+ */
534
+ public function test_coauthors_emails() {
535
+
536
+ global $post, $coauthors_plus;
537
+
538
+ // Backing up global post.
539
+ $post_backup = $post;
540
+
541
+ $post = $this->post;
542
+
543
+ $emails = coauthors_emails( null, null, null, null, false );
544
+
545
+ $this->assertEquals( $this->author1->user_email, $emails );
546
+
547
+ $emails = coauthors_emails( '</span><span>', '</span><span>', '<span>', '</span>', false );
548
+
549
+ $this->assertEquals( '<span>' . $this->author1->user_email . '</span>', $emails );
550
+
551
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
552
+
553
+ $emails = coauthors_emails( null, null, null, null, false );
554
+
555
+ $this->assertEquals( $this->author1->user_email . ' and ' . $this->editor1->user_email, $emails );
556
+
557
+ $emails = coauthors_emails( '</span><span>', '</span><span>', '<span>', '</span>', false );
558
+
559
+ $this->assertEquals( '<span>' . $this->author1->user_email . '</span><span>' . $this->editor1->user_email . '</span>', $emails );
560
+
561
+ $email = 'test@example.org';
562
+ $user_id = $this->factory->user->create( array(
563
+ 'user_email' => $email,
564
+ ) );
565
+ $post = $this->factory->post->create_and_get( array(
566
+ 'post_author' => $user_id,
567
+ ) );
568
+
569
+ $emails = coauthors_emails( null, null, null, null, false );
570
+
571
+ $this->assertEquals( $email, $emails );
572
+
573
+ // Restore global post from backup.
574
+ $post = $post_backup;
575
+ }
576
+
577
+ /**
578
+ * Checks single co-author if he/she is a guest author.
579
+ *
580
+ * @covers ::coauthors_links_single()
581
+ */
582
+ public function test_coauthors_links_single_when_guest_author() {
583
+
584
+ global $post, $authordata;
585
+
586
+ // Backing up global post.
587
+ $post_backup = $post;
588
+
589
+ $post = $this->post;
590
+
591
+ // Backing up global author data.
592
+ $authordata_backup = $authordata;
593
+
594
+ $this->author1->type = 'guest-author';
595
+
596
+ $this->assertNull( coauthors_links_single( $this->author1 ) );
597
+
598
+ update_user_meta( $this->author1->ID, 'website', 'example.org' );
599
+
600
+ $this->assertNull( coauthors_links_single( $this->author1 ) );
601
+
602
+ $authordata = $this->author1;
603
+ $author_link = coauthors_links_single( $this->author1 );
604
+
605
+ $this->assertContains( get_the_author_meta( 'website' ), $author_link, 'Author link not found.' );
606
+ $this->assertContains( get_the_author(), $author_link, 'Author name not found.' );
607
+
608
+ // Here we are checking author name should not be more then one time.
609
+ // Asserting ">get_the_author()<" because "get_the_author()" can be multiple times like in href, title, etc.
610
+ $this->assertEquals( 1, substr_count( $author_link, '>' . get_the_author() . '<' ) );
611
+
612
+ // Restore global author data from backup.
613
+ $authordata = $authordata_backup;
614
+
615
+ // Restore global post from backup.
616
+ $post = $post_backup;
617
+ }
618
+
619
+ /**
620
+ * Checks single co-author when user's url is set and not a guest author.
621
+ *
622
+ * @covers ::coauthors_links_single()
623
+ */
624
+ public function test_coauthors_links_single_author_url_is_set() {
625
+
626
+ global $post, $authordata;
627
+
628
+ // Backing up global post.
629
+ $post_backup = $post;
630
+
631
+ $post = $this->post;
632
+
633
+ // Backing up global author data.
634
+ $authordata_backup = $authordata;
635
+
636
+ $user_id = $this->factory->user->create( array(
637
+ 'user_url' => 'example.org',
638
+ ) );
639
+ $user = get_user_by( 'id', $user_id );
640
+
641
+ $authordata = $user;
642
+ $author_link = coauthors_links_single( $user );
643
+
644
+ $this->assertContains( get_the_author_meta( 'url' ), $author_link, 'Author link not found.' );
645
+ $this->assertContains( get_the_author(), $author_link, 'Author name not found.' );
646
+
647
+ // Here we are checking author name should not be more then one time.
648
+ // Asserting ">get_the_author()<" because "get_the_author()" can be multiple times like in href, title, etc.
649
+ $this->assertEquals( 1, substr_count( $author_link, '>' . get_the_author() . '<' ) );
650
+
651
+ // Restore global author data from backup.
652
+ $authordata = $authordata_backup;
653
+
654
+ // Restore global post from backup.
655
+ $post = $post_backup;
656
+ }
657
+
658
+ /**
659
+ * Checks single co-author when user's website/url not exist.
660
+ *
661
+ * @covers ::coauthors_links_single()
662
+ */
663
+ public function test_coauthors_links_single_when_url_not_exist() {
664
+
665
+ global $post, $authordata;
666
+
667
+ // Backing up global post.
668
+ $post_backup = $post;
669
+
670
+ $post = $this->post;
671
+
672
+ // Backing up global author data.
673
+ $authordata_backup = $authordata;
674
+
675
+ $this->editor1->type = 'guest-author';
676
+
677
+ $author_link = coauthors_links_single( $this->editor1 );
678
+
679
+ $this->assertEmpty( $author_link );
680
+
681
+ $authordata = $this->author1;
682
+ $author_link = coauthors_links_single( $this->author1 );
683
+
684
+ $this->assertEquals( get_the_author(), $author_link );
685
+
686
+ // Restore global author data from backup.
687
+ $authordata = $authordata_backup;
688
+
689
+ // Restore global post from backup.
690
+ $post = $post_backup;
691
+ }
692
+
693
+ /**
694
+ * Checks co-authors IDs.
695
+ *
696
+ * @covers ::coauthors_ids()
697
+ * @covers ::coauthors__echo()
698
+ */
699
+ public function test_coauthors_ids() {
700
+
701
+ global $post, $coauthors_plus;
702
+
703
+ // Backing up global post.
704
+ $post_backup = $post;
705
+
706
+ $post = $this->post;
707
+
708
+ $ids = coauthors_ids( null, null, null, null, false );
709
+
710
+ $this->assertEquals( $this->author1->ID, $ids );
711
+
712
+ $ids = coauthors_ids( '</span><span>', '</span><span>', '<span>', '</span>', false );
713
+
714
+ $this->assertEquals( '<span>' . $this->author1->ID . '</span>', $ids );
715
+
716
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
717
+
718
+ $ids = coauthors_ids( null, null, null, null, false );
719
+
720
+ $this->assertEquals( $this->author1->ID . ' and ' . $this->editor1->ID, $ids );
721
+
722
+ $ids = coauthors_ids( '</span><span>', '</span><span>', '<span>', '</span>', false );
723
+
724
+ $this->assertEquals( '<span>' . $this->author1->ID . '</span><span>' . $this->editor1->ID . '</span>', $ids );
725
+
726
+ // Restore global post from backup.
727
+ $post = $post_backup;
728
+ }
729
+
730
+ /**
731
+ * Checks co-authors meta.
732
+ *
733
+ * @covers ::get_the_coauthor_meta()
734
+ */
735
+ public function test_get_the_coauthor_meta() {
736
+
737
+ global $post;
738
+
739
+ // Backing up global post.
740
+ $post_backup = $post;
741
+
742
+ $this->assertEmpty( get_the_coauthor_meta( '' ) );
743
+
744
+ update_user_meta( $this->author1->ID, 'meta_key', 'meta_value' );
745
+
746
+ $this->assertEmpty( get_the_coauthor_meta( 'meta_key' ) );
747
+
748
+ $post = $this->post;
749
+ $meta = get_the_coauthor_meta( 'meta_key' );
750
+
751
+ $this->assertEquals( 'meta_value', $meta[ $this->author1->ID ] );
752
+
753
+ // Restore global post from backup.
754
+ $post = $post_backup;
755
+ }
756
+
757
+ /**
758
+ * Checks all the co-authors of the blog with default args.
759
+ *
760
+ * @covers ::coauthors_wp_list_authors()
761
+ */
762
+ public function test_coauthors_wp_list_authors_for_default_args() {
763
+
764
+ global $coauthors_plus;
765
+
766
+ $args = array(
767
+ 'echo' => false,
768
+ );
769
+
770
+ $coauthors = coauthors_wp_list_authors( $args );
771
+
772
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $coauthors, 'Author link not found.' );
773
+ $this->assertContains( $this->author1->display_name, $coauthors, 'Author name not found.' );
774
+
775
+ $coauthors = coauthors_wp_list_authors( $args );
776
+
777
+ $this->assertNotContains( 'href="' . get_author_posts_url( $this->editor1->ID, $this->editor1->user_nicename ) . '"', $coauthors );
778
+ $this->assertNotContains( $this->editor1->display_name, $coauthors );
779
+
780
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
781
+
782
+ $coauthors = coauthors_wp_list_authors( $args );
783
+
784
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $coauthors, 'Main author link not found.' );
785
+ $this->assertContains( $this->author1->display_name, $coauthors, 'Main author name not found.' );
786
+
787
+ // Here we are checking author name should not be more then one time.
788
+ // Asserting ">{$this->author1->display_name}<" because "$this->author1->display_name" can be multiple times like in href, title, etc.
789
+ $this->assertEquals( 1, substr_count( $coauthors, ">{$this->author1->display_name}<" ) );
790
+
791
+ $this->assertContains( '</li><li>', $coauthors, 'Coauthors name separator is not matched.' );
792
+ $this->assertContains( 'href="' . get_author_posts_url( $this->editor1->ID, $this->editor1->user_nicename ) . '"', $coauthors, 'Coauthor link not found.' );
793
+ $this->assertContains( $this->editor1->display_name, $coauthors, 'Coauthor name not found.' );
794
+
795
+ // Here we are checking editor name should not be more then one time.
796
+ // Asserting ">{$this->editor1->display_name}<" because "$this->editor1->display_name" can be multiple times like in href, title, etc.
797
+ $this->assertEquals( 1, substr_count( $coauthors, ">{$this->editor1->display_name}<" ) );
798
+ }
799
+
800
+ /**
801
+ * Checks all the co-authors of the blog with optioncount option.
802
+ *
803
+ * @covers ::coauthors_wp_list_authors()
804
+ */
805
+ public function test_coauthors_wp_list_authors_for_optioncount() {
806
+
807
+ $this->assertContains( '(' . count_user_posts( $this->author1->ID ) . ')', coauthors_wp_list_authors( array(
808
+ 'echo' => false,
809
+ 'optioncount' => true,
810
+ ) ) );
811
+ }
812
+
813
+ /**
814
+ * Checks all the co-authors of the blog with show_fullname option.
815
+ *
816
+ * @covers ::coauthors_wp_list_authors()
817
+ */
818
+ public function test_coauthors_wp_list_authors_for_show_fullname() {
819
+
820
+ $args = array(
821
+ 'echo' => false,
822
+ 'show_fullname' => true,
823
+ );
824
+
825
+ $this->assertContains( $this->author1->display_name, coauthors_wp_list_authors( $args ) );
826
+
827
+ $user = $this->factory->user->create_and_get( array(
828
+ 'first_name' => 'First',
829
+ 'last_name' => 'Last',
830
+ ) );
831
+
832
+ $this->factory->post->create( array(
833
+ 'post_author' => $user->ID,
834
+ ) );
835
+
836
+ $this->assertContains( "{$user->user_firstname} {$user->user_lastname}", coauthors_wp_list_authors( $args ) );
837
+ }
838
+
839
+ /**
840
+ * Checks all the co-authors of the blog with hide_empty option.
841
+ *
842
+ * @covers ::coauthors_wp_list_authors()
843
+ */
844
+ public function test_coauthors_wp_list_authors_for_hide_empty() {
845
+
846
+ global $coauthors_plus;
847
+
848
+ $coauthors_plus->guest_authors->create( array(
849
+ 'user_login' => 'author2',
850
+ 'display_name' => 'author2',
851
+ ) );
852
+
853
+ $this->assertContains( 'author2', coauthors_wp_list_authors( array(
854
+ 'echo' => false,
855
+ 'hide_empty' => false,
856
+ ) ) );
857
+ }
858
+
859
+ /**
860
+ * Checks all the co-authors of the blog with feed option.
861
+ *
862
+ * @covers ::coauthors_wp_list_authors()
863
+ */
864
+ public function test_coauthors_wp_list_authors_for_feed() {
865
+
866
+ $feed_text = 'link to feed';
867
+ $coauthors = coauthors_wp_list_authors( array(
868
+ 'echo' => false,
869
+ 'feed' => $feed_text,
870
+ ) );
871
+
872
+ $this->assertContains( esc_url( get_author_feed_link( $this->author1->ID ) ), $coauthors );
873
+ $this->assertContains( $feed_text, $coauthors );
874
+ }
875
+
876
+ /**
877
+ * Checks all the co-authors of the blog with feed_image option.
878
+ *
879
+ * @covers ::coauthors_wp_list_authors()
880
+ */
881
+ public function test_coauthors_wp_list_authors_for_feed_image() {
882
+
883
+ $feed_image = WP_TESTS_DOMAIN . '/path/to/a/graphic.png';
884
+ $coauthors = coauthors_wp_list_authors( array(
885
+ 'echo' => false,
886
+ 'feed_image' => $feed_image,
887
+ ) );
888
+
889
+ $this->assertContains( esc_url( get_author_feed_link( $this->author1->ID ) ), $coauthors );
890
+ $this->assertContains( $feed_image, $coauthors );
891
+ }
892
+
893
+ /**
894
+ * Checks all the co-authors of the blog with feed_type option.
895
+ *
896
+ * @covers ::coauthors_wp_list_authors()
897
+ */
898
+ public function test_coauthors_wp_list_authors_for_feed_type() {
899
+
900
+ $feed_type = 'atom';
901
+ $feed_text = 'link to feed';
902
+ $coauthors = coauthors_wp_list_authors( array(
903
+ 'echo' => false,
904
+ 'feed_type' => $feed_type,
905
+ 'feed' => $feed_text,
906
+ ) );
907
+
908
+ $this->assertContains( esc_url( get_author_feed_link( $this->author1->ID, $feed_type ) ), $coauthors );
909
+ $this->assertContains( $feed_type, $coauthors );
910
+ $this->assertContains( $feed_text, $coauthors );
911
+ }
912
+
913
+ /**
914
+ * Checks all the co-authors of the blog with style option.
915
+ *
916
+ * @covers ::coauthors_wp_list_authors()
917
+ */
918
+ public function test_coauthors_wp_list_authors_for_style() {
919
+
920
+ $coauthors = coauthors_wp_list_authors( array(
921
+ 'echo' => false,
922
+ 'style' => 'none',
923
+ ) );
924
+
925
+ $this->assertNotContains( '<li>', $coauthors );
926
+ $this->assertNotContains( '</li>', $coauthors );
927
+ }
928
+
929
+ /**
930
+ * Checks all the co-authors of the blog with html option.
931
+ *
932
+ * @covers ::coauthors_wp_list_authors()
933
+ */
934
+ public function test_coauthors_wp_list_authors_for_html() {
935
+
936
+ global $coauthors_plus;
937
+
938
+ $args = array(
939
+ 'echo' => false,
940
+ 'html' => false,
941
+ );
942
+
943
+ $this->assertEquals( $this->author1->display_name, coauthors_wp_list_authors( $args ) );
944
+
945
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
946
+
947
+ $this->assertEquals( "{$this->author1->display_name}, {$this->editor1->display_name}", coauthors_wp_list_authors( $args ) );
948
+ }
949
+
950
+ /**
951
+ * Checks all the co-authors of the blog with guest_authors_only option.
952
+ *
953
+ * @covers ::coauthors_wp_list_authors()
954
+ */
955
+ public function test_coauthors_wp_list_authors_for_guest_authors_only() {
956
+
957
+ global $coauthors_plus;
958
+
959
+ $args = array(
960
+ 'echo' => false,
961
+ 'guest_authors_only' => true,
962
+ );
963
+
964
+ $this->assertEmpty( coauthors_wp_list_authors( $args ) );
965
+
966
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
967
+ 'user_login' => 'author2',
968
+ 'display_name' => 'author2',
969
+ ) );
970
+
971
+ $this->assertEmpty( coauthors_wp_list_authors( $args ) );
972
+
973
+ $guest_author = $coauthors_plus->guest_authors->get_guest_author_by( 'id', $guest_author_id );
974
+
975
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $guest_author->user_login ), true );
976
+
977
+ $this->assertContains( $guest_author->display_name, coauthors_wp_list_authors( $args ) );
978
+ }
979
+
980
+ /**
981
+ * Checks co-author's avatar.
982
+ *
983
+ * @covers ::coauthors_get_avatar()
984
+ */
985
+ public function test_coauthors_get_avatar_default() {
986
+
987
+ $this->assertEmpty( coauthors_get_avatar( $this->author1->ID ) );
988
+ $this->assertEquals( preg_match( "|^<img alt='[^']*' src='[^']*' srcset='[^']*' class='[^']*' height='[^']*' width='[^']*' />$|", coauthors_get_avatar( $this->author1 ) ), 1 );
989
+ }
990
+
991
+ /**
992
+ * Checks co-author's avatar when author is a guest author.
993
+ *
994
+ * @covers ::coauthors_get_avatar()
995
+ */
996
+ public function test_coauthors_get_avatar_when_guest_author() {
997
+
998
+ global $coauthors_plus;
999
+
1000
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
1001
+ 'user_login' => 'author2',
1002
+ 'display_name' => 'author2',
1003
+ ) );
1004
+
1005
+ $guest_author = $coauthors_plus->guest_authors->get_guest_author_by( 'id', $guest_author_id );
1006
+
1007
+ $this->assertEquals( preg_match( "|^<img alt='[^']*' src='[^']*' srcset='[^']*' class='[^']*' height='[^']*' width='[^']*' />$|", coauthors_get_avatar( $guest_author ) ), 1 );
1008
+
1009
+ $filename = rand_str() . '.jpg';
1010
+ $contents = rand_str();
1011
+ $upload = wp_upload_bits( $filename, null, $contents );
1012
+
1013
+ $this->assertTrue( empty( $upload['error'] ) );
1014
+
1015
+ $attachment_id = $this->_make_attachment( $upload );
1016
+
1017
+ set_post_thumbnail( $guest_author->ID, $attachment_id );
1018
+
1019
+ $avatar = coauthors_get_avatar( $guest_author );
1020
+ $attachment_url = wp_get_attachment_url( $attachment_id );
1021
+
1022
+ $this->assertContains( $filename, $avatar );
1023
+ $this->assertContains( 'src="' . $attachment_url . '"', $avatar );
1024
+ }
1025
+
1026
+ /**
1027
+ * Checks co-author's avatar when user's email is not set somehow.
1028
+ *
1029
+ * @covers ::coauthors_get_avatar()
1030
+ */
1031
+ public function test_coauthors_get_avatar_when_user_email_not_set() {
1032
+
1033
+ global $coauthors_plus;
1034
+
1035
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
1036
+ 'user_login' => 'author2',
1037
+ 'display_name' => 'author2',
1038
+ ) );
1039
+
1040
+ $guest_author = $coauthors_plus->guest_authors->get_guest_author_by( 'id', $guest_author_id );
1041
+
1042
+ unset( $guest_author->user_email );
1043
+
1044
+ $this->assertEmpty( coauthors_get_avatar( $guest_author ) );
1045
+ }
1046
+
1047
+ /**
1048
+ * Checks co-author's avatar with size.
1049
+ *
1050
+ * @covers ::coauthors_get_avatar()
1051
+ */
1052
+ public function test_coauthors_get_avatar_size() {
1053
+
1054
+ $size = '100';
1055
+ $this->assertEquals( preg_match( "|^<img .*height='$size'.*width='$size'|", coauthors_get_avatar( $this->author1, $size ) ), 1 );
1056
+ }
1057
+
1058
+ /**
1059
+ * Checks co-author's avatar with alt.
1060
+ *
1061
+ * @covers ::coauthors_get_avatar()
1062
+ */
1063
+ public function test_coauthors_get_avatar_alt() {
1064
+
1065
+ $alt = 'Test';
1066
+ $this->assertEquals( preg_match( "|^<img alt='$alt'|", coauthors_get_avatar( $this->author1, 96, '', $alt ) ), 1 );
1067
+ }
1068
+ }