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,\}#x27;) ]; 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 @@