Co-Authors Plus - Version 3.4

Version Description

  • New filter get_coauthors for modifying coauthor data returned in get_coauthors()
  • New filter coauthors_guest_authors_exported_extra_data to allow guest author to export data as regular author
  • New filter get_avatar_url() to show avatar in JS selection
  • New parameter in coauthors_wp_list_authors() to only query authors with posts
  • Add internationalization support to title and name in author archives
  • Add safelist to skip irrelevant capabilities during permission checks
  • Add helper function get_guest_author_post_count()
  • Add parameter for outputting HTML classes in coauthors_get_avatar() template tag
  • Add --append_coauthors flag to synopsis of CLI assign-coauthors
  • Adjust CLI command create-guest-authors-from-csv to import website, avatar and description
  • Post type of "any" can be used in filters
  • Remove unnecessary is_array() check
  • Remove unnecessary action_pre_user_query()
  • Use correct args in search_authors()
  • Have filter_author_archive_title() run on author archives only
  • Improve tests coverage
  • Change posts_selection to action from filter
  • Fix number of args expected for get_the_archive_title callback
  • Fix spelling, update FAQ for disabling guest authors and credits in readme
  • Output coauthors_links_single() template tag correctly when guest author has no website
  • Number by "Mine" link shows correct listing of posts
  • Linked guest authors show accurate post counts
  • Can no longer add co-author more than once
  • No more overwriting posts with current user in add_coauthors()
  • Accurate post count for user when using different login
  • No more double post count for users with linked accounts
  • Fix SQL error
  • Fix "Mine" link href for Pages
  • Can delete users when guest authors functionality disabled
  • Fix incompatibility issue with Yoast of missing posts in author pages
  • Resolve undefined index warnings on author archives
  • Resolve warnings when current user has no term assigned
Download this release

Release Info

Developer automattic
Plugin Icon wp plugin Co-Authors Plus
Version 3.4
Comparing to
See all releases

Code changes from version 3.3.1 to 3.4

Makefile ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ .PHONY: lint test
2
+
3
+ test: lint phpunit
4
+
5
+ lint:
6
+ find . -name \*.php -not -path "./vendor/*" -print0 | xargs -0 -n 1 -P 4 php -d display_errors=stderr -l > /dev/null
7
+
8
+ phpunit:
9
+ phpunit
README.md ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Co-Authors Plus
2
+
3
+ * Contributors: batmoo, danielbachhuber, automattic
4
+ * Tags: authors, users, multiple authors, co-authors, multi-author, publishing
5
+ * Tested up to: 5.1.1
6
+ * Requires at least: 4.1
7
+ * Stable tag: 3.4
8
+
9
+ Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box
10
+
11
+ ## Description
12
+
13
+ Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box. Co-authored posts appear on a co-author's archive page and in their feed. Co-authors may edit the posts they are associated with, and co-authors who are contributors may only edit posts if they have not been published (as is core behaviour).
14
+
15
+ Add writers as bylines without creating WordPress user accounts. Simply [create a guest author profile](http://vip.wordpress.com/documentation/add-guest-bylines-to-your-content-with-co-authors-plus/) for the writer and assign the byline as you normally would.
16
+
17
+ On the frontend, use the [Co-Authors Plus template tags](http://vip.wordpress.com/documentation/incorporate-co-authors-plus-template-tags-into-your-theme/) to list co-authors anywhere you'd normally list the author.
18
+
19
+ This plugin is an almost complete rewrite of the [Co-Authors](https://wordpress.org/plugins/co-authors/) plugin originally developed by Weston Ruter (2007). The original plugin was inspired by the '[Multiple Authors](https://txfx.net/2005/08/16/new-plugin-multiple-authors/)' plugin by Mark Jaquith (2005).
20
+
21
+ ## Frequently Asked Questions
22
+
23
+ * How do I add Co-Authors Plus support to my theme?
24
+
25
+ If you've just installed Co-Authors Plus, you might notice that the bylines are being added in the backend but aren't appearing on the frontend. You'll need to [add the template tags to your theme](http://vip.wordpress.com/documentation/incorporate-co-authors-plus-template-tags-into-your-theme/) before the bylines will appear.
26
+
27
+ * What happens to posts and pages when I delete a user assigned to a post or page as a coauthor?
28
+
29
+ When a user is deleted from WordPress, they will be removed from all posts for which they are co-authors. If you chose to reassign their posts to another user, that user will be set as the coauthor instead.
30
+
31
+ * Can I use Co-Authors Plus with WordPress multisite?
32
+
33
+ Yep! Co-Authors Plus can be activated on a site-by-site basis, or network-activated. If you create guest authors, however, those guest authors will exist on a site-by-site basis.
34
+
35
+ * Who needs permission to do what?
36
+
37
+ To assign co-authors to posts, a WordPress user will need the `edit_others_posts` capability. This is typically granted to the Editor role, but can be altered with the `coauthors_plus_edit_authors` filter.
38
+
39
+ To create new guest author profiles, a WordPress will need the `list_users` capability. This is typically granted to the Administrator role, but can be altered with the `coauthors_guest_author_manage_cap` filter.
40
+
41
+ * Can I easily create a list of all co-authors?
42
+
43
+ Yep! There's a template tag called `coauthors_wp_list_authors()` that accepts many of the same arguments as `wp_list_authors()`. Look in template-tags.php for more details.
44
+
45
+ * I have a large database, will this make it slow?
46
+
47
+ If the site has a large database, you may run into issues with heavier than usual queries. You can work around this by disabling compat mode and force it to use simpler, tax-only queries by adding the following to your theme:
48
+
49
+ ```
50
+ // Use simple tax queries for CAP to improve performance
51
+ add_filter( 'coauthors_plus_should_query_post_author', '__return_false' );
52
+ ```
53
+
54
+ Note that this requires the site(s) to have proper terms set up for all users. You can do this with the following wp-cli command:
55
+
56
+ ```
57
+ # This is pretty long-running and can be expensive; be careful!
58
+ $ wp --url=example.com co-authors-plus create-terms-for-posts
59
+ ```
60
+
61
+ ## Changelog ##
62
+
63
+ **3.4**
64
+ * New filter `get_coauthors` for modifying coauthor data returned in `get_coauthors()` #646
65
+ * New filter `coauthors_guest_authors_exported_extra_data` to allow guest author to export data as regular author #528
66
+ * New filter `get_avatar_url()` to show avatar in JS selection #621
67
+ * New parameter in `coauthors_wp_list_authors()` to only query authors with posts #496
68
+ * Add internationalization support to title and name in author archives #516
69
+ * Add safelist to skip irrelevant capabilities during permission checks #543
70
+ * Add helper function `get_guest_author_post_count()` #605
71
+ * Add parameter for outputting HTML classes in `coauthors_get_avatar()` template tag #610
72
+ * Add `--append_coauthors` flag to synopsis of CLI `assign-coauthors` #600
73
+ * Adjust CLI command `create-guest-authors-from-csv` to import website, avatar and description (#603 and #619)
74
+ * Post type of "any" can be used in filters #617
75
+ * Remove unnecessary `is_array()` check #471
76
+ * Remove unnecessary `action_pre_user_query()` #531
77
+ * Use correct args in `search_authors()` #519
78
+ * Have `filter_author_archive_title()` run on author archives only #535
79
+ * Improve tests coverage (#529, #540, #546, #576 and #569)
80
+ * Change `posts_selection` to action from filter #563
81
+ * Fix number of args expected for `get_the_archive_title` callback #657
82
+ * Fix spelling, update FAQ for disabling guest authors and credits in readme (#656, #523 and #501)
83
+ * Output `coauthors_links_single()` template tag correctly when guest author has no website #504
84
+ * Number by "Mine" link shows correct listing of posts #663
85
+ * Linked guest authors show accurate post counts #674
86
+ * Can no longer add co-author more than once #532
87
+ * No more overwriting posts with current user in `add_coauthors()` #545
88
+ * Accurate post count for user when using different login #558
89
+ * No more double post count for users with linked accounts #567
90
+ * Fix SQL error (#593 and #628)
91
+ * Fix "Mine" link href for Pages #547
92
+ * Can delete users when guest authors functionality disabled #602
93
+ * Fix incompatibility issue with Yoast of missing posts in author pages #624
94
+ * Resolve undefined index warnings on author archives #521
95
+ * Resolve warnings when current user has no term assigned #517
96
+
97
+ Props: [TheCrowned](https://github.com/TheCrowned), [shantanu2704](https://github.com/shantanu2704), [WPprodigy](https://github.com/WPprodigy), [blunce24](https://github.com/blunce24), [rebeccahum](https://github.com/rebeccahum), [andrewfleming](https://github.com/andrewfleming), [justnorris](https://github.com/justnorris), [sboisvert](https://github.com/sboisvert), [jasonbahl](https://github.com/jasonbahl), [mariovalney](https://github.com/mariovalney), [RoyTheRoyalBoy](https://github.com/RoyTheRoyalBoy), [jacobarriola](https://github.com/jacobarriola), [smistephen](https://github.com/smistephen), [manzoorwanijk](https://github.com/manzoorwanijk), [kodemonster](https://github.com/kodemonster), [westonruter](https://github.com/westonruter), [binodkalathil](https://github.com/binodkalathil), [scofennell](https://github.com/scofennell), [hyperionjrw](https://github.com/hyperionjrw), [pdemarte](https://github.com/pdemarte), [mostafaabd](https://github.com/mostafaabd), [paulschreiber](https://github.com/paulschreiber)
98
+
99
+ **3.3.1 ("Gutentag")**
100
+ * 5.0 Compat: Hide core author inputs when using the Block Editor to limit confusion (h/t jonathanstegall).
101
+
102
+ **3.3.0 ("Rebecca")**
103
+ * Fix private post viewing on front-end #386
104
+ * Reduce amount of sleep #400
105
+ * Author search UX issues #407
106
+ * Remove associated guest user when mapped user id deleted. #414
107
+ * Removed double left join on posts_join_filter #419
108
+ * Fixed WP CLI create-terms-for-posts if no co-authors found #420
109
+ * Pages archive now displays co-authors and quick edit works #422
110
+ * Terminology updated throughout #423
111
+ * Replace hardcoded 'author' with $this->$coauthor_taxonomy #426
112
+ * Move parenthesis to fix esc_html and sprintf #430
113
+ * Added progress to create-guest-authors so users have an idea of how long it will take #431
114
+ * Deleting guest authors is less confusing #432
115
+ * Guest author's featured image is avatar now #433
116
+ * Removed extra image sizing #434
117
+ * Remove duplicated byline #435
118
+ * coauthors_wp_list_authors() has option to list only guest authors now #436
119
+ * remove duplicates from linked accounts on coauthors_wp_list_authors() #437
120
+ * Accurate Guest Author post count on linked accounts #438
121
+ * New README.md #439
122
+ * Filter author archive #441
123
+ * Fix coauthors_links_single() #444
124
+ * Added guest author hooks for create/delete #446
125
+ * Fixes logic for DOING_AUTOSAVE check #450
126
+ * user_login spaces problem when using add_coauthors #453
127
+ * Adding details of filter for slow performance #456
128
+ * Remove redundant test for 404 on Author Archive #457
129
+ * Guest Author Counts are more accurate #461
130
+ * Set $coauthors_loading #468
131
+ * Fix the issue where guest authors with non-ASCII characters can't be used as co-authors #473
132
+ * Fix the issue where incompatibility when `coauthors_auto_apply_template_tags` set to true #474
133
+ * Unit tests/Fix warnings for template tags #475
134
+ * Review and improve test coverage #476
135
+ * Update class-wp-cli.php #480
136
+ * Update .travis.yml file for PHPUnit tests #482
137
+ * Changes to resolve issue #332 about missing coauthor meta #484
138
+
139
+ Props to the many people who helped make this release possible: [catchmyfame](https://github.com/catchmyfame), [danielbachhuber](https://github.com/danielbachhuber), [david-binda](https://github.com/david-binda), [douglas-johnson](https://github.com/douglas-johnson), [castlehouse](https://github.com/castlehouse), [frankar](https://github.com/frankar), [haleeben](https://github.com/haleeben), [jjeaton](https://github.com/jjeaton), [johnbillion](https://github.com/johnbillion), [kevinlisota](https://github.com/kevinlisota), [mattoperry](https://github.com/mattoperry), [mdbitz](https://github.com/mdbitz), [mdchiragpatel](https://github.com/mdchiragpatel), [megfh](https://github.com/megfh), [mjangda](https://github.com/mjangda), [mslinnea](https://github.com/mslinnea), [natebot](https://github.com/natebot), [nickdaugherty](https://github.com/nickdaugherty), [nilzari](https://github.com/nilzari), [philipjohn](https://github.com/philipjohn), [pkevan](https://github.com/pkevan), [rebeccahum](https://github.com/rebeccahum), [ryanmarkel](https://github.com/ryanmarkel), [sanketio](https://github.com/sanketio), [sboisvert](https://github.com/sboisvert), [Spongsta](https://github.com/Spongsta), [srguglielmo](https://github.com/srguglielmo), [timburden](https://github.com/timburden), [trepmal](https://github.com/trepmal), [TylerDurdon](https://github.com/TylerDurdon)
140
+
141
+ **3.2.2**
142
+ * Fix broken author ordering in 4.7+ (props mslinnea)
143
+ * Fix no moderation e-mail bug (props RobjS)
144
+ * Cached functions in CLI commands (props jasonbahl)
145
+ * Fix missing echos (props trepmal)
146
+ * Add `coauthors_guest_author_query_args` filter (props trepmal)
147
+
148
+ **3.2.1 (May 16, 2016)**
149
+ * Hotfix for broken Guest Author bio metabox (props JS Morisset)
150
+
151
+ **3.2 (May 12, 2016)**
152
+ * Various minor bug and security fixes
153
+
154
+ **3.1.2 (Aug. 31, 2015)**
155
+ * Minor bug fixes and coding standards changes.
156
+ * The author's display name is now filtered through `the_author` in `coauthors_posts_links_single()`
157
+ * New Russian and Ukrainian translations, courtesy of [Jurko Chervony](http://skinik.name/).
158
+
159
+ **3.1.1 (Mar. 20, 2014)**
160
+ * Bug fix: Co-authors selection UI should appear when creating a new post too.
161
+
162
+ **3.1 (Mar. 17, 2014)**
163
+ * Manage co-authors from Quick Edit. Props [mpatek](https://github.com/mpatek).
164
+ * Updated Spanish translation, courtesy of [sergiomajluf](https://github.com/sergiomajluf).
165
+ * Now matches core behavior when displaying author archive on multisite: user of the blog, or previously published author on the blog.
166
+ * Breaking change: "Create Profile" link is no longer shown by default on the Manage Users screen. Instead, it can be enabled with the `coauthors_show_create_profile_user_link` filter.
167
+ * Guest authors work properly with Jetpack Open Graph tags. Props [hibernation](https://github.com/hibernation).
168
+ * Guest author profile editor now supports a few different fields. Props [alpha1](https://github.com/alpha1).
169
+ * New `coauthors_count_published_post_types` filter for specifying the post type(s) used when calculating the user's number of published posts.
170
+ * Bug fix: Ensure `post_author` is set to one of the co-authors assigned to a post.
171
+ * Bug fix: Filter author feed link for guest authors on the author page. Props [hibernation](https://github.com/hibernation).
172
+ * Packages a composer.json file for those using Composer.
173
+ * Beginnings of unit test coverage for core features. Increased minimum required WordPress version to 3.7 because WordPress.org unit testing framework doesn't work reliabilty below that.
174
+
175
+ **3.0.7 (Jan. 27, 2014)**
176
+ * Better support for installing Co-Authors Plus as a symlinked directory. [Follow these instructions](http://kaspars.net/blog/wordpress/plugins-via-symlinks) to filter `plugins_url`.
177
+ * Links to authors' posts pages to comply to hCard microformat, which Google depends on.
178
+ * New `coauthors_emails()` template tag to list email addresses of the co-authors. Props [benlk](https://github.com/benlk).
179
+ * Bug fix: Remove extraneous space between last two co-authors output. Props [johnciacia](https://github.com/johnciacia).
180
+ * Updated French translation, courtesy of Jojaba (via email).
181
+
182
+ **3.0.6 (Dec. 9, 2013)**
183
+ * New Swedish translation, courtesy of [alundstroem](https://github.com/alundstroem)
184
+ * Updated German translation, courtesy of [krafit](https://github.com/krafit).
185
+ * New Dutch translation, courtesy of [kardotim](https://github.com/kardotim)
186
+ * New filter for specifying the default author assigned to a post. Props [tannerm](https://github.com/tannerm)
187
+ * Bug fix: When filtering a user's published post count, use the value of their guest author profile if one is mapped.
188
+ * Added support for checkboxes in Guest Author profiles
189
+ * Fix Strict warnings from CPT's that don't define all capabilities
190
+ * New swap-coauthors CLI command for replacing one co-author with another
191
+
192
+ **3.0.5 (Feb. 18, 2013)**
193
+ * New filter `coauthors_search_authors_get_terms_args` allows you to increase the number of matches returned with AJAX co-author selection
194
+ * Bug fix: If there isn't an author term yet for a co-author, avoid an erronous join that caused duplicate posts to appear.
195
+
196
+ **3.0.4 (Jan. 6, 2013)** =
197
+ * Support for automatically adding co-authors to your feeds. Props [cfg](https://github.com/cfg).
198
+ * Bug fix: No Co-Authors Plus on attachments. For now.
199
+ * Bug fix: Better support for co-authors with non-standard user_nicenames. Props [STRML](https://github.com/STRML).
200
+
201
+ **3.0.3 (Dec. 3, 2012)**
202
+ * Bug fix: The default order for the 'author' taxonomy should be `term_order`, in order for the author positions to stick. Props [lgedeon](https://github.com/lgedeon)
203
+
204
+ **3.0.2 (Nov. 23, 2012)**
205
+ * Bug fix: Fall back to non-pretty permalinks when the author permastruct is empty, so that `coauthors_posts_links()` doesn't link to the homepage
206
+
207
+ **3.0.1 (Nov. 21, 2012)**
208
+ * Add your own custom columns to the guest authors table using filters. Props [cfg](https://github.com/cfg)
209
+ * A new wp-cli subcommand for renaming co-authors and another for removing author terms mistakenly assigned to revisions
210
+ * Bug fix: Using a featured image for a guest author avatar didn't work. Now it does.
211
+ * Bug fix: Don't assign author terms to revisions to avoid unnecessary database bloat
212
+ * Bug fix: Make the `coauthors_wp_list_authors()` template tag work again
213
+ * Bug fix: Improve capability filtering by properly handling super admin access and situations where `user_id = 0`
214
+ * Minor UI enhancements for guest authors
215
+
216
+ **3.0 (Nov. 12, 2012)**
217
+ * Create guest author profiles for bylines you'd like to assign without creating WordPress user accounts. Guest authors can have all of the same fields as normal users including display name, biography, and avatars.
218
+ * Support for non-Latin characters in usernames and guest author names
219
+ * wp-cli subcommands for creating, assigning, and reassigning co-authors
220
+ * For themes using core template tags like `the_author()` or `the_author_posts_link()`, you enable Co-Authors Plus support with a simple filter
221
+ * New author terms are now prefixed with `cap-` to avoid collisions with global scope
222
+ * Bug fix: Apply query filters to only `post_types` registered with the taxonomy. Props [Tom Ransom](https://github.com/1bigidea)
223
+ * Filter `coauthors_posts_link_single()` with `coauthors_posts_link`. Also adds `rel="author"`. Props [Amit Sannad](https://github.com/asannad) and [Gabriel Koen](https://github.com/mintindeed)
224
+ * Filter for the context and priorities of the Co-Authors meta boxes. Props [Tomáš Kapler](https://github.com/tkapler)
225
+ * Renamed the post meta box for selecting authors so it applies to many post types. Props [John Blackbourn](https://github.com/johnbillion)
226
+
227
+ **2.6.4 (May 7, 2012)**
228
+ * Bug fix: Properly filter the user query so users can AJAX search against the display name field again
229
+ * If https is used for the admin, also use the secure Gravatar URL. Props [rmcfrazier](https://github.com/rmcfrazier)
230
+
231
+ **2.6.3 (Apr. 30, 2012)**
232
+ * AJAX user search is back to searching against user login, display name, email address and user ID. The method introduced in v2.6.2 didn't scale well
233
+ * French translation courtesy of Sylvain Bérubé
234
+ * Spanish translation courtesy of Alejandro Arcos
235
+ * Bug fix: Resolved incorrect caps check against user editing an already published post. [See forum thread](http://wordpress.org/support/topic/multiple-authors-cant-edit-pages?replies=17#post-2741243)
236
+
237
+ **2.6.2 (Mar. 6, 2012)**
238
+ * AJAX user search matches against first name, last name, and nickname fields too, in addition to display name, user login, and email address
239
+ * Comment moderation and approved notifications are properly sent to all co-authors with the correct caps
240
+ * Filter required capability for user to be returned in an AJAX search with `coauthors_edit_author_cap`
241
+ * Filter out administrators and other non-authors from AJAX search with `coauthors_edit_ignored_authors`
242
+ * Automatically adds co-authors to Edit Flow's story budget and calendar views
243
+ * Bug fix: Don't set post_author value to current user when quick editing a post. This doesn't appear in the UI anywhere, but adds the post to the current user's list of posts
244
+ * Bug fix: Properly cc other co-authors on new comment email notifications
245
+ * Bug fix: If a user has already been added as an author to a post, don't show them in the AJAX search again
246
+ * Bug fix: Allow output constants to be defined in a theme's functions.php file and include filters you can use instead
247
+
248
+ **2.6.1 (Dec. 30, 2011)**
249
+ * Fix mangled usernames because of sanitize_key http://wordpress.org/support/topic/plugin-co-authors-plus-26-not-working-with-wp-33
250
+
251
+ **2.6 (Dec. 22, 2011)**
252
+ * Sortable authors: Drag and drop the order of the authors as you'd like them to appear ([props kingkool68](http://profiles.wordpress.org/users/kingkool68/))
253
+ * Search for authors by display name (instead of nicename which was essentially the same as user_login)
254
+ * Option to remove the first author when there are two or more so it's less confusing
255
+ * Bumped requirements to WordPress 3.1
256
+ * Bug fix: Update the published post count for each user more reliably
257
+
258
+ **2.5.3 (Aug. 14, 2011)**
259
+ * Bug fix: Removed extra comma when only two authors were listed. If you used the `COAUTHORS_DEFAULT_BETWEEN_LAST` constant, double-check what you have
260
+
261
+ **2.5.2 (Apr. 23, 2011)**
262
+ * Bug: Couldn't query terms and authors at the same time (props nbaxley)
263
+ * Bug: Authors with empty fields (e.g. first name) were displaying blank in some cases
264
+ * Bug: authors with spaces in usernames not getting saved (props MLmsw, Ruben S. and others!)
265
+ * Bug: revisions getting wrong user attached (props cliquenoir!)
266
+
267
+ **2.5.1 (Mar. 26, 2011)**
268
+ * Fix with author post count (throwing errors)
269
+
270
+ **2.5 (Mar. 26, 2011)**
271
+ * Custom Post Type Support
272
+ * Compatibility with WP 3.0 and 3.1
273
+ * Gravatars
274
+ * Lots and lots and lots of bug fixes
275
+ * Thanks to everyone who submitted bugs, fixes, and suggestions! And for your patience!
276
+
277
+ **2.1.1 (Oct. 16, 2009)**
278
+ * Fix for co-authors not being added if their username is different from display name
279
+ * Fixes to readme.txt (fixes for textual and punctuation errors, language clarification, minor formatting changes) courtesy of [Waldo Jaquith](http://www.vqronline.org)
280
+
281
+ **2.1 (Oct. 11, 2009)**
282
+ * Fixed issues related to localization. Thanks to Jan Zombik <zombik@students.uni-mainz.de> for the fixes.
283
+ * Added `set_time_limit` to update function to get around timeout issues when upgrading plugin
284
+
285
+ **2.0 (Oct. 11, 2009)**
286
+ * Plugin mostly rewritten to make use of taxonomy instead of `post_meta`
287
+ * Can now see all authors of a post under the author column from Edit Posts page
288
+ * All authors of a post are now notified on a new comment
289
+ * Various javascript enhancements
290
+ * New option to allow subscribers to be added as authors
291
+ * All Authors can edit they posts of which they are co-authors
292
+ * FIX: Issues with `wp_coauthors_list` function
293
+ * FIX: Issues with coauthored posts not showing up on author archives
294
+
295
+ **1.2.0 (Jun. 16, 2012)**
296
+ * FIX: Added compatibility for WordPress 2.8
297
+ * FIX: Added new template tags (`get_the_coauthor_meta` & `the_coauthor_meta`) to fix issues related to displaying author info on author archive pages. See [Other Notes](http://wordpress.org/extend/plugins/co-authors-plus/other_notes/) for details.
298
+ * FIX: Plugin should now work for plugins not using the `wp_` DB prefix
299
+ * FIX: Coauthors should no longer be alphabetically reordered when the post is updated
300
+ * FIX: Plugin now used WordPress native AJAX calls to tighten security
301
+ * DOCS: Added details about the new template tags
302
+
303
+ **1.1.5 (Apr. 26, 2009)**
304
+ * FIX: Not searching Updated SQL query for autosuggest to search through first name, last name, and nickname
305
+ * FIX: When editing an author, and clicking on a suggested author, the original author was not be removed
306
+ * DOCS: Added code comments to javascript; more still to be added
307
+ * DOCS: Updated readme information
308
+
309
+ **1.1.4 (Apr. 25, 2009)**
310
+ * Disabled "New Author" output in suggest box, for now
311
+ * Hopefully fixed SVN issue (if you're having trouble with the plugin, please delete the plugin and reinstall)
312
+
313
+ **1.1.3 (Apr. 23, 2009)**
314
+ * Add blur event to disable input box
315
+ * Limit only one edit at a time.
316
+ * Checked basic cross-browser compatibility (Firefox 3 OS X, Safari 3 OS X, IE7 Vista).
317
+ * Add suggest javascript plugin to Edit Page.
318
+
319
+ **1.1.2 (Apr. 19, 2009)**
320
+ * Disabled form submit when enter pressed.
321
+
322
+ **1.1.1 (Apr. 15, 2009)**
323
+ * Changed SQL query to return only contributor-level and above users.
324
+
325
+ **1.1.0 (Apr. 14, 2009)**
326
+ * Initial beta release.
327
+
328
+ ## Installation
329
+
330
+ 1. IMPORTANT: Please disable the original Co-Authors plugin (if you are using it) before installing Co-Authors Plus
331
+ 2. Extract the coauthors-plus.zip file and upload its contents to the `/wp-content/plugins/` directory. Alternately, you can install directly from the Plugin directory within your WordPress Install.
332
+ 3. Activate the plugin through the "Plugins" menu in WordPress.
333
+ 4. Place the appropriate [co-authors template tags](http://vip.wordpress.com/documentation/incorporate-co-authors-plus-template-tags-into-your-theme/) in your template.
334
+ 5. Add co-authors to your posts and pages.
335
+
336
+ ## Screenshots
337
+
338
+ 1. Multiple authors can be added to a Post, Page, or Custom Post Type using an auto-complete interface.
339
+ 2. The order of your co-authors can be changed by drag and drop.
340
+ 3. Guest authors allow you to assign bylines without creating WordPress user accounts. You can also override existing WordPress account meta by mapping a guest author to a WordPress user.
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.3.1
7
  Author: Mohammad Jangda, Daniel Bachhuber, Automattic
8
  Copyright: 2008-2015 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
@@ -32,7 +32,7 @@ Co-author - in the context of a single post, a guest author or user assigned to
32
  Author - user with the role of author
33
  */
34
 
35
- define( 'COAUTHORS_PLUS_VERSION', '3.3.1' );
36
 
37
  require_once( dirname( __FILE__ ) . '/template-tags.php' );
38
  require_once( dirname( __FILE__ ) . '/deprecated.php' );
@@ -64,6 +64,8 @@ class CoAuthors_Plus {
64
 
65
  var $having_terms = '';
66
 
 
 
67
  /**
68
  * __construct()
69
  */
@@ -108,7 +110,7 @@ class CoAuthors_Plus {
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
 
114
  // Support for Edit Flow's calendar and story budget
@@ -130,7 +132,10 @@ class CoAuthors_Plus {
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
  /**
@@ -219,7 +224,6 @@ class CoAuthors_Plus {
219
 
220
  // Apply some targeted filters
221
  add_action( 'load-edit.php', array( $this, 'load_edit' ) );
222
-
223
  }
224
 
225
  /**
@@ -378,14 +382,16 @@ class CoAuthors_Plus {
378
  <?php
379
  foreach ( $coauthors as $coauthor ) :
380
  $count++;
 
381
  ?>
382
  <li>
383
- <?php echo get_avatar( $coauthor->user_email, $this->gravatar_size ); ?>
384
  <span id="<?php echo esc_attr( 'coauthor-readonly-' . $count ); ?>" class="coauthor-tag">
385
  <input type="text" name="coauthorsinput[]" readonly="readonly" value="<?php echo esc_attr( $coauthor->display_name ); ?>" />
386
  <input type="text" name="coauthors[]" value="<?php echo esc_attr( $coauthor->user_login ); ?>" />
387
  <input type="text" name="coauthorsemails[]" value="<?php echo esc_attr( $coauthor->user_email ); ?>" />
388
  <input type="text" name="coauthorsnicenames[]" value="<?php echo esc_attr( $coauthor->user_nicename ); ?>" />
 
389
  </span>
390
  </li>
391
  <?php
@@ -619,8 +625,12 @@ class CoAuthors_Plus {
619
  global $wpdb;
620
 
621
  if ( $query->is_author() ) {
 
 
 
 
622
 
623
- if ( ! empty( $query->query_vars['post_type'] ) && ! is_object_in_taxonomy( $query->query_vars['post_type'], $this->coauthor_taxonomy ) ) {
624
  return $join;
625
  }
626
 
@@ -648,15 +658,24 @@ class CoAuthors_Plus {
648
  return $join;
649
  }
650
 
651
- /**
652
- * Modify the author query posts SQL to include posts co-authored
653
- */
 
 
 
 
 
654
  function posts_where_filter( $where, $query ) {
655
  global $wpdb;
656
 
657
  if ( $query->is_author() ) {
 
 
 
 
658
 
659
- if ( ! empty( $query->query_vars['post_type'] ) && ! is_object_in_taxonomy( $query->query_vars['post_type'], $this->coauthor_taxonomy ) ) {
660
  return $where;
661
  }
662
 
@@ -703,14 +722,22 @@ class CoAuthors_Plus {
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
@@ -725,10 +752,12 @@ class CoAuthors_Plus {
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' );
@@ -745,8 +774,11 @@ class CoAuthors_Plus {
745
  global $wpdb;
746
 
747
  if ( $query->is_author() ) {
748
-
749
- if ( ! empty( $query->query_vars['post_type'] ) && ! is_object_in_taxonomy( $query->query_vars['post_type'], $this->coauthor_taxonomy ) ) {
 
 
 
750
  return $groupby;
751
  }
752
 
@@ -864,8 +896,13 @@ class CoAuthors_Plus {
864
  }
865
 
866
  // A co-author is always required
 
867
  if ( empty( $coauthors ) ) {
868
- $coauthors = array( $current_user->user_login );
 
 
 
 
869
  }
870
 
871
  // Set the co-authors
@@ -936,15 +973,17 @@ class CoAuthors_Plus {
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
 
@@ -990,24 +1029,25 @@ class CoAuthors_Plus {
990
  }
991
 
992
  /**
993
- * Filter the count_users_posts() core function to include our correct count
 
 
 
 
994
  */
995
  function filter_count_user_posts( $count, $user_id ) {
996
  $user = get_userdata( $user_id );
997
-
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
 
1013
  return $count;
@@ -1067,8 +1107,11 @@ class CoAuthors_Plus {
1067
  * the query_var is changed.
1068
  *
1069
  * Also, we have to do some hacky WP_Query modification for guest authors
 
 
 
1070
  */
1071
- public function fix_author_page() {
1072
 
1073
  if ( ! is_author() ) {
1074
  return;
@@ -1147,7 +1190,8 @@ class CoAuthors_Plus {
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();
@@ -1166,7 +1210,7 @@ class CoAuthors_Plus {
1166
  $args = array(
1167
  'count_total' => false,
1168
  'search' => sprintf( '*%s*', $search ),
1169
- 'search_fields' => array(
1170
  'ID',
1171
  'display_name',
1172
  'user_email',
@@ -1174,9 +1218,7 @@ class CoAuthors_Plus {
1174
  ),
1175
  'fields' => 'all_with_meta',
1176
  );
1177
- add_action( 'pre_user_query', array( $this, 'action_pre_user_query' ) );
1178
  $found_users = get_users( $args );
1179
- remove_action( 'pre_user_query', array( $this, 'action_pre_user_query' ) );
1180
 
1181
  foreach ( $found_users as $found_user ) {
1182
  $term = $this->get_author_term( $found_user );
@@ -1212,7 +1254,7 @@ class CoAuthors_Plus {
1212
  $ignored_authors = apply_filters( 'coauthors_edit_ignored_authors', $ignored_authors );
1213
  foreach ( $found_users as $key => $found_user ) {
1214
  // Make sure the user is contributor and above (or a custom cap)
1215
- if ( in_array( $found_user->user_login, $ignored_authors ) ) {
1216
  unset( $found_users[ $key ] );
1217
  } else if ( 'wpuser' === $found_user->type && false === $found_user->has_cap( apply_filters( 'coauthors_edit_author_cap', 'edit_posts' ) ) ) {
1218
  unset( $found_users[ $key ] );
@@ -1221,17 +1263,6 @@ class CoAuthors_Plus {
1221
  return (array) $found_users;
1222
  }
1223
 
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 );
1231
- }
1232
-
1233
- }
1234
-
1235
  /**
1236
  * Modify get_terms() to LIKE against the term description instead of the term name
1237
  *
@@ -1298,7 +1329,7 @@ class CoAuthors_Plus {
1298
  'author_name' => wp_get_current_user()->user_nicename,
1299
  );
1300
  if ( 'post' != get_post_type() ) {
1301
- $mine_args['post_type'] = get_post_type();
1302
  }
1303
  if ( ! empty( $_REQUEST['author_name'] ) && wp_get_current_user()->user_nicename == $_REQUEST['author_name'] ) {
1304
  $class = ' class="current"';
@@ -1349,6 +1380,32 @@ class CoAuthors_Plus {
1349
  return (bool) in_array( $pagenow, $this->_pages_whitelist );
1350
  }
1351
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1352
  /**
1353
  * Allows guest authors to edit the post they're co-authors of
1354
  */
@@ -1358,11 +1415,16 @@ class CoAuthors_Plus {
1358
  $user_id = isset( $args[1] ) ? $args[1] : 0;
1359
  $post_id = isset( $args[2] ) ? $args[2] : 0;
1360
 
 
 
 
 
1361
  $obj = get_post_type_object( get_post_type( $post_id ) );
1362
  if ( ! $obj || 'revision' == $obj->name ) {
1363
  return $allcaps;
1364
  }
1365
 
 
1366
  $caps_to_modify = array(
1367
  $obj->cap->edit_post,
1368
  'edit_post', // Need to filter this too, unfortunately: http://core.trac.wordpress.org/ticket/22415
@@ -1410,19 +1472,10 @@ class CoAuthors_Plus {
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;
@@ -1617,12 +1670,62 @@ class CoAuthors_Plus {
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
 
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.4
7
  Author: Mohammad Jangda, Daniel Bachhuber, Automattic
8
  Copyright: 2008-2015 Shared and distributed between Mohammad Jangda, Daniel Bachhuber, Weston Ruter
9
 
32
  Author - user with the role of author
33
  */
34
 
35
+ define( 'COAUTHORS_PLUS_VERSION', '3.4' );
36
 
37
  require_once( dirname( __FILE__ ) . '/template-tags.php' );
38
  require_once( dirname( __FILE__ ) . '/deprecated.php' );
64
 
65
  var $having_terms = '';
66
 
67
+ var $to_be_filtered_caps = array();
68
+
69
  /**
70
  * __construct()
71
  */
110
  add_filter( 'wp_get_object_terms', array( $this, 'filter_wp_get_object_terms' ), 10, 4 );
111
 
112
  // Make sure we've correctly set data on guest author pages
113
+ add_action( '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
114
  add_action( 'the_post', array( $this, 'fix_author_page' ) );
115
 
116
  // Support for Edit Flow's calendar and story budget
132
  add_action( 'set_object_terms', array( $this, 'clear_cache_on_terms_set' ), 10, 6 );
133
 
134
  // Filter to correct author on author archive page
135
+ add_filter( 'get_the_archive_title', array( $this, 'filter_author_archive_title'), 10, 1 );
136
+
137
+ // Filter to display author image if exists instead of avatar
138
+ add_filter( 'get_avatar_url', array( $this, 'filter_get_avatar_url' ), 10, 2 );
139
  }
140
 
141
  /**
224
 
225
  // Apply some targeted filters
226
  add_action( 'load-edit.php', array( $this, 'load_edit' ) );
 
227
  }
228
 
229
  /**
382
  <?php
383
  foreach ( $coauthors as $coauthor ) :
384
  $count++;
385
+ $avatar_url = get_avatar_url( $coauthor->ID, array( 'default' => 'gravatar_default' ) );
386
  ?>
387
  <li>
388
+ <?php echo get_avatar( $coauthor->ID, $this->gravatar_size ); ?>
389
  <span id="<?php echo esc_attr( 'coauthor-readonly-' . $count ); ?>" class="coauthor-tag">
390
  <input type="text" name="coauthorsinput[]" readonly="readonly" value="<?php echo esc_attr( $coauthor->display_name ); ?>" />
391
  <input type="text" name="coauthors[]" value="<?php echo esc_attr( $coauthor->user_login ); ?>" />
392
  <input type="text" name="coauthorsemails[]" value="<?php echo esc_attr( $coauthor->user_email ); ?>" />
393
  <input type="text" name="coauthorsnicenames[]" value="<?php echo esc_attr( $coauthor->user_nicename ); ?>" />
394
+ <input type="hidden" name="coauthorsavatars[]" value="<?php echo esc_url( $avatar_url ); ?>" />
395
  </span>
396
  </li>
397
  <?php
625
  global $wpdb;
626
 
627
  if ( $query->is_author() ) {
628
+ $post_type = $query->query_vars['post_type'];
629
+ if ( 'any' === $post_type ) {
630
+ $post_type = get_post_types( array( 'exclude_from_search' => false ) );
631
+ }
632
 
633
+ if ( ! empty( $post_type ) && ! is_object_in_taxonomy( $post_type, $this->coauthor_taxonomy ) ) {
634
  return $join;
635
  }
636
 
658
  return $join;
659
  }
660
 
661
+ /**
662
+ * Modify the author query posts SQL to include posts co-authored
663
+ *
664
+ * @param string $where
665
+ * @param WP_Query $query
666
+ *
667
+ * @return string
668
+ */
669
  function posts_where_filter( $where, $query ) {
670
  global $wpdb;
671
 
672
  if ( $query->is_author() ) {
673
+ $post_type = $query->query_vars['post_type'];
674
+ if ( 'any' === $post_type ) {
675
+ $post_type = get_post_types( array( 'exclude_from_search' => false ) );
676
+ }
677
 
678
+ if ( ! empty( $post_type ) && ! is_object_in_taxonomy( $post_type, $this->coauthor_taxonomy ) ) {
679
  return $where;
680
  }
681
 
722
  }
723
  $terms_implode = rtrim( $terms_implode, ' OR' );
724
 
725
+ // We need to check the query is the main query as a new query object would result in the wrong ID
726
+ $id = is_author() && $query->is_main_query() ? get_queried_object_id() : '\d+';
727
+
728
+ //If we have an ID but it's not a "real" ID that means that this isn't the first time the filter has fired and the object_id has already been replaced by a previous run of this filter. We therefore need to replace the 0
729
+ // This happens when wp_query::get_posts() is run multiple times.
730
+ // If previous condition resulted in this being a string there's no point wasting a db query looking for a user.
731
+ if ( $id !== '\d+' && false === get_user_by( 'id', $id ) ){
732
+ $id = '\d+';
733
+ }
734
 
735
  // When WordPress generates query as 'post_author IN (id)'.
736
  if ( false !== strpos( $where, "{$wpdb->posts}.post_author IN " ) ) {
737
 
738
  $maybe_both_query = $maybe_both ? '$0 OR' : '';
739
 
740
+ $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
741
 
742
  } else {
743
  $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
752
  $current_coauthor = $this->get_coauthor_by( 'user_nicename', wp_get_current_user()->user_nicename );
753
  $current_coauthor_term = $this->get_author_term( $current_coauthor );
754
 
755
+ if ( is_a( $current_coauthor_term, 'WP_Term' ) ) {
756
+ $current_user_query = $wpdb->term_taxonomy . '.taxonomy = \'' . $this->coauthor_taxonomy . '\' AND ' . $wpdb->term_taxonomy . '.term_id = \'' . $current_coauthor_term->term_id . '\'';
757
+ $this->having_terms .= ' ' . $wpdb->term_taxonomy . '.term_id = \'' . $current_coauthor_term->term_id . '\' OR ';
758
 
759
+ $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}
760
+ }
761
  }
762
 
763
  $this->having_terms = rtrim( $this->having_terms, ' OR' );
774
  global $wpdb;
775
 
776
  if ( $query->is_author() ) {
777
+ $post_type = $query->query_vars['post_type'];
778
+ if ( 'any' === $post_type ) {
779
+ $post_type = get_post_types( array( 'exclude_from_search' => false ) );
780
+ }
781
+ if ( ! empty( $post_type ) && ! is_object_in_taxonomy( $post_type, $this->coauthor_taxonomy ) ) {
782
  return $groupby;
783
  }
784
 
896
  }
897
 
898
  // A co-author is always required
899
+ // If no coauthor is provided AND no coauthors are currently set, assign to current user - retain old ones otherwise.
900
  if ( empty( $coauthors ) ) {
901
+ if( empty( $existing_coauthors ) ) {
902
+ $coauthors = array( $current_user->user_login );
903
+ } else {
904
+ $coauthors = $existing_coauthors;
905
+ }
906
  }
907
 
908
  // Set the co-authors
973
  wp_delete_term( $delete_user->user_login, $this->coauthor_taxonomy );
974
  }
975
 
976
+ if ( $this->is_guest_authors_enabled() ) {
977
+ // Get the deleted user data by user id.
978
+ $user_data = get_user_by( 'id', $delete_id );
979
 
980
+ // Get the associated user.
981
+ $associated_user = $this->guest_authors->get_guest_author_by( 'linked_account', $user_data->data->user_login );
982
 
983
+ if ( isset( $associated_user->ID ) ) {
984
+ // Delete associated guest user.
985
+ $this->guest_authors->delete( $associated_user->ID );
986
+ }
987
  }
988
  }
989
 
1029
  }
1030
 
1031
  /**
1032
+ * Filter the count_users_posts() core function to include our correct count.
1033
+ *
1034
+ * @param int $count Post count
1035
+ * @param int $user_id WP user ID
1036
+ * @return int Post count
1037
  */
1038
  function filter_count_user_posts( $count, $user_id ) {
1039
  $user = get_userdata( $user_id );
 
1040
  $user = $this->get_coauthor_by( 'user_nicename', $user->user_nicename );
1041
 
1042
  $term = $this->get_author_term( $user );
1043
+
1044
+ if ( $term && ! is_wp_error( $term ) ) {
1045
+ if ( 'guest-author' === $user->type ) {
1046
+ // If using guest author term count, add on linked user count.
1047
+ $count = (int) $count + $term->count;
1048
  } else {
1049
+ $count = $term->count;
1050
  }
 
 
1051
  }
1052
 
1053
  return $count;
1107
  * the query_var is changed.
1108
  *
1109
  * Also, we have to do some hacky WP_Query modification for guest authors
1110
+ *
1111
+ * @param string $selection The assembled selection query
1112
+ * @void
1113
  */
1114
+ public function fix_author_page( $selection ) {
1115
 
1116
  if ( ! is_author() ) {
1117
  return;
1190
  if( empty( $authors ) ) echo apply_filters( 'coauthors_no_matching_authors_message', 'Sorry, no matching authors found.');
1191
 
1192
  foreach ( $authors as $author ) {
1193
+ $avatar_url = get_avatar_url( $author->ID, array( 'default' => 'gravatar_default' ) );
1194
+ echo esc_html( $author->ID . ' | ' . $author->user_login . ' | ' . $author->display_name . ' | ' . $author->user_email . ' | ' . rawurldecode( $author->user_nicename ) ) . ' | ' . esc_url( $avatar_url ) . "\n";
1195
  }
1196
 
1197
  die();
1210
  $args = array(
1211
  'count_total' => false,
1212
  'search' => sprintf( '*%s*', $search ),
1213
+ 'search_columns' => array(
1214
  'ID',
1215
  'display_name',
1216
  'user_email',
1218
  ),
1219
  'fields' => 'all_with_meta',
1220
  );
 
1221
  $found_users = get_users( $args );
 
1222
 
1223
  foreach ( $found_users as $found_user ) {
1224
  $term = $this->get_author_term( $found_user );
1254
  $ignored_authors = apply_filters( 'coauthors_edit_ignored_authors', $ignored_authors );
1255
  foreach ( $found_users as $key => $found_user ) {
1256
  // Make sure the user is contributor and above (or a custom cap)
1257
+ if ( in_array( $found_user->user_nicename, $ignored_authors ) ) { //AJAX sends a list of already present *users_nicenames*
1258
  unset( $found_users[ $key ] );
1259
  } else if ( 'wpuser' === $found_user->type && false === $found_user->has_cap( apply_filters( 'coauthors_edit_author_cap', 'edit_posts' ) ) ) {
1260
  unset( $found_users[ $key ] );
1263
  return (array) $found_users;
1264
  }
1265
 
 
 
 
 
 
 
 
 
 
 
 
1266
  /**
1267
  * Modify get_terms() to LIKE against the term description instead of the term name
1268
  *
1329
  'author_name' => wp_get_current_user()->user_nicename,
1330
  );
1331
  if ( 'post' != get_post_type() ) {
1332
+ $mine_args['post_type'] = get_current_screen()->post_type;
1333
  }
1334
  if ( ! empty( $_REQUEST['author_name'] ) && wp_get_current_user()->user_nicename == $_REQUEST['author_name'] ) {
1335
  $class = ' class="current"';
1380
  return (bool) in_array( $pagenow, $this->_pages_whitelist );
1381
  }
1382
 
1383
+ /**
1384
+ * Builds list of capabilities that CAP should filter.
1385
+ *
1386
+ * Will only work after $this->supported_post_types has been populated.
1387
+ * Will only run once per request, and then cache the result.
1388
+ * The result is cached in $this->to_be_filtered_caps since CoAuthors_Plus is only instantiated once and stored as a global.
1389
+ *
1390
+ * @return array caps that CAP should filter
1391
+ */
1392
+ public function get_to_be_filtered_caps() {
1393
+ if( ! empty( $this->supported_post_types ) && empty( $this->to_be_filtered_caps ) ) {
1394
+ $this->to_be_filtered_caps[] = 'edit_post'; // Need to filter this too, unfortunately: http://core.trac.wordpress.org/ticket/22415
1395
+
1396
+ foreach( $this->supported_post_types as $single ) {
1397
+ $obj = get_post_type_object( $single );
1398
+
1399
+ $this->to_be_filtered_caps[] = $obj->cap->edit_post;
1400
+ $this->to_be_filtered_caps[] = $obj->cap->edit_others_posts; // This as well: http://core.trac.wordpress.org/ticket/22417
1401
+ }
1402
+
1403
+ $this->to_be_filtered_caps = array_unique( $this->to_be_filtered_caps );
1404
+ }
1405
+
1406
+ return $this->to_be_filtered_caps;
1407
+ }
1408
+
1409
  /**
1410
  * Allows guest authors to edit the post they're co-authors of
1411
  */
1415
  $user_id = isset( $args[1] ) ? $args[1] : 0;
1416
  $post_id = isset( $args[2] ) ? $args[2] : 0;
1417
 
1418
+ if( ! in_array( $cap, $this->get_to_be_filtered_caps(), true ) ) {
1419
+ return $allcaps;
1420
+ }
1421
+
1422
  $obj = get_post_type_object( get_post_type( $post_id ) );
1423
  if ( ! $obj || 'revision' == $obj->name ) {
1424
  return $allcaps;
1425
  }
1426
 
1427
+ //Even though we bail if cap is not among the to_be_filtered ones, there is a time in early request processing in which that list is not yet available, so the following block is needed
1428
  $caps_to_modify = array(
1429
  $obj->cap->edit_post,
1430
  'edit_post', // Need to filter this too, unfortunately: http://core.trac.wordpress.org/ticket/22415
1472
  return $term;
1473
  }
1474
 
1475
+ // See if the prefixed term is available, otherwise default to just the nicename
1476
+ $term = get_term_by( 'slug', 'cap-' . $coauthor->user_nicename, $this->coauthor_taxonomy );
1477
+ if ( ! $term ) {
1478
+ $term = get_term_by( 'slug', $coauthor->user_nicename, $this->coauthor_taxonomy );
 
 
 
 
 
 
 
 
 
1479
  }
1480
  wp_cache_set( $cache_key, $term, 'co-authors-plus' );
1481
  return $term;
1670
 
1671
  /**
1672
  * Filter of the header of author archive pages to correctly display author.
1673
+ *
1674
+ * @param $title string Archive Page Title
1675
+ *
1676
+ * @return string Archive Page Title
1677
  */
1678
+ public function filter_author_archive_title( $title ) {
1679
+
1680
+ // Bail if not an author archive template
1681
+ if ( ! is_author() ) {
1682
+ return $title;
1683
+ }
1684
+
1685
+ $author_slug = sanitize_user( get_query_var( 'author_name' ) );
1686
+ $author = $this->get_coauthor_by( 'user_nicename', $author_slug );
1687
+
1688
+ return sprintf( __( 'Author: %s' ), $author->display_name );
1689
+ }
1690
+
1691
+ /**
1692
+ * Get the post count for the guest author
1693
+ *
1694
+ * @param object $guest_author guest-author object.
1695
+ * @return int post count for the guest author
1696
+ */
1697
+ public function get_guest_author_post_count( $guest_author ) {
1698
+ if ( ! is_object( $guest_author ) ) {
1699
+ return;
1700
+ }
1701
+
1702
+ $term = $this->get_author_term( $guest_author );
1703
+ $guest_term = get_term_by( 'slug', 'cap-' . $guest_author->user_nicename, $this->coauthor_taxonomy );
1704
+
1705
+ if ( is_object( $guest_term )
1706
+ && ! empty( $guest_author->linked_account )
1707
+ && $guest_term->count ) {
1708
+ return count_user_posts( get_user_by( 'login', $guest_author->linked_account )->ID );
1709
+ } elseif ( $term ) {
1710
+ return $term->count;
1711
+ } else {
1712
+ return 0;
1713
+ }
1714
+ }
1715
+
1716
+ /**
1717
+ * Filter to display author image if exists instead of avatar.
1718
+ *
1719
+ * @param $url string Avatar URL
1720
+ * @param $id int Author ID
1721
+ *
1722
+ * @return string Avatar URL
1723
+ */
1724
+ public function filter_get_avatar_url( $url, $id ) {
1725
+ if ( has_post_thumbnail( $id ) ) {
1726
+ $url = get_the_post_thumbnail_url( $id, $this->gravatar_size );
1727
  }
1728
+ return $url;
1729
  }
1730
  }
1731
 
composer.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name" : "automattic/co-authors-plus",
3
+ "description": "Multiple bylines and Guest Authors for WordPress",
4
+ "homepage" : "http://wordpress.org/plugins/co-authors-plus/",
5
+ "type" : "wordpress-plugin",
6
+ "license" : "GPL-2.0+",
7
+ "authors" : [
8
+ {
9
+ "name": "Daniel Bachhuber",
10
+ "email": "d@danielbachhuber.com",
11
+ "homepage": "http://danielbachhuber.com",
12
+ "role": "Developer"
13
+ },
14
+ {
15
+ "name" : "Automattic",
16
+ "homepage": "http://automattic.com/"
17
+ }
18
+ ],
19
+ "support" : {
20
+ "issues": "https://github.com/Automattic/Co-Authors-Plus/issues",
21
+ "source": "https://github.com/Automattic/Co-Authors-Plus",
22
+ "forum": "http://wordpress.org/support/plugin/co-authors-plus"
23
+ },
24
+ "require": {
25
+ "composer/installers": "~1.0"
26
+ }
27
+ }
css/co-authors-plus.css CHANGED
File without changes
css/guest-authors.css CHANGED
File without changes
deprecated.php CHANGED
File without changes
js/co-authors-plus.js CHANGED
@@ -82,7 +82,7 @@ jQuery( document ).ready(function () {
82
  if ( ! co ) var co = coauthors_create_autosuggest( author.name, coName )
83
  var tag = coauthors_create_author_tag( author );
84
  var input = coauthors_create_author_hidden_input( author );
85
- var $gravatar = coauthors_create_author_gravatar( author, 25 );
86
 
87
  tag.append( $gravatar );
88
 
@@ -200,6 +200,9 @@ jQuery( document ).ready(function () {
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] ) );
@@ -251,35 +254,16 @@ jQuery( document ).ready(function () {
251
  return $tag;
252
  }
253
 
254
- function coauthors_create_author_gravatar( author, size ) {
255
-
256
- var gravatar_link = get_gravatar_link( author.email, size );
257
 
258
  var $gravatar = jQuery( '<img/>' )
259
  .attr( 'alt', author.name )
260
- .attr( 'src', gravatar_link )
261
  .addClass( 'coauthor-gravatar' )
262
  ;
263
  return $gravatar;
264
  }
265
 
266
- // MD5 (Message-Digest Algorithm) by WebToolkit -- needed for gravatars
267
- // http://www.webtoolkit.info/javascript-md5.html
268
- function MD5(s){function L(k,d){return(k<<d)|(k>>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/\r\n/g,"\n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x)}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g)}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase()};
269
-
270
- // Adapted from http://www.deluxeblogtips.com/2010/04/get-gravatar-using-only-javascript.html
271
- function get_gravatar_link( email, size ) {
272
- var size = size || 80;
273
-
274
- // need to check if page is secure or not
275
- var gravatar_url = 'http://www.gravatar.com/avatar/';
276
- if ( 'https:' == document.location.protocol ) {
277
- // secure
278
- gravatar_url = 'https://secure.gravatar.com/avatar/';
279
- }
280
- return gravatar_url + MD5( email ) + '.jpg?s=' + size;
281
- }
282
-
283
  /*
284
  * Creates the text tag for a co-author
285
  * @param string Name of the co-author
@@ -389,6 +373,7 @@ jQuery( document ).ready(function () {
389
  var $post_coauthor_names = jQuery( 'input[name="coauthorsinput[]"]' );
390
  var $post_coauthor_emails = jQuery( 'input[name="coauthorsemails[]"]' );
391
  var $post_coauthor_nicenames = jQuery( 'input[name="coauthorsnicenames[]"]' );
 
392
 
393
  var post_coauthors = [];
394
 
@@ -397,7 +382,8 @@ jQuery( document ).ready(function () {
397
  login: $post_coauthor_logins[i].value,
398
  name: $post_coauthor_names[i].value,
399
  email: $post_coauthor_emails[i].value,
400
- nicename: $post_coauthor_nicenames[i].value
 
401
  });
402
  }
403
 
82
  if ( ! co ) var co = coauthors_create_autosuggest( author.name, coName )
83
  var tag = coauthors_create_author_tag( author );
84
  var input = coauthors_create_author_hidden_input( author );
85
+ var $gravatar = coauthors_create_author_gravatar( author );
86
 
87
  tag.append( $gravatar );
88
 
200
  author.login = jQuery.trim( vals[1] );
201
  author.name = jQuery.trim( vals[2] );
202
  author.email = jQuery.trim( vals[3] );
203
+ if( author.avatar !== '' ){
204
+ author.avatar = jQuery.trim( vals[5] );
205
+ }
206
 
207
  // Decode user-nicename if it has special characters in it.
208
  author.nicename = decodeURIComponent( jQuery.trim( vals[4] ) );
254
  return $tag;
255
  }
256
 
257
+ function coauthors_create_author_gravatar( author ) {
 
 
258
 
259
  var $gravatar = jQuery( '<img/>' )
260
  .attr( 'alt', author.name )
261
+ .attr( 'src', author.avatar )
262
  .addClass( 'coauthor-gravatar' )
263
  ;
264
  return $gravatar;
265
  }
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  /*
268
  * Creates the text tag for a co-author
269
  * @param string Name of the co-author
373
  var $post_coauthor_names = jQuery( 'input[name="coauthorsinput[]"]' );
374
  var $post_coauthor_emails = jQuery( 'input[name="coauthorsemails[]"]' );
375
  var $post_coauthor_nicenames = jQuery( 'input[name="coauthorsnicenames[]"]' );
376
+ var $post_coauthoravatars = jQuery( 'input[name="coauthorsavatars[]"]' );
377
 
378
  var post_coauthors = [];
379
 
382
  login: $post_coauthor_logins[i].value,
383
  name: $post_coauthor_names[i].value,
384
  email: $post_coauthor_emails[i].value,
385
+ nicename: $post_coauthor_nicenames[i].value,
386
+ avatar: $post_coauthoravatars[i].value,
387
  });
388
  }
389
 
js/guest-authors.js CHANGED
File without changes
languages/co-authors-plus-de_DE.mo CHANGED
File without changes
languages/co-authors-plus-de_DE.po CHANGED
File without changes
languages/co-authors-plus-nl_NL.mo CHANGED
File without changes
languages/co-authors-plus-nl_NL.po CHANGED
File without changes
languages/co-authors-plus-sv_SE.mo CHANGED
File without changes
languages/co-authors-plus-sv_SE.po CHANGED
File without changes
lib/select2/select2.css CHANGED
File without changes
lib/select2/select2.min.js CHANGED
File without changes
lib/select2/select2.png CHANGED
File without changes
lib/select2/select2x2.png CHANGED
File without changes
lib/select2/spinner.gif CHANGED
File without changes
php/class-coauthors-guest-authors.php CHANGED
@@ -69,6 +69,9 @@ class CoAuthors_Guest_Authors
69
  // Add support for featured thumbnails that we can use for guest author avatars
70
  add_filter( 'get_avatar', array( $this, 'filter_get_avatar' ),10 ,5 );
71
 
 
 
 
72
  // Allow users to change where this is placed in the WordPress admin
73
  $this->parent_page = apply_filters( 'coauthors_guest_author_parent_page', $this->parent_page );
74
 
@@ -95,25 +98,25 @@ class CoAuthors_Guest_Authors
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(
102
- 'name' => $this->labels['plural'],
103
- 'singular_name' => $this->labels['singular'],
104
- 'add_new' => _x( 'Add New', 'guest author', 'co-authors-plus' ),
105
- 'all_items' => $this->labels['all_items'],
106
- 'add_new_item' => $this->labels['add_new_item'],
107
- 'edit_item' => $this->labels['edit_item'],
108
- 'new_item' => $this->labels['new_item'],
109
- 'view_item' => $this->labels['view_item'],
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,
@@ -467,12 +470,7 @@ class CoAuthors_Guest_Authors
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>';
@@ -493,9 +491,9 @@ class CoAuthors_Guest_Authors
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 );
@@ -960,11 +958,12 @@ class CoAuthors_Guest_Authors
960
  /**
961
  * Get an thumbnail for a Guest Author object
962
  *
963
- * @param object The Guest Author object for which to retrieve the thumbnail
964
- * @param int The desired image size
965
- * @return string The thumbnail image tag, or null if one doesn't exist
 
966
  */
967
- function get_guest_author_thumbnail( $guest_author, $size ) {
968
  // See if the guest author has an avatar
969
  if ( ! has_post_thumbnail( $guest_author->ID ) ) {
970
  return null;
@@ -973,6 +972,12 @@ class CoAuthors_Guest_Authors
973
  $args = array(
974
  'class' => "avatar avatar-{$size} photo",
975
  );
 
 
 
 
 
 
976
 
977
  $size = array( $size, $size );
978
 
@@ -1258,6 +1263,11 @@ class CoAuthors_Guest_Authors
1258
  update_post_meta( $post_id, $pm_key, $args[ $key ] );
1259
  }
1260
 
 
 
 
 
 
1261
  // Make sure the author term exists and that we're assigning it to this post type
1262
  $author_term = $coauthors_plus->update_author_term( $this->get_guest_author_by( 'ID', $post_id ) );
1263
  wp_set_post_terms( $post_id, array( $author_term->slug ), $coauthors_plus->coauthor_taxonomy, false );
@@ -1503,4 +1513,95 @@ class CoAuthors_Guest_Authors
1503
 
1504
  return $link;
1505
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1506
  }
69
  // Add support for featured thumbnails that we can use for guest author avatars
70
  add_filter( 'get_avatar', array( $this, 'filter_get_avatar' ),10 ,5 );
71
 
72
+ // Add a Personal Data Exporter to guest authors
73
+ add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'filter_personal_data_exporter' ), 1 );
74
+
75
  // Allow users to change where this is placed in the WordPress admin
76
  $this->parent_page = apply_filters( 'coauthors_guest_author_parent_page', $this->parent_page );
77
 
98
  'remove_featured_image' => __( 'Remove Avatar', 'co-authors-plus' ),
99
  ) );
100
 
101
+ // Register a post type to store our guest authors
102
  $args = array(
103
  'label' => $this->labels['singular'],
104
  'labels' => array(
105
+ 'name' => isset( $this->labels['plural'] ) ? $this->labels['plural'] : '',
106
+ 'singular_name' => isset( $this->labels['singular'] ) ? $this->labels['singular'] : '',
107
+ 'add_new' => _x( 'Add New', 'guest author', 'co-authors-plus' ),
108
+ 'all_items' => isset( $this->labels['all_items'] ) ? $this->labels['all_items'] : '',
109
+ 'add_new_item' => isset( $this->labels['add_new_item'] ) ? $this->labels['add_new_item'] : '',
110
+ 'edit_item' => isset( $this->labels['edit_item'] ) ? $this->labels['edit_item'] : '',
111
+ 'new_item' => isset( $this->labels['new_item'] ) ? $this->labels['new_item'] : '',
112
+ 'view_item' => isset( $this->labels['view_item'] ) ? $this->labels['view_item'] : '',
113
+ 'search_items' => isset( $this->labels['search_items'] ) ? $this->labels['search_items'] : '',
114
+ 'not_found' => isset( $this->labels['not_found'] ) ? $this->labels['not_found'] : '',
115
+ 'not_found_in_trash' => isset( $this->labels['not_found_in_trash'] ) ? $this->labels['not_found_in_trash'] : '',
116
+ 'featured_image' => isset( $this->labels['featured_image'] ) ? $this->labels['featured_image'] : '',
117
+ 'set_featured_image' => isset( $this->labels['set_featured_image'] ) ? $this->labels['set_featured_image'] : '',
118
+ 'use_featured_image' => isset( $this->labels['use_featured_image'] ) ? $this->labels['use_featured_image'] : '',
119
+ 'remove_featured_image' => isset( $this->labels['remove_featured_image'] ) ? $this->labels['remove_featured_image'] : '',
120
  ),
121
  'public' => true,
122
  'publicly_queryable' => false,
470
 
471
  // get post count
472
  global $coauthors_plus;
473
+ $count = $coauthors_plus->get_guest_author_post_count( $guest_author );
 
 
 
 
 
474
 
475
  echo '<div class="wrap">';
476
  echo '<div class="icon32" id="icon-users"><br/></div>';
491
  }
492
  $post_count_message .= $note;
493
  }
494
+ $allowed_html = array(
495
+ 'p' => array(
496
+ 'class' => array(),
497
  ),
498
  );
499
  echo wp_kses( $post_count_message, $allowed_html );
958
  /**
959
  * Get an thumbnail for a Guest Author object
960
  *
961
+ * @param object The Guest Author object for which to retrieve the thumbnail.
962
+ * @param int The desired image size.
963
+ * @param array|string Optional. An array or string of additional classes. Default null.
964
+ * @return string The thumbnail image tag, or null if one doesn't exist.
965
  */
966
+ function get_guest_author_thumbnail( $guest_author, $size, $class = null ) {
967
  // See if the guest author has an avatar
968
  if ( ! has_post_thumbnail( $guest_author->ID ) ) {
969
  return null;
972
  $args = array(
973
  'class' => "avatar avatar-{$size} photo",
974
  );
975
+ if ( ! empty( $class ) ) {
976
+ if ( is_array( $class ) ) {
977
+ $class = implode( ' ', $class );
978
+ }
979
+ $args['class'] += " $class";
980
+ }
981
 
982
  $size = array( $size, $size );
983
 
1263
  update_post_meta( $post_id, $pm_key, $args[ $key ] );
1264
  }
1265
 
1266
+ // Attach the avatar / featured image.
1267
+ if ( ! empty( $args[ 'avatar' ] ) ) {
1268
+ set_post_thumbnail( $post_id, $args[ 'avatar' ] );
1269
+ }
1270
+
1271
  // Make sure the author term exists and that we're assigning it to this post type
1272
  $author_term = $coauthors_plus->update_author_term( $this->get_guest_author_by( 'ID', $post_id ) );
1273
  wp_set_post_terms( $post_id, array( $author_term->slug ), $coauthors_plus->coauthor_taxonomy, false );
1513
 
1514
  return $link;
1515
  }
1516
+
1517
+ /**
1518
+ * Filter Personal Data Exporters to add Guest Author exporter
1519
+ *
1520
+ * @since 3.3.1
1521
+ */
1522
+ public function filter_personal_data_exporter( $exporters ) {
1523
+ $exporters['cap-guest-author'] = array(
1524
+ 'exporter_friendly_name' => __( 'Guest Author', 'co-authors-plus' ),
1525
+ 'callback' => array( $this, 'personal_data_exporter' ),
1526
+ );
1527
+
1528
+ return $exporters;
1529
+ }
1530
+
1531
+ /**
1532
+ * Finds and exports personal data associated with an email address for guest authors
1533
+ *
1534
+ * @since 3.3.1
1535
+ *
1536
+ * @param string $email_address The guest author email address.
1537
+ * @return array An array of personal data.
1538
+ */
1539
+ public function personal_data_exporter( $email_address ) {
1540
+ $email_address = trim( $email_address );
1541
+
1542
+ $data_to_export = array();
1543
+
1544
+ $author = $this->get_guest_author_by( 'user_email', $email_address );
1545
+
1546
+ if ( ! $author ) {
1547
+ return array(
1548
+ 'data' => array(),
1549
+ 'done' => true,
1550
+ );
1551
+ }
1552
+
1553
+ $author_data = array(
1554
+ 'ID' => __( 'ID', 'co-authors-plus' ),
1555
+ 'user_login' => __( 'Login Name', 'co-authors-plus' ),
1556
+ 'display_name' => __( 'Display Name', 'co-authors-plus' ),
1557
+ 'user_email' => __( 'Email', 'co-authors-plus' ),
1558
+ 'first_name' => __( 'First Name', 'co-authors-plus' ),
1559
+ 'last_name' => __( 'Last Name', 'co-authors-plus' ),
1560
+ 'website' => __( 'Website', 'co-authors-plus' ),
1561
+ 'aim' => __( 'AIM', 'co-authors-plus' ),
1562
+ 'yahooim' => __( 'Yahoo IM', 'co-authors-plus' ),
1563
+ 'jabber' => __( 'Jabber / Google Talk', 'co-authors-plus' ),
1564
+ 'description' => __( 'Biographical Info', 'co-authors-plus' ),
1565
+ );
1566
+
1567
+ $author_data_to_export = array();
1568
+
1569
+ foreach ( $author_data as $key => $name ) {
1570
+ if ( empty( $author->$key ) ) {
1571
+ continue;
1572
+ }
1573
+
1574
+ $author_data_to_export[] = array(
1575
+ 'name' => $name,
1576
+ 'value' => $author->$key,
1577
+ );
1578
+ }
1579
+
1580
+ /**
1581
+ * Filters extra data to allow plugins add data related to guest author
1582
+ *
1583
+ * @since 3.3.1
1584
+ *
1585
+ * @param array $extra_data A empty array to be populated with extra data
1586
+ * @param int $author->ID The guest author ID
1587
+ * @param string $email_address The guest author email address
1588
+ */
1589
+ $extra_data = apply_filters( 'coauthors_guest_author_personal_export_extra_data', [], $author->ID, $email_address );
1590
+
1591
+ if ( is_array( $extra_data ) && ! empty( $extra_data ) ) {
1592
+ $author_data_to_export = array_merge( $author_data_to_export, $extra_data );
1593
+ }
1594
+
1595
+ $data_to_export[] = array(
1596
+ 'group_id' => 'cap-guest-author',
1597
+ 'group_label' => __( 'Guest Author', 'co-authors-plus' ),
1598
+ 'item_id' => "cap-guest-author-{$author->ID}",
1599
+ 'data' => $author_data_to_export,
1600
+ );
1601
+
1602
+ return array(
1603
+ 'data' => $data_to_export,
1604
+ 'done' => true,
1605
+ );
1606
+ }
1607
  }
php/class-coauthors-template-filters.php CHANGED
File without changes
php/class-coauthors-wp-list-table.php CHANGED
@@ -250,14 +250,15 @@ class CoAuthors_WP_List_Table extends WP_List_Table {
250
  */
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;
 
261
  }
262
  return '<a href="' . esc_url( add_query_arg( 'author_name', rawurlencode( $item->user_login ), admin_url( 'edit.php' ) ) ) . '">' . $count . '</a>';
263
  }
250
  */
251
  function column_posts( $item ) {
252
  global $coauthors_plus;
253
+ $count = $coauthors_plus->get_guest_author_post_count( $item );
254
+
255
+ if ( ! empty( $item->linked_account ) ) {
256
+ global $coauthors_plus;
257
+ // Add user term count to guest author term count.
258
+ $term = get_term_by( 'slug', 'cap-' . $item->linked_account, $coauthors_plus->coauthor_taxonomy );
259
+ if ( is_object( $term ) ) {
260
+ $count = $count + $term->count;
261
+ }
262
  }
263
  return '<a href="' . esc_url( add_query_arg( 'author_name', rawurlencode( $item->user_login ), admin_url( 'edit.php' ) ) ) . '">' . $count . '</a>';
264
  }
php/class-wp-cli.php CHANGED
@@ -121,7 +121,7 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
121
  * @since 3.0
122
  *
123
  * @subcommand assign-coauthors
124
- * @synopsis [--meta_key=<key>] [--post_type=<ptype>]
125
  */
126
  public function assign_coauthors( $args, $assoc_args ) {
127
  global $coauthors_plus;
@@ -823,6 +823,9 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
823
  'display_name' => sanitize_text_field( $author['display_name'] ),
824
  'user_login' => sanitize_user( $author['user_login'] ),
825
  'user_email' => sanitize_email( $author['user_email'] ),
 
 
 
826
  );
827
 
828
  $display_name_space_pos = strpos( $author['display_name'], ' ' );
@@ -861,6 +864,9 @@ class CoAuthorsPlus_Command extends WP_CLI_Command {
861
  'user_email' => $author['user_email'],
862
  'first_name' => $author['first_name'],
863
  'last_name' => $author['last_name'],
 
 
 
864
  ) );
865
 
866
  if ( $guest_author_id ) {
121
  * @since 3.0
122
  *
123
  * @subcommand assign-coauthors
124
+ * @synopsis [--meta_key=<key>] [--post_type=<ptype>] [--append_coauthors]
125
  */
126
  public function assign_coauthors( $args, $assoc_args ) {
127
  global $coauthors_plus;
823
  'display_name' => sanitize_text_field( $author['display_name'] ),
824
  'user_login' => sanitize_user( $author['user_login'] ),
825
  'user_email' => sanitize_email( $author['user_email'] ),
826
+ 'website' => esc_url_raw( $author['website'] ),
827
+ 'description' => wp_filter_post_kses( $author['description'] ),
828
+ 'avatar' => absint( $author['avatar'] ),
829
  );
830
 
831
  $display_name_space_pos = strpos( $author['display_name'], ' ' );
864
  'user_email' => $author['user_email'],
865
  'first_name' => $author['first_name'],
866
  'last_name' => $author['last_name'],
867
+ 'website' => $author['website'],
868
+ 'description' => $author['description'],
869
+ 'avatar' => $author['avatar'],
870
  ) );
871
 
872
  if ( $guest_author_id ) {
php/integrations/amp.php CHANGED
File without changes
php/integrations/amp/meta-author.php CHANGED
File without changes
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: 5.0
5
  Requires at least: 4.1
6
- Stable tag: 3.3.1
7
 
8
  Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box
9
 
@@ -15,7 +15,7 @@ Add writers as bylines without creating WordPress user accounts. Simply [create
15
 
16
  On the frontend, use the [Co-Authors Plus template tags](http://vip.wordpress.com/documentation/incorporate-co-authors-plus-template-tags-into-your-theme/) to list co-authors anywhere you'd normally list the author.
17
 
18
- This plugin is an almost complete rewrite of the Co-Authors plugin originally developed at [Shepherd Interactive](http://www.shepherd-interactive.com/) (2007). The original plugin was inspired by the 'Multiple Authors' plugin by Mark Jaquith (2005).
19
 
20
  == Frequently Asked Questions ==
21
 
@@ -41,6 +41,11 @@ To create new guest author profiles, a WordPress will need the 'list_users' capa
41
 
42
  Yep! There's a template tag called `coauthors_wp_list_authors()` that accepts many of the same arguments as `wp_list_authors()`. Look in template-tags.php for more details.
43
 
 
 
 
 
 
44
  == Upgrade Notice ==
45
 
46
  = 3.1 =
@@ -57,6 +62,40 @@ Bug fixes and minor enhancements
57
 
58
  == Changelog ==
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  = 3.3.1 ("Gutentag") =
61
  * 5.0 Compat: Hide core author inputs when using the Block Editor to limit confusion (h/t jonathanstegall).
62
 
1
  === Co-Authors Plus ===
2
  Contributors: batmoo, danielbachhuber, automattic
3
  Tags: authors, users, multiple authors, coauthors, multi-author, publishing
4
+ Tested up to: 5.1.1
5
  Requires at least: 4.1
6
+ Stable tag: 3.4
7
 
8
  Assign multiple bylines to posts, pages, and custom post types via a search-as-you-type input box
9
 
15
 
16
  On the frontend, use the [Co-Authors Plus template tags](http://vip.wordpress.com/documentation/incorporate-co-authors-plus-template-tags-into-your-theme/) to list co-authors anywhere you'd normally list the author.
17
 
18
+ This plugin is an almost complete rewrite of the [Co-Authors](https://wordpress.org/plugins/co-authors/) plugin originally developed by Weston Ruter (2007). The original plugin was inspired by the '[Multiple Authors](https://txfx.net/2005/08/16/new-plugin-multiple-authors/)' plugin by Mark Jaquith (2005).
19
 
20
  == Frequently Asked Questions ==
21
 
41
 
42
  Yep! There's a template tag called `coauthors_wp_list_authors()` that accepts many of the same arguments as `wp_list_authors()`. Look in template-tags.php for more details.
43
 
44
+ = Can I disable Guest Authors?
45
+
46
+ Yep! Guest authors can be disabled entirely through an apt filter. Having the following line load on `init` will do the trick:
47
+ `add_filter( 'coauthors_guest_authors_enabled', '__return_false' )`
48
+
49
  == Upgrade Notice ==
50
 
51
  = 3.1 =
62
 
63
  == Changelog ==
64
 
65
+ = 3.4 =
66
+ * New filter get_coauthors for modifying coauthor data returned in get_coauthors()
67
+ * New filter coauthors_guest_authors_exported_extra_data to allow guest author to export data as regular author
68
+ * New filter get_avatar_url() to show avatar in JS selection
69
+ * New parameter in coauthors_wp_list_authors() to only query authors with posts
70
+ * Add internationalization support to title and name in author archives
71
+ * Add safelist to skip irrelevant capabilities during permission checks
72
+ * Add helper function get_guest_author_post_count()
73
+ * Add parameter for outputting HTML classes in coauthors_get_avatar() template tag
74
+ * Add --append_coauthors flag to synopsis of CLI assign-coauthors
75
+ * Adjust CLI command create-guest-authors-from-csv to import website, avatar and description
76
+ * Post type of "any" can be used in filters
77
+ * Remove unnecessary is_array() check
78
+ * Remove unnecessary action_pre_user_query()
79
+ * Use correct args in search_authors()
80
+ * Have filter_author_archive_title() run on author archives only
81
+ * Improve tests coverage
82
+ * Change posts_selection to action from filter
83
+ * Fix number of args expected for get_the_archive_title callback
84
+ * Fix spelling, update FAQ for disabling guest authors and credits in readme
85
+ * Output coauthors_links_single() template tag correctly when guest author has no website
86
+ * Number by "Mine" link shows correct listing of posts
87
+ * Linked guest authors show accurate post counts
88
+ * Can no longer add co-author more than once
89
+ * No more overwriting posts with current user in `add_coauthors()`
90
+ * Accurate post count for user when using different login
91
+ * No more double post count for users with linked accounts
92
+ * Fix SQL error
93
+ * Fix "Mine" link href for Pages
94
+ * Can delete users when guest authors functionality disabled
95
+ * Fix incompatibility issue with Yoast of missing posts in author pages
96
+ * Resolve undefined index warnings on author archives
97
+ * Resolve warnings when current user has no term assigned
98
+
99
  = 3.3.1 ("Gutentag") =
100
  * 5.0 Compat: Hide core author inputs when using the Block Editor to limit confusion (h/t jonathanstegall).
101
 
screenshot-1.png CHANGED
File without changes
screenshot-2.png CHANGED
File without changes
screenshot-3.png CHANGED
File without changes
template-tags.php CHANGED
@@ -37,6 +37,7 @@ function get_coauthors( $post_id = 0 ) {
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
 
@@ -420,22 +421,20 @@ function coauthors_emails( $between = null, $betweenLast = null, $before = null,
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
  }
@@ -527,6 +526,7 @@ function the_coauthor_meta( $field, $user_id = 0 ) {
527
  * feed (string) (''): If isn't empty, show links to author's feeds.
528
  * feed_image (string) (''): If isn't empty, use this image to link to feeds.
529
  * echo (boolean) (true): Set to false to return the output, instead of echoing.
 
530
  * @param array $args The argument array.
531
  * @return null|string The output, if echo is set to false.
532
  */
@@ -544,7 +544,8 @@ function coauthors_wp_list_authors( $args = array() ) {
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 );
@@ -552,8 +553,12 @@ function coauthors_wp_list_authors( $args = array() ) {
552
 
553
  $term_args = array(
554
  'orderby' => 'name',
555
- 'hide_empty' => 0,
556
  'number' => (int) $args['number'],
 
 
 
 
 
557
  );
558
  $author_terms = get_terms( $coauthors_plus->coauthor_taxonomy, $term_args );
559
 
@@ -678,11 +683,19 @@ function coauthors_wp_list_authors( $args = array() ) {
678
  * This is a replacement for using get_avatar(), which only operates on email addresses and cannot differentiate
679
  * between Guest Authors (who may share an email) and regular user accounts
680
  *
681
- * @param object $coauthor The Co Author or Guest Author object
682
- * @param int $size The desired size
683
- * @return string The image tag for the avatar, or an empty string if none could be determined
 
 
 
 
 
 
 
 
684
  */
685
- function coauthors_get_avatar( $coauthor, $size = 32, $default = '', $alt = false ) {
686
  global $coauthors_plus;
687
 
688
  if ( ! is_object( $coauthor ) ) {
@@ -690,7 +703,7 @@ function coauthors_get_avatar( $coauthor, $size = 32, $default = '', $alt = fals
690
  }
691
 
692
  if ( isset( $coauthor->type ) && 'guest-author' == $coauthor->type ) {
693
- $guest_author_thumbnail = $coauthors_plus->guest_authors->get_guest_author_thumbnail( $coauthor, $size );
694
 
695
  if ( $guest_author_thumbnail ) {
696
  return $guest_author_thumbnail;
@@ -699,7 +712,7 @@ function coauthors_get_avatar( $coauthor, $size = 32, $default = '', $alt = fals
699
 
700
  // Make sure we're dealing with an object for which we can retrieve an email
701
  if ( isset( $coauthor->user_email ) ) {
702
- return get_avatar( $coauthor->user_email, $size, $default, $alt );
703
  }
704
 
705
  // Nothing matched, an invalid object was passed.
37
  }
38
  // remove duplicate $coauthors objects from mapping user accounts to guest authors accounts
39
  $coauthors = array_unique( $coauthors, SORT_REGULAR );
40
+ $coauthors = apply_filters( 'get_coauthors', $coauthors, $post_id );
41
  return $coauthors;
42
  }
43
 
421
  * @return string
422
  */
423
  function coauthors_links_single( $author ) {
424
+ if ( 'guest-author' === $author->type && get_the_author_meta( 'website' ) ) {
425
+ return sprintf( '<a href="%s" title="%s" rel="author external">%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
  elseif ( get_the_author_meta( 'url' ) ) {
432
+ return sprintf( '<a href="%s" title="%s" rel="author external">%s</a>',
433
  esc_url( get_the_author_meta( 'url' ) ),
434
  esc_attr( sprintf( __( 'Visit %s&#8217;s website' ), esc_html( get_the_author() ) ) ),
435
  esc_html( get_the_author() )
436
  );
437
+ }
438
  else {
439
  return esc_html( get_the_author() );
440
  }
526
  * feed (string) (''): If isn't empty, show links to author's feeds.
527
  * feed_image (string) (''): If isn't empty, use this image to link to feeds.
528
  * echo (boolean) (true): Set to false to return the output, instead of echoing.
529
+ * authors_with_posts_only (boolean) (false): If true, don't query for authors with no posts.
530
  * @param array $args The argument array.
531
  * @return null|string The output, if echo is set to false.
532
  */
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
+ 'authors_with_posts_only' => false,
549
  );
550
 
551
  $args = wp_parse_args( $args, $defaults );
553
 
554
  $term_args = array(
555
  'orderby' => 'name',
 
556
  'number' => (int) $args['number'],
557
+ /*
558
+ * Historically, this was set to always be `0` ignoring `$args['hide_empty']` value
559
+ * To avoid any backwards incompatibility, inventing `authors_with_posts_only` that defaults to false
560
+ */
561
+ 'hide_empty' => (boolean) $args['authors_with_posts_only'],
562
  );
563
  $author_terms = get_terms( $coauthors_plus->coauthor_taxonomy, $term_args );
564
 
683
  * This is a replacement for using get_avatar(), which only operates on email addresses and cannot differentiate
684
  * between Guest Authors (who may share an email) and regular user accounts
685
  *
686
+ * @param object $coauthor The Co Author or Guest Author object.
687
+ * @param int $size The desired size.
688
+ * @param string $default Optional. URL for the default image or a default type. Accepts '404'
689
+ * (return a 404 instead of a default image), 'retro' (8bit), 'monsterid'
690
+ * (monster), 'wavatar' (cartoon face), 'indenticon' (the "quilt"),
691
+ * 'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF),
692
+ * or 'gravatar_default' (the Gravatar logo). Default is the value of the
693
+ * 'avatar_default' option, with a fallback of 'mystery'.
694
+ * @param string $alt Optional. Alternative text to use in &lt;img&gt; tag. Default false.
695
+ * @param array|string $class Optional. Array or string of additional classes to add to the &lt;img&gt; element. Default null.
696
+ * @return string The image tag for the avatar, or an empty string if none could be determined.
697
  */
698
+ function coauthors_get_avatar( $coauthor, $size = 32, $default = '', $alt = false, $class = null ) {
699
  global $coauthors_plus;
700
 
701
  if ( ! is_object( $coauthor ) ) {
703
  }
704
 
705
  if ( isset( $coauthor->type ) && 'guest-author' == $coauthor->type ) {
706
+ $guest_author_thumbnail = $coauthors_plus->guest_authors->get_guest_author_thumbnail( $coauthor, $size, $class );
707
 
708
  if ( $guest_author_thumbnail ) {
709
  return $guest_author_thumbnail;
712
 
713
  // Make sure we're dealing with an object for which we can retrieve an email
714
  if ( isset( $coauthor->user_email ) ) {
715
+ return get_avatar( $coauthor->user_email, $size, $default, $alt, array( 'class' => $class ) );
716
  }
717
 
718
  // Nothing matched, an invalid object was passed.
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,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ * On author pages, the queried object should only be set
10
+ * to a user that's not a member of the blog if they
11
+ * have at least one published post. This matches core behavior.
12
+ *
13
+ * @see https://core.trac.wordpress.org/changeset/27290
14
+ */
15
+ function test__author_queried_object_fix() {
16
+ global $wp_rewrite, $coauthors_plus;
17
+
18
+ /**
19
+ * Set up
20
+ */
21
+ $author1 = $this->factory->user->create( array( 'user_login' => 'msauthor1' ) );
22
+ $author2 = $this->factory->user->create( array( 'user_login' => 'msauthor2' ) );
23
+ $blog2 = $this->factory->blog->create( array( 'user_id' => $author1 ) );
24
+
25
+ switch_to_blog( $blog2 );
26
+ $wp_rewrite->init();
27
+
28
+ $blog2_post1 = $this->factory->post->create( array(
29
+ 'post_status' => 'publish',
30
+ 'post_content' => rand_str(),
31
+ 'post_title' => rand_str(),
32
+ 'post_author' => $author1,
33
+ ) );
34
+
35
+ /**
36
+ * Author 1 is an author on the blog
37
+ */
38
+ $this->go_to( get_author_posts_url( $author1 ) );
39
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
40
+
41
+ // Add the user to the blog
42
+ add_user_to_blog( $blog2, $author2, 'author' );
43
+
44
+ /**
45
+ * Author 2 is now on the blog, but not yet published
46
+ */
47
+ $this->go_to( get_author_posts_url( $author2 ) );
48
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
49
+
50
+ // Add the user as an author on the original post
51
+ $author2_obj = get_user_by( 'id', $author2 );
52
+ $coauthors_plus->add_coauthors( $blog2_post1, array( $author2_obj->user_login ), true );
53
+
54
+ /**
55
+ * Author 2 is now on the blog, and published
56
+ */
57
+ $this->go_to( get_author_posts_url( $author2 ) );
58
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
59
+
60
+ // Remove the user from the blog
61
+ remove_user_from_blog( $author2, $blog2 );
62
+
63
+ /**
64
+ * Author 2 was removed from the blog, but still a published author
65
+ */
66
+ $this->go_to( get_author_posts_url( $author2 ) );
67
+ $this->assertQueryTrue( 'is_author', 'is_archive' );
68
+
69
+ // Delete the user from the network
70
+ wpmu_delete_user( $author2 );
71
+
72
+ /**
73
+ * Author 2 is no more
74
+ */
75
+ $this->go_to( get_author_posts_url( $author2 ) );
76
+ $this->assertEquals( false, get_user_by( 'id', $author2 ) );
77
+
78
+ restore_current_blog();
79
+
80
+ }
81
+ }
tests/test-author-queries.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_Author_Queries extends CoAuthorsPlus_TestCase {
4
+
5
+ public function test__author_arg__user_is_post_author_query_as_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
+ wp_set_current_user( $author_id );
16
+
17
+ $query = new WP_Query( array(
18
+ 'author' => $author_id,
19
+ ) );
20
+
21
+ $this->assertEquals( 1, count( $query->posts ) );
22
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
23
+ }
24
+
25
+ public function test__author_arg__user_is_post_author() {
26
+ $author_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
27
+ $author = get_userdata( $author_id );
28
+ $post_id = $this->factory->post->create( array(
29
+ 'post_author' => $author_id,
30
+ 'post_status' => 'publish',
31
+ 'post_type' => 'post',
32
+ ) );
33
+ $this->_cap->add_coauthors( $post_id, array( $author->user_login ) );
34
+
35
+ $query = new WP_Query( array(
36
+ 'author' => $author_id,
37
+ ) );
38
+
39
+ $this->assertEquals( 1, count( $query->posts ) );
40
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
41
+ }
42
+
43
+ public function test__author_name_arg__user_is_post_author() {
44
+ $author_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
45
+ $author = get_userdata( $author_id );
46
+ $post_id = $this->factory->post->create( array(
47
+ 'post_author' => $author_id,
48
+ 'post_status' => 'publish',
49
+ 'post_type' => 'post',
50
+ ) );
51
+ $this->_cap->add_coauthors( $post_id, array( $author->user_login ) );
52
+
53
+ $query = new WP_Query( array(
54
+ 'author_name' => $author->user_login,
55
+ ) );
56
+
57
+ $this->assertEquals( 1, count( $query->posts ) );
58
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
59
+ }
60
+
61
+ public function test__author_name_arg__user_is_coauthor() {
62
+ $author1_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
63
+ $author1 = get_userdata( $author1_id );
64
+ $author2_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'superman' ) );
65
+ $author2 = get_userdata( $author2_id );
66
+
67
+ $post_id = $this->factory->post->create( array(
68
+ 'post_author' => $author1_id,
69
+ 'post_status' => 'publish',
70
+ 'post_type' => 'post',
71
+ ) );
72
+ $this->_cap->add_coauthors( $post_id, array( $author1->user_login, $author2->user_login ) );
73
+
74
+ $query = new WP_Query( array(
75
+ 'author_name' => $author2->user_login,
76
+ ) );
77
+
78
+ $this->assertEquals( 1, count( $query->posts ) );
79
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
80
+ }
81
+
82
+ public function test__author_arg__user_is_coauthor__author_arg() {
83
+ $author1_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
84
+ $author1 = get_userdata( $author1_id );
85
+ $author2_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'superman' ) );
86
+ $author2 = get_userdata( $author2_id );
87
+
88
+ $post_id = $this->factory->post->create( array(
89
+ 'post_author' => $author1_id,
90
+ 'post_status' => 'publish',
91
+ 'post_type' => 'post',
92
+ ) );
93
+ $this->_cap->add_coauthors( $post_id, array( $author1->user_login, $author2->user_login ) );
94
+
95
+ $query = new WP_Query( array(
96
+ 'author' => $author2_id,
97
+ ) );
98
+
99
+ $this->assertEquals( 1, count( $query->posts ) );
100
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
101
+ }
102
+
103
+ public function test__author_name_arg_plus_tax_query__user_is_post_author() {
104
+ $author_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
105
+ $author = get_userdata( $author_id );
106
+ $post_id = $this->factory->post->create( array(
107
+ 'post_author' => $author_id,
108
+ 'post_status' => 'publish',
109
+ 'post_type' => 'post',
110
+ ) );
111
+ $this->_cap->add_coauthors( $post_id, array( $author->user_login ) );
112
+ wp_set_post_terms( $post_id, 'test', 'post_tag' );
113
+
114
+ $query = new WP_Query( array(
115
+ 'author_name' => $author->user_login,
116
+ 'tag' => 'test',
117
+ ) );
118
+
119
+ $this->assertEquals( 1, count( $query->posts ) );
120
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
121
+ }
122
+
123
+ public function tests__author_name_arg_plus_tax_query__is_coauthor() {
124
+ $author1_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'batman' ) );
125
+ $author1 = get_userdata( $author1_id );
126
+ $author2_id = $this->factory->user->create( array( 'role' => 'author', 'user_login' => 'superman' ) );
127
+ $author2 = get_userdata( $author2_id );
128
+
129
+ $post_id = $this->factory->post->create( array(
130
+ 'post_author' => $author1_id,
131
+ 'post_status' => 'publish',
132
+ 'post_type' => 'post',
133
+ ) );
134
+ $this->_cap->add_coauthors( $post_id, array( $author1->user_login, $author2->user_login ) );
135
+ wp_set_post_terms( $post_id, 'test', 'post_tag' );
136
+
137
+ $query = new WP_Query( array(
138
+ 'author_name' => $author2->user_login,
139
+ 'tag' => 'test',
140
+ ) );
141
+
142
+ $this->assertEquals( 1, count( $query->posts ) );
143
+ $this->assertEquals( $post_id, $query->posts[ 0 ]->ID );
144
+ }
145
+ }
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->assertArrayNotHasKey( $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->assertArrayNotHasKey( $this->editor1->user_login, $authors );
401
+ $this->assertArrayNotHasKey( '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->assertArrayNotHasKey( $this->editor1->user_login, $authors );
409
+ $this->assertArrayNotHasKey( '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->assertArrayNotHasKey( $this->editor1->user_login, $authors );
417
+ $this->assertArrayNotHasKey( '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->assertArrayNotHasKey( $this->editor1->user_login, $authors );
425
+ $this->assertArrayNotHasKey( '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_nicename );
446
+
447
+ $authors = $coauthors_plus->search_authors( '', $ignored_authors );
448
+
449
+ $this->assertNotEmpty( $authors );
450
+ $this->assertArrayNotHasKey( $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->assertArrayNotHasKey( $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_nicename, $author2->user_nicename ) );
465
+
466
+ $this->assertNotEmpty( $authors );
467
+ $this->assertArrayNotHasKey( $this->author1->user_login, $authors );
468
+ $this->assertArrayNotHasKey( $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_nicename );
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->assertArrayNotHasKey( $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 ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Test_Manage_CoAuthors extends CoAuthorsPlus_TestCase {
4
+
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
+
12
+ $post = array(
13
+ 'post_author' => $this->author1,
14
+ 'post_status' => 'publish',
15
+ 'post_content' => rand_str(),
16
+ 'post_title' => rand_str(),
17
+ 'post_type' => 'post',
18
+ );
19
+
20
+ $this->author1_post1 = wp_insert_post( $post );
21
+
22
+ $post = array(
23
+ 'post_author' => $this->author1,
24
+ 'post_status' => 'publish',
25
+ 'post_content' => rand_str(),
26
+ 'post_title' => rand_str(),
27
+ 'post_type' => 'post',
28
+ );
29
+
30
+ $this->author1_post2 = wp_insert_post( $post );
31
+
32
+ $page = array(
33
+ 'post_author' => $this->author1,
34
+ 'post_status' => 'publish',
35
+ 'post_content' => rand_str(),
36
+ 'post_title' => rand_str(),
37
+ 'post_type' => 'page',
38
+ );
39
+
40
+ $this->author1_page1 = wp_insert_post( $page );
41
+
42
+ $page = array(
43
+ 'post_author' => $this->author1,
44
+ 'post_status' => 'publish',
45
+ 'post_content' => rand_str(),
46
+ 'post_title' => rand_str(),
47
+ 'post_type' => 'page',
48
+ );
49
+
50
+ $this->author1_page2 = wp_insert_post( $page );
51
+ }
52
+
53
+ public function tearDown() {
54
+ parent::tearDown();
55
+ }
56
+
57
+ /**
58
+ * Test assigning a Co-Author to a post
59
+ */
60
+ public function test_add_coauthor_to_post() {
61
+ global $coauthors_plus;
62
+
63
+ $coauthors = get_coauthors( $this->author1_post1 );
64
+ $this->assertEquals( 1, count( $coauthors ) );
65
+
66
+ // append = true, should preserve order
67
+ $editor1 = get_user_by( 'id', $this->editor1 );
68
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), true );
69
+ $coauthors = get_coauthors( $this->author1_post1 );
70
+ $this->assertEquals( array( $this->author1, $this->editor1 ), wp_list_pluck( $coauthors, 'ID' ) );
71
+
72
+ // append = false, overrides existing authors
73
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), false );
74
+ $coauthors = get_coauthors( $this->author1_post1 );
75
+ $this->assertEquals( array( $this->editor1 ), wp_list_pluck( $coauthors, 'ID' ) );
76
+
77
+ }
78
+
79
+ /**
80
+ * When a co-author is assigned to a post, the post author value
81
+ * should be set appropriately
82
+ *
83
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/140
84
+ */
85
+ public function test_add_coauthor_updates_post_author() {
86
+ global $coauthors_plus;
87
+
88
+ // append = true, preserves existing post_author
89
+ $editor1 = get_user_by( 'id', $this->editor1 );
90
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), true );
91
+ $this->assertEquals( $this->author1, get_post( $this->author1_post1 )->post_author );
92
+
93
+ // append = false, overrides existing post_author
94
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ), false );
95
+ $this->assertEquals( $this->editor1, get_post( $this->author1_post1 )->post_author );
96
+
97
+ }
98
+
99
+ /**
100
+ * Post published count should default to 'post', but be filterable
101
+ *
102
+ * @see https://github.com/Automattic/Co-Authors-Plus/issues/170
103
+ */
104
+ public function test_post_publish_count_for_coauthor() {
105
+ global $coauthors_plus;
106
+
107
+ $editor1 = get_user_by( 'id', $this->editor1 );
108
+
109
+ /**
110
+ * Two published posts
111
+ */
112
+ $coauthors_plus->add_coauthors( $this->author1_post1, array( $editor1->user_login ) );
113
+ $coauthors_plus->add_coauthors( $this->author1_post2, array( $editor1->user_login ) );
114
+ $this->assertEquals( 2, count_user_posts( $editor1->ID ) );
115
+
116
+ /**
117
+ * One published page too, but no filter
118
+ */
119
+ $coauthors_plus->add_coauthors( $this->author1_page1, array( $editor1->user_login ) );
120
+ $this->assertEquals( 2, count_user_posts( $editor1->ID ) );
121
+
122
+ // Publish count to include posts and pages
123
+ $filter = function() {
124
+ return array( 'post', 'page' );
125
+ };
126
+ add_filter( 'coauthors_count_published_post_types', $filter );
127
+
128
+ /**
129
+ * Two published posts and pages
130
+ */
131
+ $coauthors_plus->add_coauthors( $this->author1_page2, array( $editor1->user_login ) );
132
+ $this->assertEquals( 4, count_user_posts( $editor1->ID ) );
133
+
134
+ // Publish count is just pages
135
+ remove_filter( 'coauthors_count_published_post_types', $filter );
136
+ $filter = function() {
137
+ return array( 'page' );
138
+ };
139
+ add_filter( 'coauthors_count_published_post_types', $filter );
140
+
141
+ /**
142
+ * Just one published page now for the editor
143
+ */
144
+ $author1 = get_user_by( 'id', $this->author1 );
145
+ $coauthors_plus->add_coauthors( $this->author1_page2, array( $author1->user_login ) );
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,1071 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ $authordata = $this->author1;
594
+
595
+ // Shows that it's necessary to set $authordata to $this->author1
596
+ $this->assertEquals( $authordata, $this->author1, 'Global $authordata not matching expected $this->author1.' );
597
+
598
+ $this->author1->type = 'guest-author';
599
+
600
+ $this->assertEquals( get_the_author_link(), coauthors_links_single( $this->author1 ), 'Co-Author link generation differs from Core author link one (without user_url)' );
601
+
602
+ wp_update_user( array( 'ID' => $this->author1->ID, 'user_url' => 'example.org' ) );
603
+ $authordata = get_userdata( $this->author1->ID ); // Because wp_update_user flushes cache, but does not update global var
604
+
605
+ $this->assertEquals( get_the_author_link(), coauthors_links_single( $this->author1 ), 'Co-Author link generation differs from Core author link one (with user_url)' );
606
+
607
+ $author_link = coauthors_links_single( $this->author1 );
608
+ $this->assertContains( get_the_author_meta( 'url' ), $author_link, 'Author url not found in link.' );
609
+ $this->assertContains( get_the_author(), $author_link, 'Author name not found in link.' );
610
+
611
+ // Here we are checking author name should not be more then one time.
612
+ // Asserting ">get_the_author()<" because "get_the_author()" can be multiple times like in href, title, etc.
613
+ $this->assertEquals( 1, substr_count( $author_link, '>' . get_the_author() . '<' ) );
614
+
615
+ // Restore global author data from backup.
616
+ $authordata = $authordata_backup;
617
+
618
+ // Restore global post from backup.
619
+ $post = $post_backup;
620
+ }
621
+
622
+ /**
623
+ * Checks single co-author when user's url is set and not a guest author.
624
+ *
625
+ * @covers ::coauthors_links_single()
626
+ */
627
+ public function test_coauthors_links_single_author_url_is_set() {
628
+
629
+ global $post, $authordata;
630
+
631
+ // Backing up global post.
632
+ $post_backup = $post;
633
+
634
+ $post = $this->post;
635
+
636
+ // Backing up global author data.
637
+ $authordata_backup = $authordata;
638
+
639
+ $user_id = $this->factory->user->create( array(
640
+ 'user_url' => 'example.org',
641
+ ) );
642
+ $user = get_user_by( 'id', $user_id );
643
+
644
+ $authordata = $user;
645
+ $author_link = coauthors_links_single( $user );
646
+
647
+ $this->assertContains( get_the_author_meta( 'url' ), $author_link, 'Author link not found.' );
648
+ $this->assertContains( get_the_author(), $author_link, 'Author name not found.' );
649
+
650
+ // Here we are checking author name should not be more then one time.
651
+ // Asserting ">get_the_author()<" because "get_the_author()" can be multiple times like in href, title, etc.
652
+ $this->assertEquals( 1, substr_count( $author_link, '>' . get_the_author() . '<' ) );
653
+
654
+ // Restore global author data from backup.
655
+ $authordata = $authordata_backup;
656
+
657
+ // Restore global post from backup.
658
+ $post = $post_backup;
659
+ }
660
+
661
+ /**
662
+ * Checks single co-author when user's website/url not exist.
663
+ *
664
+ * @covers ::coauthors_links_single()
665
+ */
666
+ public function test_coauthors_links_single_when_url_not_exist() {
667
+
668
+ global $post, $authordata;
669
+
670
+ // Backing up global post.
671
+ $post_backup = $post;
672
+
673
+ $post = $this->post;
674
+
675
+ // Backing up global author data.
676
+ $authordata_backup = $authordata;
677
+
678
+ $this->editor1->type = 'guest-author';
679
+
680
+ $author_link = coauthors_links_single( $this->editor1 );
681
+
682
+ $this->assertEquals( get_the_author(), $author_link );
683
+
684
+ $authordata = $this->author1;
685
+ $author_link = coauthors_links_single( $this->author1 );
686
+
687
+ $this->assertEquals( get_the_author(), $author_link );
688
+
689
+ // Restore global author data from backup.
690
+ $authordata = $authordata_backup;
691
+
692
+ // Restore global post from backup.
693
+ $post = $post_backup;
694
+ }
695
+
696
+ /**
697
+ * Checks co-authors IDs.
698
+ *
699
+ * @covers ::coauthors_ids()
700
+ * @covers ::coauthors__echo()
701
+ */
702
+ public function test_coauthors_ids() {
703
+
704
+ global $post, $coauthors_plus;
705
+
706
+ // Backing up global post.
707
+ $post_backup = $post;
708
+
709
+ $post = $this->post;
710
+
711
+ $ids = coauthors_ids( null, null, null, null, false );
712
+
713
+ $this->assertEquals( $this->author1->ID, $ids );
714
+
715
+ $ids = coauthors_ids( '</span><span>', '</span><span>', '<span>', '</span>', false );
716
+
717
+ $this->assertEquals( '<span>' . $this->author1->ID . '</span>', $ids );
718
+
719
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
720
+
721
+ $ids = coauthors_ids( null, null, null, null, false );
722
+
723
+ $this->assertEquals( $this->author1->ID . ' and ' . $this->editor1->ID, $ids );
724
+
725
+ $ids = coauthors_ids( '</span><span>', '</span><span>', '<span>', '</span>', false );
726
+
727
+ $this->assertEquals( '<span>' . $this->author1->ID . '</span><span>' . $this->editor1->ID . '</span>', $ids );
728
+
729
+ // Restore global post from backup.
730
+ $post = $post_backup;
731
+ }
732
+
733
+ /**
734
+ * Checks co-authors meta.
735
+ *
736
+ * @covers ::get_the_coauthor_meta()
737
+ */
738
+ public function test_get_the_coauthor_meta() {
739
+
740
+ global $post;
741
+
742
+ // Backing up global post.
743
+ $post_backup = $post;
744
+
745
+ $this->assertEmpty( get_the_coauthor_meta( '' ) );
746
+
747
+ update_user_meta( $this->author1->ID, 'meta_key', 'meta_value' );
748
+
749
+ $this->assertEmpty( get_the_coauthor_meta( 'meta_key' ) );
750
+
751
+ $post = $this->post;
752
+ $meta = get_the_coauthor_meta( 'meta_key' );
753
+
754
+ $this->assertEquals( 'meta_value', $meta[ $this->author1->ID ] );
755
+
756
+ // Restore global post from backup.
757
+ $post = $post_backup;
758
+ }
759
+
760
+ /**
761
+ * Checks all the co-authors of the blog with default args.
762
+ *
763
+ * @covers ::coauthors_wp_list_authors()
764
+ */
765
+ public function test_coauthors_wp_list_authors_for_default_args() {
766
+
767
+ global $coauthors_plus;
768
+
769
+ $args = array(
770
+ 'echo' => false,
771
+ );
772
+
773
+ $coauthors = coauthors_wp_list_authors( $args );
774
+
775
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $coauthors, 'Author link not found.' );
776
+ $this->assertContains( $this->author1->display_name, $coauthors, 'Author name not found.' );
777
+
778
+ $coauthors = coauthors_wp_list_authors( $args );
779
+
780
+ $this->assertNotContains( 'href="' . get_author_posts_url( $this->editor1->ID, $this->editor1->user_nicename ) . '"', $coauthors );
781
+ $this->assertNotContains( $this->editor1->display_name, $coauthors );
782
+
783
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
784
+
785
+ $coauthors = coauthors_wp_list_authors( $args );
786
+
787
+ $this->assertContains( 'href="' . get_author_posts_url( $this->author1->ID, $this->author1->user_nicename ) . '"', $coauthors, 'Main author link not found.' );
788
+ $this->assertContains( $this->author1->display_name, $coauthors, 'Main author name not found.' );
789
+
790
+ // Here we are checking author name should not be more then one time.
791
+ // Asserting ">{$this->author1->display_name}<" because "$this->author1->display_name" can be multiple times like in href, title, etc.
792
+ $this->assertEquals( 1, substr_count( $coauthors, ">{$this->author1->display_name}<" ) );
793
+
794
+ $this->assertContains( '</li><li>', $coauthors, 'Coauthors name separator is not matched.' );
795
+ $this->assertContains( 'href="' . get_author_posts_url( $this->editor1->ID, $this->editor1->user_nicename ) . '"', $coauthors, 'Coauthor link not found.' );
796
+ $this->assertContains( $this->editor1->display_name, $coauthors, 'Coauthor name not found.' );
797
+
798
+ // Here we are checking editor name should not be more then one time.
799
+ // Asserting ">{$this->editor1->display_name}<" because "$this->editor1->display_name" can be multiple times like in href, title, etc.
800
+ $this->assertEquals( 1, substr_count( $coauthors, ">{$this->editor1->display_name}<" ) );
801
+ }
802
+
803
+ /**
804
+ * Checks all the co-authors of the blog with optioncount option.
805
+ *
806
+ * @covers ::coauthors_wp_list_authors()
807
+ */
808
+ public function test_coauthors_wp_list_authors_for_optioncount() {
809
+
810
+ $this->assertContains( '(' . count_user_posts( $this->author1->ID ) . ')', coauthors_wp_list_authors( array(
811
+ 'echo' => false,
812
+ 'optioncount' => true,
813
+ ) ) );
814
+ }
815
+
816
+ /**
817
+ * Checks all the co-authors of the blog with show_fullname option.
818
+ *
819
+ * @covers ::coauthors_wp_list_authors()
820
+ */
821
+ public function test_coauthors_wp_list_authors_for_show_fullname() {
822
+
823
+ $args = array(
824
+ 'echo' => false,
825
+ 'show_fullname' => true,
826
+ );
827
+
828
+ $this->assertContains( $this->author1->display_name, coauthors_wp_list_authors( $args ) );
829
+
830
+ $user = $this->factory->user->create_and_get( array(
831
+ 'first_name' => 'First',
832
+ 'last_name' => 'Last',
833
+ ) );
834
+
835
+ $this->factory->post->create( array(
836
+ 'post_author' => $user->ID,
837
+ ) );
838
+
839
+ $this->assertContains( "{$user->user_firstname} {$user->user_lastname}", coauthors_wp_list_authors( $args ) );
840
+ }
841
+
842
+ /**
843
+ * Checks all the co-authors of the blog with hide_empty option.
844
+ *
845
+ * @covers ::coauthors_wp_list_authors()
846
+ */
847
+ public function test_coauthors_wp_list_authors_for_hide_empty() {
848
+
849
+ global $coauthors_plus;
850
+
851
+ $coauthors_plus->guest_authors->create( array(
852
+ 'user_login' => 'author2',
853
+ 'display_name' => 'author2',
854
+ ) );
855
+
856
+ $this->assertContains( 'author2', coauthors_wp_list_authors( array(
857
+ 'echo' => false,
858
+ 'hide_empty' => false,
859
+ ) ) );
860
+ }
861
+
862
+ /**
863
+ * Checks all the co-authors of the blog with feed option.
864
+ *
865
+ * @covers ::coauthors_wp_list_authors()
866
+ */
867
+ public function test_coauthors_wp_list_authors_for_feed() {
868
+
869
+ $feed_text = 'link to feed';
870
+ $coauthors = coauthors_wp_list_authors( array(
871
+ 'echo' => false,
872
+ 'feed' => $feed_text,
873
+ ) );
874
+
875
+ $this->assertContains( esc_url( get_author_feed_link( $this->author1->ID ) ), $coauthors );
876
+ $this->assertContains( $feed_text, $coauthors );
877
+ }
878
+
879
+ /**
880
+ * Checks all the co-authors of the blog with feed_image option.
881
+ *
882
+ * @covers ::coauthors_wp_list_authors()
883
+ */
884
+ public function test_coauthors_wp_list_authors_for_feed_image() {
885
+
886
+ $feed_image = WP_TESTS_DOMAIN . '/path/to/a/graphic.png';
887
+ $coauthors = coauthors_wp_list_authors( array(
888
+ 'echo' => false,
889
+ 'feed_image' => $feed_image,
890
+ ) );
891
+
892
+ $this->assertContains( esc_url( get_author_feed_link( $this->author1->ID ) ), $coauthors );
893
+ $this->assertContains( $feed_image, $coauthors );
894
+ }
895
+
896
+ /**
897
+ * Checks all the co-authors of the blog with feed_type option.
898
+ *
899
+ * @covers ::coauthors_wp_list_authors()
900
+ */
901
+ public function test_coauthors_wp_list_authors_for_feed_type() {
902
+
903
+ $feed_type = 'atom';
904
+ $feed_text = 'link to feed';
905
+ $coauthors = coauthors_wp_list_authors( array(
906
+ 'echo' => false,
907
+ 'feed_type' => $feed_type,
908
+ 'feed' => $feed_text,
909
+ ) );
910
+
911
+ $this->assertContains( esc_url( get_author_feed_link( $this->author1->ID, $feed_type ) ), $coauthors );
912
+ $this->assertContains( $feed_type, $coauthors );
913
+ $this->assertContains( $feed_text, $coauthors );
914
+ }
915
+
916
+ /**
917
+ * Checks all the co-authors of the blog with style option.
918
+ *
919
+ * @covers ::coauthors_wp_list_authors()
920
+ */
921
+ public function test_coauthors_wp_list_authors_for_style() {
922
+
923
+ $coauthors = coauthors_wp_list_authors( array(
924
+ 'echo' => false,
925
+ 'style' => 'none',
926
+ ) );
927
+
928
+ $this->assertNotContains( '<li>', $coauthors );
929
+ $this->assertNotContains( '</li>', $coauthors );
930
+ }
931
+
932
+ /**
933
+ * Checks all the co-authors of the blog with html option.
934
+ *
935
+ * @covers ::coauthors_wp_list_authors()
936
+ */
937
+ public function test_coauthors_wp_list_authors_for_html() {
938
+
939
+ global $coauthors_plus;
940
+
941
+ $args = array(
942
+ 'echo' => false,
943
+ 'html' => false,
944
+ );
945
+
946
+ $this->assertEquals( $this->author1->display_name, coauthors_wp_list_authors( $args ) );
947
+
948
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $this->editor1->user_login ), true );
949
+
950
+ $this->assertEquals( "{$this->author1->display_name}, {$this->editor1->display_name}", coauthors_wp_list_authors( $args ) );
951
+ }
952
+
953
+ /**
954
+ * Checks all the co-authors of the blog with guest_authors_only option.
955
+ *
956
+ * @covers ::coauthors_wp_list_authors()
957
+ */
958
+ public function test_coauthors_wp_list_authors_for_guest_authors_only() {
959
+
960
+ global $coauthors_plus;
961
+
962
+ $args = array(
963
+ 'echo' => false,
964
+ 'guest_authors_only' => true,
965
+ );
966
+
967
+ $this->assertEmpty( coauthors_wp_list_authors( $args ) );
968
+
969
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
970
+ 'user_login' => 'author2',
971
+ 'display_name' => 'author2',
972
+ ) );
973
+
974
+ $this->assertEmpty( coauthors_wp_list_authors( $args ) );
975
+
976
+ $guest_author = $coauthors_plus->guest_authors->get_guest_author_by( 'id', $guest_author_id );
977
+
978
+ $coauthors_plus->add_coauthors( $this->post->ID, array( $guest_author->user_login ), true );
979
+
980
+ $this->assertContains( $guest_author->display_name, coauthors_wp_list_authors( $args ) );
981
+ }
982
+
983
+ /**
984
+ * Checks co-author's avatar.
985
+ *
986
+ * @covers ::coauthors_get_avatar()
987
+ */
988
+ public function test_coauthors_get_avatar_default() {
989
+
990
+ $this->assertEmpty( coauthors_get_avatar( $this->author1->ID ) );
991
+ $this->assertEquals( preg_match( "|^<img alt='[^']*' src='[^']*' srcset='[^']*' class='[^']*' height='[^']*' width='[^']*' />$|", coauthors_get_avatar( $this->author1 ) ), 1 );
992
+ }
993
+
994
+ /**
995
+ * Checks co-author's avatar when author is a guest author.
996
+ *
997
+ * @covers ::coauthors_get_avatar()
998
+ */
999
+ public function test_coauthors_get_avatar_when_guest_author() {
1000
+
1001
+ global $coauthors_plus;
1002
+
1003
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
1004
+ 'user_login' => 'author2',
1005
+ 'display_name' => 'author2',
1006
+ ) );
1007
+
1008
+ $guest_author = $coauthors_plus->guest_authors->get_guest_author_by( 'id', $guest_author_id );
1009
+
1010
+ $this->assertEquals( preg_match( "|^<img alt='[^']*' src='[^']*' srcset='[^']*' class='[^']*' height='[^']*' width='[^']*' />$|", coauthors_get_avatar( $guest_author ) ), 1 );
1011
+
1012
+ $filename = rand_str() . '.jpg';
1013
+ $contents = rand_str();
1014
+ $upload = wp_upload_bits( $filename, null, $contents );
1015
+
1016
+ $this->assertTrue( empty( $upload['error'] ) );
1017
+
1018
+ $attachment_id = $this->_make_attachment( $upload );
1019
+
1020
+ set_post_thumbnail( $guest_author->ID, $attachment_id );
1021
+
1022
+ $avatar = coauthors_get_avatar( $guest_author );
1023
+ $attachment_url = wp_get_attachment_url( $attachment_id );
1024
+
1025
+ $this->assertContains( $filename, $avatar );
1026
+ $this->assertContains( 'src="' . $attachment_url . '"', $avatar );
1027
+ }
1028
+
1029
+ /**
1030
+ * Checks co-author's avatar when user's email is not set somehow.
1031
+ *
1032
+ * @covers ::coauthors_get_avatar()
1033
+ */
1034
+ public function test_coauthors_get_avatar_when_user_email_not_set() {
1035
+
1036
+ global $coauthors_plus;
1037
+
1038
+ $guest_author_id = $coauthors_plus->guest_authors->create( array(
1039
+ 'user_login' => 'author2',
1040
+ 'display_name' => 'author2',
1041
+ ) );
1042
+
1043
+ $guest_author = $coauthors_plus->guest_authors->get_guest_author_by( 'id', $guest_author_id );
1044
+
1045
+ unset( $guest_author->user_email );
1046
+
1047
+ $this->assertEmpty( coauthors_get_avatar( $guest_author ) );
1048
+ }
1049
+
1050
+ /**
1051
+ * Checks co-author's avatar with size.
1052
+ *
1053
+ * @covers ::coauthors_get_avatar()
1054
+ */
1055
+ public function test_coauthors_get_avatar_size() {
1056
+
1057
+ $size = '100';
1058
+ $this->assertEquals( preg_match( "|^<img .*height='$size'.*width='$size'|", coauthors_get_avatar( $this->author1, $size ) ), 1 );
1059
+ }
1060
+
1061
+ /**
1062
+ * Checks co-author's avatar with alt.
1063
+ *
1064
+ * @covers ::coauthors_get_avatar()
1065
+ */
1066
+ public function test_coauthors_get_avatar_alt() {
1067
+
1068
+ $alt = 'Test';
1069
+ $this->assertEquals( preg_match( "|^<img alt='$alt'|", coauthors_get_avatar( $this->author1, 96, '', $alt ) ), 1 );
1070
+ }
1071
+ }
upgrade.php CHANGED
@@ -17,32 +17,29 @@ function coauthors_plus_upgrade_20() {
17
  // Get all posts with meta_key _coauthor
18
  $all_posts = get_posts( array( 'numberposts' => '-1', 'meta_key' => '_coauthor' ) );
19
 
20
- if ( is_array( $all_posts ) ) {
21
- foreach ( $all_posts as $single_post ) {
22
-
23
- // reset execution time limit
24
- set_time_limit( 60 );
25
-
26
- // create new array
27
- $coauthors = array();
28
- // get author id -- try to use get_profile
29
- $coauthor = get_user_by( 'id', (int) $single_post->post_author );
30
- if ( is_object( $coauthor ) ) {
31
- $coauthors[] = $coauthor->user_login;
32
- }
33
- // get coauthors id
34
- $legacy_coauthors = get_post_meta( $single_post->ID, '_coauthor' );
35
-
36
- if ( is_array( $legacy_coauthors ) ) {
37
- foreach ( $legacy_coauthors as $legacy_coauthor ) {
38
- $legacy_coauthor_login = get_user_by( 'id', (int) $legacy_coauthor );
39
- if ( is_object( $legacy_coauthor_login ) && ! in_array( $legacy_coauthor_login->user_login, $coauthors ) ) {
40
- $coauthors[] = $legacy_coauthor_login->user_login;
41
- }
42
  }
43
  }
44
- $coauthors_plus->add_coauthors( $single_post->ID, $coauthors );
45
-
46
  }
 
47
  }
48
  }
17
  // Get all posts with meta_key _coauthor
18
  $all_posts = get_posts( array( 'numberposts' => '-1', 'meta_key' => '_coauthor' ) );
19
 
20
+
21
+ foreach ( $all_posts as $single_post ) {
22
+ // reset execution time limit
23
+ set_time_limit( 60 );
24
+
25
+ // create new array
26
+ $coauthors = array();
27
+ // get author id -- try to use get_profile
28
+ $coauthor = get_user_by( 'id', (int) $single_post->post_author );
29
+ if ( is_object( $coauthor ) ) {
30
+ $coauthors[] = $coauthor->user_login;
31
+ }
32
+ // get coauthors id
33
+ $legacy_coauthors = get_post_meta( $single_post->ID, '_coauthor' );
34
+
35
+ if ( is_array( $legacy_coauthors ) ) {
36
+ foreach ( $legacy_coauthors as $legacy_coauthor ) {
37
+ $legacy_coauthor_login = get_user_by( 'id', (int) $legacy_coauthor );
38
+ if ( is_object( $legacy_coauthor_login ) && ! in_array( $legacy_coauthor_login->user_login, $coauthors ) ) {
39
+ $coauthors[] = $legacy_coauthor_login->user_login;
 
 
40
  }
41
  }
 
 
42
  }
43
+ $coauthors_plus->add_coauthors( $single_post->ID, $coauthors );
44
  }
45
  }