Co-Authors Plus - Version 3.2.2

Version Description

  • Fix broken author ordering in 4.7+ (props mslinnea)
  • Fix no moderation e-mail bug (props RobjS)
  • Cached functions in CLI commands (props jasonbahl)
  • Fix missing echos (props trepmal)
  • Add coauthors_guest_author_query_args filter (props trepmal)
Download this release

Release Info

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

Code changes from version 3.2.1 to 3.2.2

.travis.yml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.3
5
+ - 5.5
6
+
7
+ env:
8
+ - WP_VERSION=latest
9
+ - WP_VERSION=3.7
10
+
11
+ before_script:
12
+ - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
13
+
14
+ script: phpunit
bin/install-wp-tests.sh ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ if [ $# -lt 3 ]; then
4
+ echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version]"
5
+ exit 1
6
+ fi
7
+
8
+ DB_NAME=$1
9
+ DB_USER=$2
10
+ DB_PASS=$3
11
+ DB_HOST=${4-localhost}
12
+ WP_VERSION=${5-latest}
13
+
14
+ WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
15
+ WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
16
+
17
+ download() {
18
+ if [ `which curl` ]; then
19
+ curl -s "$1" > "$2";
20
+ elif [ `which wget` ]; then
21
+ wget -nv -O "$2" "$1"
22
+ fi
23
+ }
24
+
25
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
26
+ WP_TESTS_TAG="tags/$WP_VERSION"
27
+ else
28
+ # http serves a single offer, whereas https serves multiple. we only want one
29
+ download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
30
+ grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
31
+ LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
32
+ if [[ -z "$LATEST_VERSION" ]]; then
33
+ echo "Latest WordPress version could not be found"
34
+ exit 1
35
+ fi
36
+ WP_TESTS_TAG="tags/$LATEST_VERSION"
37
+ fi
38
+
39
+ set -ex
40
+
41
+ install_wp() {
42
+
43
+ if [ -d $WP_CORE_DIR ]; then
44
+ return;
45
+ fi
46
+
47
+ mkdir -p $WP_CORE_DIR
48
+
49
+ if [ $WP_VERSION == 'latest' ]; then
50
+ local ARCHIVE_NAME='latest'
51
+ else
52
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
53
+ fi
54
+
55
+ download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz
56
+ tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
57
+
58
+ download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
59
+ }
60
+
61
+ install_test_suite() {
62
+ # portable in-place argument for both GNU sed and Mac OSX sed
63
+ if [[ $(uname -s) == 'Darwin' ]]; then
64
+ local ioption='-i .bak'
65
+ else
66
+ local ioption='-i'
67
+ fi
68
+
69
+ # set up testing suite if it doesn't yet exist
70
+ if [ ! -d $WP_TESTS_DIR ]; then
71
+ # set up testing suite
72
+ mkdir -p $WP_TESTS_DIR
73
+ svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
74
+ fi
75
+
76
+ cd $WP_TESTS_DIR
77
+
78
+ if [ ! -f wp-tests-config.php ]; then
79
+ download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
80
+ sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php
81
+ sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
82
+ sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
83
+ sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
84
+ sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
85
+ fi
86
+
87
+ }
88
+
89
+ install_db() {
90
+ # parse DB_HOST for port or socket references
91
+ local PARTS=(${DB_HOST//\:/ })
92
+ local DB_HOSTNAME=${PARTS[0]};
93
+ local DB_SOCK_OR_PORT=${PARTS[1]};
94
+ local EXTRA=""
95
+
96
+ if ! [ -z $DB_HOSTNAME ] ; then
97
+ if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
98
+ EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
99
+ elif ! [ -z $DB_SOCK_OR_PORT ] ; then
100
+ EXTRA=" --socket=$DB_SOCK_OR_PORT"
101
+ elif ! [ -z $DB_HOSTNAME ] ; then
102
+ EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
103
+ fi
104
+ fi
105
+
106
+ # create database
107
+ mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
108
+ }
109
+
110
+ install_wp
111
+ install_test_suite
112
+ install_db
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.1
7
  Author: Mohammad Jangda, Daniel Bachhuber, Automattic
8
  Copyright: 2008-2015 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
@@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
 
25
  */
26
 
27
- define( 'COAUTHORS_PLUS_VERSION', '3.2.1' );
28
 
29
  require_once( dirname( __FILE__ ) . '/template-tags.php' );
30
  require_once( dirname( __FILE__ ) . '/deprecated.php' );
@@ -116,6 +116,10 @@ class CoAuthors_Plus {
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
  }
120
 
121
  /**
@@ -375,14 +379,14 @@ class CoAuthors_Plus {
375
  ?>
376
  </ul>
377
  <div class="clear"></div>
378
- <p><?php wp_kses( __( '<strong>Note:</strong> To edit post authors, please enable javascript or use a javascript-capable browser', 'co-authors-plus' ), array( 'strong' => array() ) ); ?></p>
379
  </div>
380
  <?php
381
  endif;
382
  ?>
383
 
384
  <div id="coauthors-edit" class="hide-if-no-js">
385
- <p><?php wp_kses( __( 'Click on an author to change them. Drag to change their order. Click on <strong>Remove</strong> to remove them.', 'co-authors-plus' ), array( 'strong' => array() ) ); ?></p>
386
  </div>
387
 
388
  <?php wp_nonce_field( 'coauthors-edit', 'coauthors-nonce' ); ?>
@@ -506,7 +510,7 @@ class CoAuthors_Plus {
506
  <label class="inline-edit-group inline-edit-coauthors">
507
  <span class="title"><?php esc_html_e( 'Authors', 'co-authors-plus' ) ?></span>
508
  <div id="coauthors-edit" class="hide-if-no-js">
509
- <p><?php wp_kses( __( 'Click on an author to change them. Drag to change their order. Click on <strong>Remove</strong> to remove them.', 'co-authors-plus' ), array( 'strong' => array() ) ); ?></p>
510
  </div>
511
  <?php wp_nonce_field( 'coauthors-edit', 'coauthors-nonce' ); ?>
512
  </label>
@@ -611,12 +615,18 @@ class CoAuthors_Plus {
611
  }
612
 
613
  // Check to see that JOIN hasn't already been added. Props michaelingp and nbaxley
614
- $term_relationship_join = " INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
615
- $term_taxonomy_join = " INNER JOIN {$wpdb->term_taxonomy} ON ( {$wpdb->term_relationships}.term_taxonomy_id = {$wpdb->term_taxonomy}.term_taxonomy_id )";
616
 
617
- if ( false === strpos( $join, trim( $term_relationship_join ) ) ) {
618
- $join .= str_replace( 'INNER JOIN', 'LEFT JOIN', $term_relationship_join );
 
 
 
 
 
619
  }
 
620
  if ( false === strpos( $join, trim( $term_taxonomy_join ) ) ) {
621
  $join .= str_replace( 'INNER JOIN', 'LEFT JOIN', $term_taxonomy_join );
622
  }
@@ -1463,6 +1473,68 @@ class CoAuthors_Plus {
1463
  // Send back the updated Open Graph Tags
1464
  return apply_filters( 'coauthors_open_graph_tags', $og_tags );
1465
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1466
  }
1467
 
1468
  global $coauthors_plus;
@@ -1595,6 +1667,7 @@ function cap_filter_comment_moderation_email_recipients( $recipients, $comment_i
1595
 
1596
  if ( isset( $post_id ) ) {
1597
  $coauthors = get_coauthors( $post_id );
 
1598
  foreach ( $coauthors as $user ) {
1599
  if ( ! empty( $user->user_email ) ) {
1600
  $extra_recipients[] = $user->user_email;
@@ -1605,3 +1678,17 @@ function cap_filter_comment_moderation_email_recipients( $recipients, $comment_i
1605
  }
1606
  return $recipients;
1607
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
 
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' );
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
  /**
379
  ?>
380
  </ul>
381
  <div class="clear"></div>
382
+ <p><?php echo wp_kses( __( '<strong>Note:</strong> To edit post authors, please enable javascript or use a javascript-capable browser', 'co-authors-plus' ), array( 'strong' => array() ) ); ?></p>
383
  </div>
384
  <?php
385
  endif;
386
  ?>
387
 
388
  <div id="coauthors-edit" class="hide-if-no-js">
389
+ <p><?php echo wp_kses( __( 'Click on an author to change them. Drag to change their order. Click on <strong>Remove</strong> to remove them.', 'co-authors-plus' ), array( 'strong' => array() ) ); ?></p>
390
  </div>
391
 
392
  <?php wp_nonce_field( 'coauthors-edit', 'coauthors-nonce' ); ?>
510
  <label class="inline-edit-group inline-edit-coauthors">
511
  <span class="title"><?php esc_html_e( 'Authors', 'co-authors-plus' ) ?></span>
512
  <div id="coauthors-edit" class="hide-if-no-js">
513
+ <p><?php echo wp_kses( __( 'Click on an author to change them. Drag to change their order. Click on <strong>Remove</strong> to remove them.', 'co-authors-plus' ), array( 'strong' => array() ) ); ?></p>
514
  </div>
515
  <?php wp_nonce_field( 'coauthors-edit', 'coauthors-nonce' ); ?>
516
  </label>
615
  }
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 ) )
626
+ && false === strpos( $join, trim( $term_relationship_left_join ) ) ) {
627
+ $join .= $term_relationship_left_join;
628
  }
629
+
630
  if ( false === strpos( $join, trim( $term_taxonomy_join ) ) ) {
631
  $join .= str_replace( 'INNER JOIN', 'LEFT JOIN', $term_taxonomy_join );
632
  }
1473
  // Send back the updated Open Graph Tags
1474
  return apply_filters( 'coauthors_open_graph_tags', $og_tags );
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 ) {
1487
+
1488
+ if ( ! $post_id ) {
1489
+ return array();
1490
+ }
1491
+
1492
+ $cache_key = 'coauthors_post_' . $post_id;
1493
+ $coauthor_terms = wp_cache_get( $cache_key, 'co-authors-plus' );
1494
+
1495
+ if ( false === $coauthor_terms ) {
1496
+ $coauthor_terms = wp_get_object_terms( $post_id, $this->coauthor_taxonomy, array(
1497
+ 'orderby' => 'term_order',
1498
+ 'order' => 'ASC',
1499
+ ) );
1500
+
1501
+ // This usually happens if the taxonomy doesn't exist, which should never happen, but you never know.
1502
+ if ( is_wp_error( $coauthor_terms ) ) {
1503
+ return array();
1504
+ }
1505
+
1506
+ wp_cache_set( $cache_key, $coauthor_terms, 'co-authors-plus' );
1507
+ }
1508
+
1509
+ return $coauthor_terms;
1510
+
1511
+ }
1512
+
1513
+ /**
1514
+ * Callback to clear the cache on post save and post delete.
1515
+ *
1516
+ * @param $post_id The Post ID.
1517
+ */
1518
+ public function clear_cache( $post_id ) {
1519
+ wp_cache_delete( 'coauthors_post_' . $post_id, 'co-authors-plus' );
1520
+ }
1521
+
1522
+ /**
1523
+ * Callback to clear the cache when an object's terms are changed.
1524
+ *
1525
+ * @param $post_id The Post ID.
1526
+ */
1527
+ public function clear_cache_on_terms_set( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
1528
+
1529
+ // We only care about the coauthors taxonomy
1530
+ if ( $this->coauthor_taxonomy !== $taxonomy ) {
1531
+ return;
1532
+ }
1533
+
1534
+ wp_cache_delete( 'coauthors_post_' . $object_id, 'co-authors-plus' );
1535
+
1536
+ }
1537
+
1538
  }
1539
 
1540
  global $coauthors_plus;
1667
 
1668
  if ( isset( $post_id ) ) {
1669
  $coauthors = get_coauthors( $post_id );
1670
+ $extra_recipients = array();
1671
  foreach ( $coauthors as $user ) {
1672
  if ( ! empty( $user->user_email ) ) {
1673
  $extra_recipients[] = $user->user_email;
1678
  }
1679
  return $recipients;
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.
1687
+ *
1688
+ * @param int $post_id ID of the post for which to retrieve authors.
1689
+ * @return array Array of coauthor WP_Term objects
1690
+ */
1691
+ function cap_get_coauthor_terms_for_post( $post_id ) {
1692
+ global $coauthors_plus;
1693
+ return $coauthors_plus->get_coauthor_terms_for_post( $post_id );
1694
+ }
php/class-coauthors-guest-authors.php CHANGED
@@ -675,11 +675,21 @@ class CoAuthors_Guest_Authors
675
  foreach ( $fields as $field ) {
676
  $pm_key = $this->get_post_meta_key( $field['key'] );
677
  $value = get_post_meta( $post->ID, $pm_key, true );
678
- echo '<tr><th>';
679
- echo '<label for="' . esc_attr( $pm_key ) . '">' . esc_html( $field['label'] ) . '</label>';
680
- echo '</th><td>';
681
- echo '<textarea style="width:300px;margin-bottom:6px;" name="' . esc_attr( $pm_key ) . '">' . esc_textarea( $value ) . '</textarea>';
682
- echo '</td></tr>';
 
 
 
 
 
 
 
 
 
 
683
  }
684
  echo '</tbody></table>';
685
 
675
  foreach ( $fields as $field ) {
676
  $pm_key = $this->get_post_meta_key( $field['key'] );
677
  $value = get_post_meta( $post->ID, $pm_key, true );
678
+ printf( '
679
+ <tr>
680
+ <th>
681
+ <label for="%s">%s</label>
682
+ </th>
683
+ <td>
684
+ <textarea style="width:300px;margin-bottom:6px;" name="%s">%s</textarea>
685
+ </td>
686
+ </tr>
687
+ ',
688
+ esc_attr( $pm_key ),
689
+ esc_html( $field['label'] ),
690
+ esc_attr( $pm_key ),
691
+ esc_textarea( $value )
692
+ );
693
  }
694
  echo '</tbody></table>';
695
 
php/class-coauthors-wp-list-table.php CHANGED
@@ -64,6 +64,8 @@ class CoAuthors_WP_List_Table extends WP_List_Table {
64
  'order' => 'ASC',
65
  );
66
 
 
 
67
  if ( isset( $_REQUEST['orderby'] ) ) {
68
  switch ( $_REQUEST['orderby'] ) {
69
  case 'display_name':
64
  'order' => 'ASC',
65
  );
66
 
67
+ $args = apply_filters( 'coauthors_guest_author_query_args', $args );
68
+
69
  if ( isset( $_REQUEST['orderby'] ) ) {
70
  switch ( $_REQUEST['orderby'] ) {
71
  case 'display_name':
php/class-wp-cli.php CHANGED
@@ -76,9 +76,9 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
76
 
77
  $count++;
78
 
79
- $terms = wp_get_post_terms( $single_post->ID, $coauthors_plus->coauthor_taxonomy );
80
- if ( is_wp_error( $terms ) ) {
81
- WP_CLI::error( $terms->get_error_message() );
82
  }
83
 
84
  if ( ! empty( $terms ) ) {
@@ -235,8 +235,13 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
235
  $posts = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author=%d AND post_type IN ('$post_types')", $user->ID ) );
236
  $affected = 0;
237
  foreach ( $posts as $post_id ) {
238
- if ( $coauthors = wp_get_post_terms( $post_id, $coauthors_plus->coauthor_taxonomy ) ) {
239
- WP_CLI::line( sprintf( __( 'Skipping - Post #%d already has co-authors assigned: %s', 'co-authors-plus' ), $post_id, implode( ', ', wp_list_pluck( $coauthors, 'slug' ) ) ) );
 
 
 
 
 
240
  continue;
241
  }
242
 
@@ -545,7 +550,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
545
 
546
  foreach ( $posts->posts as $single_post ) {
547
 
548
- $terms = wp_get_post_terms( $single_post->ID, $coauthors_plus->coauthor_taxonomy );
549
  if ( empty( $terms ) ) {
550
  $saved = array(
551
  $single_post->ID,
@@ -698,8 +703,8 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
698
  $affected = 0;
699
  foreach ( $ids as $post_id ) {
700
 
701
- $terms = wp_get_post_terms( $post_id, 'author' );
702
- if ( ! $terms ) {
703
  continue;
704
  }
705
 
76
 
77
  $count++;
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 ) ) {
235
  $posts = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author=%d AND post_type IN ('$post_types')", $user->ID ) );
236
  $affected = 0;
237
  foreach ( $posts as $post_id ) {
238
+ $coauthors = cap_get_coauthor_terms_for_post( $post_id );
239
+ if ( ! empty( $coauthors ) ) {
240
+ WP_CLI::line( sprintf(
241
+ __( 'Skipping - Post #%d already has co-authors assigned: %s', 'co-authors-plus' ),
242
+ $post_id,
243
+ implode( ', ', wp_list_pluck( $coauthors, 'slug' ) )
244
+ ) );
245
  continue;
246
  }
247
 
550
 
551
  foreach ( $posts->posts as $single_post ) {
552
 
553
+ $terms = cap_get_coauthor_terms_for_post( $single_post->ID );
554
  if ( empty( $terms ) ) {
555
  $saved = array(
556
  $single_post->ID,
703
  $affected = 0;
704
  foreach ( $ids as $post_id ) {
705
 
706
+ $terms = cap_get_coauthor_terms_for_post( $post_id );
707
+ if ( empty( $terms ) ) {
708
  continue;
709
  }
710
 
phpunit.xml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <phpunit
2
+ bootstrap="tests/bootstrap.php"
3
+ backupGlobals="false"
4
+ colors="true"
5
+ convertErrorsToExceptions="true"
6
+ convertNoticesToExceptions="true"
7
+ convertWarningsToExceptions="true"
8
+ >
9
+ <php>
10
+ <const name="WP_TESTS_MULTISITE" value="1" />
11
+ </php>
12
+ <testsuites>
13
+ <testsuite>
14
+ <directory prefix="test-" suffix=".php">./tests/</directory>
15
+ </testsuite>
16
+ </testsuites>
17
+ </phpunit>
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.7
5
  Requires at least: 4.1
6
- Stable tag: 3.2.1
7
 
8
  Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box
9
 
@@ -57,6 +57,13 @@ Bug fixes and minor enhancements
57
 
58
  == Changelog ==
59
 
 
 
 
 
 
 
 
60
  = 3.2.1 (May 16, 2016) =
61
  * Hotfix for broken Guest Author bio metabox (props JS Morisset)
62
 
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
 
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)
63
+ * Cached functions in CLI commands (props jasonbahl)
64
+ * Fix missing echos (props trepmal)
65
+ * Add `coauthors_guest_author_query_args` filter (props trepmal)
66
+
67
  = 3.2.1 (May 16, 2016) =
68
  * Hotfix for broken Guest Author bio metabox (props JS Morisset)
69
 
template-tags.php CHANGED
@@ -14,8 +14,7 @@ function get_coauthors( $post_id = 0 ) {
14
  }
15
 
16
  if ( $post_id ) {
17
- $coauthor_terms = get_the_terms( $post_id, $coauthors_plus->coauthor_taxonomy );
18
-
19
  if ( is_array( $coauthor_terms ) && ! empty( $coauthor_terms ) ) {
20
  foreach ( $coauthor_terms as $coauthor ) {
21
  $coauthor_slug = preg_replace( '#^cap\-#', '', $coauthor->slug );
14
  }
15
 
16
  if ( $post_id ) {
17
+ $coauthor_terms = cap_get_coauthor_terms_for_post( $post_id );
 
18
  if ( is_array( $coauthor_terms ) && ! empty( $coauthor_terms ) ) {
19
  foreach ( $coauthor_terms as $coauthor ) {
20
  $coauthor_slug = preg_replace( '#^cap\-#', '', $coauthor->slug );
tests/bootstrap.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $_tests_dir = getenv( 'WP_TESTS_DIR' );
4
+ if ( ! $_tests_dir ) {
5
+ $_tests_dir = '/tmp/wordpress-tests-lib';
6
+ }
7
+
8
+ require_once $_tests_dir . '/includes/functions.php';
9
+
10
+ function _manually_load_plugin() {
11
+ require dirname( __FILE__ ) . '/../co-authors-plus.php';
12
+ }
13
+ tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
14
+
15
+ require $_tests_dir . '/includes/bootstrap.php';
16
+
17
+ require dirname( __FILE__ ) . '/coauthorsplus-testcase.php';
tests/coauthorsplus-testcase.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Base unit test class for Co-Authors Plus
5
+ */
6
+ class CoAuthorsPlus_TestCase extends WP_UnitTestCase {
7
+ public function setUp() {
8
+ parent::setUp();
9
+
10
+ global $coauthors_plus;
11
+ $this->_cap = $coauthors_plus;
12
+ }
13
+ }
tests/test-author-queried-object.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Test Co-Authors Plus' modifications of author queries
4
+ */
5
+
6
+ class Test_Author_Queried_Object extends CoAuthorsPlus_TestCase {
7
+
8
+ /**
9
+ * Set up for test
10
+ *
11
+ * Don't create tables as 'temporary'.
12
+ *
13
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/398
14
+ */
15
+ function setUp() {
16
+ parent::setUp();
17
+
18
+ remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
19
+ remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
20
+ }
21
+
22
+ /**
23
+ * On author pages, the queried object should only be set
24
+ * to a user that's not a member of the blog if they
25
+ * have at least one published post. This matches core behavior.
26
+ *
27
+ * @see https://core.trac.wordpress.org/changeset/27290
28
+ */
29
+ function test__author_queried_object_fix() {
30
+ global $wp_rewrite, $coauthors_plus;
31
+
32
+ /**
33
+ * Set up
34
+ */
35
+ $author1 = $this->factory->user->create( array( 'user_login' => 'msauthor1' ) );
36
+ $author2 = $this->factory->user->create( array( 'user_login' => 'msauthor2' ) );
37
+ $blog2 = $this->factory->blog->create( array( 'user_id' => $author1 ) );
38
+
39
+ switch_to_blog( $blog2 );
40
+ $wp_rewrite->init();
41
+
42
+ $blog2_post1 = $this->factory->post->create( array(
43
+ 'post_status' => 'publish',
44
+ 'post_content' => rand_str(),
45
+ 'post_title' => rand_str(),
46
+ 'post_author' => $author1,
47
+ ) );
48
+
49
+ /**
50
+ * Author 1 is an author on the blog
51
+ */
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
+
64
+ /**
65
+ * Author 2 is now on the blog, but not yet published
66
+ */
67
+ $this->go_to( get_author_posts_url( $author2 ) );
68
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
69
+
70
+ // Add the user as an author on the original post
71
+ $author2_obj = get_user_by( 'id', $author2 );
72
+ $coauthors_plus->add_coauthors( $blog2_post1, array( $author2_obj->user_login ), true );
73
+
74
+ /**
75
+ * Author 2 is now on the blog, and published
76
+ */
77
+ $this->go_to( get_author_posts_url( $author2 ) );
78
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
79
+
80
+ // Remove the user from the blog
81
+ remove_user_from_blog( $author2, $blog2 );
82
+
83
+ /**
84
+ * Author 2 was removed from the blog, but still a published author
85
+ */
86
+ $this->go_to( get_author_posts_url( $author2 ) );
87
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
88
+
89
+ // Delete the user from the network
90
+ wpmu_delete_user( $author2 );
91
+
92
+ /**
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();
100
+
101
+ }
102
+ }
tests/test-author-queries.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_Author_Queries extends CoAuthorsPlus_TestCase {
4
+
5
+ public function test__author_arg__user_is_post_author() {
6
+ $author_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
7
+ $author = get_userdata( $author_id );
8
+ $post_id = $this->factory->post->create( array(
9
+ 'post_author' => $author_id,
10
+ 'post_status' => 'publish',
11
+ 'post_type' => 'post',
12
+ ) );
13
+ $this->_cap->add_coauthors( $post_id, array( $author->user_login ) );
14
+
15
+ $query = new WP_Query( array(
16
+ 'author' => $author_id,
17
+ ) );
18
+
19
+ $this->assertEquals( 1, count( $query->posts ) );
20
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
21
+ }
22
+
23
+ public function test__author_name_arg__user_is_post_author() {
24
+ $author_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
25
+ $author = get_userdata( $author_id );
26
+ $post_id = $this->factory->post->create( array(
27
+ 'post_author' => $author_id,
28
+ 'post_status' => 'publish',
29
+ 'post_type' => 'post',
30
+ ) );
31
+ $this->_cap->add_coauthors( $post_id, array( $author->user_login ) );
32
+
33
+ $query = new WP_Query( array(
34
+ 'author_name' => $author->user_login,
35
+ ) );
36
+
37
+ $this->assertEquals( 1, count( $query->posts ) );
38
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
39
+ }
40
+
41
+ public function test__author_name_arg__user_is_coauthor() {
42
+ $author1_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
43
+ $author1 = get_userdata( $author1_id );
44
+ $author2_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'superman' ) );
45
+ $author2 = get_userdata( $author2_id );
46
+
47
+ $post_id = $this->factory->post->create( array(
48
+ 'post_author' => $author1_id,
49
+ 'post_status' => 'publish',
50
+ 'post_type' => 'post',
51
+ ) );
52
+ $this->_cap->add_coauthors( $post_id, array( $author1->user_login, $author2->user_login ) );
53
+
54
+ $query = new WP_Query( array(
55
+ 'author_name' => $author2->user_login,
56
+ ) );
57
+
58
+ $this->assertEquals( 1, count( $query->posts ) );
59
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
60
+ }
61
+
62
+ public function test__author_arg__user_is_coauthor__author_arg() {
63
+ return; // TODO: re-enable; fails currently because WordPress generates query as `post_author IN (id)` which doesn't match our regex in the posts_where filter.
64
+
65
+ $author1_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
66
+ $author1 = get_userdata( $author1_id );
67
+ $author2_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'superman' ) );
68
+ $author2 = get_userdata( $author2_id );
69
+
70
+ $post_id = $this->factory->post->create( array(
71
+ 'post_author' => $author1_id,
72
+ 'post_status' => 'publish',
73
+ 'post_type' => 'post',
74
+ ) );
75
+ $this->_cap->add_coauthors( $post_id, array( $author1->user_login, $author2->user_login ) );
76
+
77
+ $query = new WP_Query( array(
78
+ 'author' => $author2_id,
79
+ ) );
80
+
81
+ $this->assertEquals( 1, count( $query->posts ) );
82
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
83
+ }
84
+
85
+ public function test__author_name_arg_plus_tax_query__user_is_post_author() {
86
+ $author_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
87
+ $author = get_userdata( $author_id );
88
+ $post_id = $this->factory->post->create( array(
89
+ 'post_author' => $author_id,
90
+ 'post_status' => 'publish',
91
+ 'post_type' => 'post',
92
+ ) );
93
+ $this->_cap->add_coauthors( $post_id, array( $author->user_login ) );
94
+ wp_set_post_terms( $post_id, 'test', 'post_tag' );
95
+
96
+ $query = new WP_Query( array(
97
+ 'author_name' => $author->user_login,
98
+ 'tag' => 'test',
99
+ ) );
100
+
101
+ $this->assertEquals( 1, count( $query->posts ) );
102
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
103
+ }
104
+
105
+ public function tests__author_name_arg_plus_tax_query__is_coauthor() {
106
+ return; // TODO: re-enable; fails currently because our posts_join_filter doesn't add an exclusive JOIN on relationships + taxonomy to match the query mods we make. We'd need aliased JOINs on relationships + taxonomy on top of the JOIN that the tax query already adds.
107
+
108
+ $author1_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
109
+ $author1 = get_userdata( $author1_id );
110
+ $author2_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'superman' ) );
111
+ $author2 = get_userdata( $author2_id );
112
+
113
+ $post_id = $this->factory->post->create( array(
114
+ 'post_author' => $author1_id,
115
+ 'post_status' => 'publish',
116
+ 'post_type' => 'post',
117
+ ) );
118
+ $this->_cap->add_coauthors( $post_id, array( $author1->user_login, $author2->user_login ) );
119
+ wp_set_post_terms( $post_id, 'test', 'post_tag' );
120
+
121
+ $query = new WP_Query( array(
122
+ 'author_name' => $author2->user_login,
123
+ 'tag' => 'test',
124
+ ) );
125
+
126
+ $this->assertEquals( 1, count( $query->posts ) );
127
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
128
+ }
129
+ }
tests/test-manage-coauthors.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_Manage_CoAuthors extends CoAuthorsPlus_TestCase {
4
+
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
+
11
+ $post = array(
12
+ 'post_author' => $this->author1,
13
+ 'post_status' => 'publish',
14
+ 'post_content' => rand_str(),
15
+ 'post_title' => rand_str(),
16
+ 'post_type' => 'post',
17
+ );
18
+
19
+ $this->author1_post1 = wp_insert_post( $post );
20
+
21
+ $post = array(
22
+ 'post_author' => $this->author1,
23
+ 'post_status' => 'publish',
24
+ 'post_content' => rand_str(),
25
+ 'post_title' => rand_str(),
26
+ 'post_type' => 'post',
27
+ );
28
+
29
+ $this->author1_post2 = wp_insert_post( $post );
30
+
31
+ $page = array(
32
+ 'post_author' => $this->author1,
33
+ 'post_status' => 'publish',
34
+ 'post_content' => rand_str(),
35
+ 'post_title' => rand_str(),
36
+ 'post_type' => 'page',
37
+ );
38
+
39
+ $this->author1_page1 = wp_insert_post( $page );
40
+
41
+ $page = array(
42
+ 'post_author' => $this->author1,
43
+ 'post_status' => 'publish',
44
+ 'post_content' => rand_str(),
45
+ 'post_title' => rand_str(),
46
+ 'post_type' => 'page',
47
+ );
48
+
49
+ $this->author1_page2 = wp_insert_post( $page );
50
+ }
51
+
52
+ public function tearDown() {
53
+ parent::tearDown();
54
+ }
55
+
56
+ /**
57
+ * Test assigning a Co-Author to a post
58
+ */
59
+ public function test_add_coauthor_to_post() {
60
+ global $coauthors_plus;
61
+
62
+ $coauthors = get_coauthors( $this->author1_post1 );
63
+ $this->assertEquals( 1, count( $coauthors ) );
64
+
65
+ // append = true, should preserve order
66
+ $editor1 = get_user_by( 'id', $this->editor1 );
67
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), true );
68
+ $coauthors = get_coauthors( $this->author1_post1 );
69
+ $this->assertEquals( array( $this->author1, $this->editor1 ), wp_list_pluck( $coauthors, 'ID' ) );
70
+
71
+ // append = false, overrides existing authors
72
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), false );
73
+ $coauthors = get_coauthors( $this->author1_post1 );
74
+ $this->assertEquals( array( $this->editor1 ), wp_list_pluck( $coauthors, 'ID' ) );
75
+
76
+ }
77
+
78
+ /**
79
+ * When a co-author is assigned to a post, the post author value
80
+ * should be set appropriately
81
+ *
82
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/140
83
+ */
84
+ public function test_add_coauthor_updates_post_author() {
85
+ global $coauthors_plus;
86
+
87
+ // append = true, preserves existing post_author
88
+ $editor1 = get_user_by( 'id', $this->editor1 );
89
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), true );
90
+ $this->assertEquals( $this->author1, get_post( $this->author1_post1 )->post_author );
91
+
92
+ // append = false, overrides existing post_author
93
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), false );
94
+ $this->assertEquals( $this->editor1, get_post( $this->author1_post1 )->post_author );
95
+
96
+ }
97
+
98
+ /**
99
+ * Post published count should default to 'post', but be filterable
100
+ *
101
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/170
102
+ */
103
+ public function test_post_publish_count_for_coauthor() {
104
+ global $coauthors_plus;
105
+
106
+ $editor1 = get_user_by( 'id', $this->editor1 );
107
+
108
+ /**
109
+ * Two published posts
110
+ */
111
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ) );
112
+ $coauthors_plus->add_coauthors( $this->author1_post2, array( $editor1->user_login ) );
113
+ $this->assertEquals( 2, count_user_posts( $editor1->ID ) );
114
+
115
+ /**
116
+ * One published page too, but no filter
117
+ */
118
+ $coauthors_plus->add_coauthors( $this->author1_page1, array( $editor1->user_login ) );
119
+ $this->assertEquals( 2, count_user_posts( $editor1->ID ) );
120
+
121
+ // Publish count to include posts and pages
122
+ $filter = function() {
123
+ return array( 'post', 'page' );
124
+ };
125
+ add_filter( 'coauthors_count_published_post_types', $filter );
126
+
127
+ /**
128
+ * Two published posts and pages
129
+ */
130
+ $coauthors_plus->add_coauthors( $this->author1_page2, array( $editor1->user_login ) );
131
+ $this->assertEquals( 4, count_user_posts( $editor1->ID ) );
132
+
133
+ // Publish count is just pages
134
+ remove_filter( 'coauthors_count_published_post_types', $filter );
135
+ $filter = function() {
136
+ return array( 'page' );
137
+ };
138
+ add_filter( 'coauthors_count_published_post_types', $filter );
139
+
140
+ /**
141
+ * Just one published page now for the editor
142
+ */
143
+ $author1 = get_user_by( 'id', $this->author1 );
144
+ $coauthors_plus->add_coauthors( $this->author1_page2, array( $author1->user_login ) );
145
+ $this->assertEquals( 1, count_user_posts( $editor1->ID ) );
146
+
147
+ }
148
+ }