diff --git a/composer.lock b/composer.lock index 3a68d43b..f7d64a00 100644 --- a/composer.lock +++ b/composer.lock @@ -107,16 +107,16 @@ }, { "name": "publishpress/wordpress-version-notices", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/publishpress/WordPress-Version-Notices.git", - "reference": "ba2b8eba33577d8c9351a9437e09af0e8f601a2c" + "reference": "b710c9d4ddf15384546d2f2209554bfdb10c5339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/publishpress/WordPress-Version-Notices/zipball/ba2b8eba33577d8c9351a9437e09af0e8f601a2c", - "reference": "ba2b8eba33577d8c9351a9437e09af0e8f601a2c", + "url": "https://api.github.com/repos/publishpress/WordPress-Version-Notices/zipball/b710c9d4ddf15384546d2f2209554bfdb10c5339", + "reference": "b710c9d4ddf15384546d2f2209554bfdb10c5339", "shasum": "" }, "require": { @@ -124,7 +124,7 @@ "pimple/pimple": "^3" }, "require-dev": { - "lucatume/wp-browser": "^2.2" + "lucatume/wp-browser": "^2.4" }, "type": "library", "autoload": { @@ -145,7 +145,7 @@ } ], "description": "Library for displaying version notices for Pro plugins in WordPress.", - "time": "2020-04-08T13:59:35+00:00" + "time": "2020-08-11T03:28:34+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1090,16 +1090,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51" + "reference": "ebd27a9866ae8254e873866f795491f02418c5a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51", - "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ebd27a9866ae8254e873866f795491f02418c5a5", + "reference": "ebd27a9866ae8254e873866f795491f02418c5a5", "shasum": "" }, "require": { @@ -1130,7 +1130,7 @@ "Xdebug", "performance" ], - "time": "2020-06-04T11:16:35+00:00" + "time": "2020-08-19T10:27:58+00:00" }, { "name": "consolidation/annotated-command", @@ -2312,7 +2312,7 @@ }, { "name": "illuminate/contracts", - "version": "v7.23.2", + "version": "v7.25.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -2356,16 +2356,16 @@ }, { "name": "illuminate/support", - "version": "v7.23.2", + "version": "v7.25.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "a73fabea211d9b26b76c64a925db4b660d150a88" + "reference": "9b0c0af8d2dd1a729f6337d0ed5c81a241ea43ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/a73fabea211d9b26b76c64a925db4b660d150a88", - "reference": "a73fabea211d9b26b76c64a925db4b660d150a88", + "url": "https://api.github.com/repos/illuminate/support/zipball/9b0c0af8d2dd1a729f6337d0ed5c81a241ea43ab", + "reference": "9b0c0af8d2dd1a729f6337d0ed5c81a241ea43ab", "shasum": "" }, "require": { @@ -2414,7 +2414,7 @@ ], "description": "The Illuminate Support package.", "homepage": "https://laravel.com", - "time": "2020-08-06T13:54:33+00:00" + "time": "2020-08-10T13:58:23+00:00" }, { "name": "justinrainbow/json-schema", @@ -3181,16 +3181,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.0", + "version": "5.2.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "3170448f5769fe19f456173d833734e0ff1b84df" + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/3170448f5769fe19f456173d833734e0ff1b84df", - "reference": "3170448f5769fe19f456173d833734e0ff1b84df", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", "shasum": "" }, "require": { @@ -3229,7 +3229,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-07-20T20:05:34+00:00" + "time": "2020-08-15T11:14:08+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -3721,6 +3721,7 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2020-08-04T08:28:15+00:00" }, { @@ -4053,11 +4054,11 @@ }, { "name": "publishpress/publishpress-plugin-builder", - "version": "1.2.2", + "version": "1.2.4", "source": { "type": "git", "url": "https://github.com/publishpress/PublishPress-Plugin-Builder", - "reference": "2111eb9b5a27809a911c3b9f34a6a0cfbac5436c" + "reference": "2dee88930e6a3a2991d48e99074bd9e1ee984601" }, "require": { "consolidation/robo": "^2.0", @@ -4088,7 +4089,7 @@ } ], "description": "Robo tasks for building WordPress plugins", - "time": "2020-08-05T19:47:09+00:00" + "time": "2020-08-13T20:02:22+00:00" }, { "name": "publishpress/wp-browser", @@ -4640,6 +4641,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", + "abandoned": true, "time": "2020-02-08T06:07:58+00:00" }, { @@ -5028,16 +5030,16 @@ }, { "name": "seld/jsonlint", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "ff2aa5420bfbc296cf6a0bc785fa5b35736de7c1" + "reference": "3d5eb71705adfa34bd34b993400622932b2f62fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/ff2aa5420bfbc296cf6a0bc785fa5b35736de7c1", - "reference": "ff2aa5420bfbc296cf6a0bc785fa5b35736de7c1", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/3d5eb71705adfa34bd34b993400622932b2f62fd", + "reference": "3d5eb71705adfa34bd34b993400622932b2f62fd", "shasum": "" }, "require": { @@ -5073,7 +5075,7 @@ "parser", "validator" ], - "time": "2020-04-30T19:05:18+00:00" + "time": "2020-08-13T09:07:59+00:00" }, { "name": "seld/phar-utils", @@ -5121,16 +5123,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.5", + "version": "3.5.6", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6" + "reference": "e97627871a7eab2f70e59166072a6b767d5834e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6", - "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/e97627871a7eab2f70e59166072a6b767d5834e0", + "reference": "e97627871a7eab2f70e59166072a6b767d5834e0", "shasum": "" }, "require": { @@ -5168,7 +5170,7 @@ "phpcs", "standards" ], - "time": "2020-04-17T01:09:41+00:00" + "time": "2020-08-10T04:50:15+00:00" }, { "name": "symfony/browser-kit", diff --git a/publishpress-authors.php b/publishpress-authors.php index 65d3a65a..2c66bafa 100644 --- a/publishpress-authors.php +++ b/publishpress-authors.php @@ -2,10 +2,10 @@ /** * Plugin Name: PublishPress Authors * Plugin URI: https://wordpress.org/plugins/publishpress-authors/ - * Description: Add support for multiple authors + * Description: PublishPress Authors allows you to add multiple authors and guest authors to WordPress posts * Author: PublishPress * Author URI: https://publishpress.com - * Version: 3.5.0 + * Version: 3.5.1 * Text Domain: publishpress-authors * * ------------------------------------------------------------------------------ diff --git a/readme.txt b/readme.txt index f5dd2dbf..581941fc 100644 --- a/readme.txt +++ b/readme.txt @@ -6,8 +6,8 @@ Author URI: https://publishpress.com Tags: multiple authors, authors, guest authors, author fields, author layouts Requires at least: 4.7 Requires PHP: 5.6 -Tested up to: 5.4 -Stable tag: 3.5.0 +Tested up to: 5.5 +Stable tag: 3.5.1 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -127,6 +127,16 @@ There are two ways to install the PublishPress Authors plugin: The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning v2.0.0](https://semver.org/spec/v2.0.0.html). += [3.5.1] - 2020-08-20 = + +* Fixed: Avoid warnings regarding constants already defined; +* Fixed: Fixed the cache for the get_multiple_authors function for archive pages, #190; +* Fixed: Fixed fatal error Object of class WP_Error could not be converted to string, #182; +* Fixed: Fixed the value for $author->display_name which was returning the value from the user object instead of the custom value set for the author, #183; +* Fixed: Fixed Plugin::filter_user_has_cap() is passing a param to Util::get_current_post_type() which doesn't support params, #187; +* Fixed: Fixed Plugin::filter_user_has_cap() to use the correct user, not the current one, #186; +* Fixed: Removed leftovers from the deprecated capability: ppma_edit_orphan_post, #193; + = [3.5.0] - 2020-08-06 = * Added: Added a new widget to display all the authors, #76; diff --git a/src/core/Classes/Installer.php b/src/core/Classes/Installer.php index fe9b6854..c3b9714f 100644 --- a/src/core/Classes/Installer.php +++ b/src/core/Classes/Installer.php @@ -160,7 +160,6 @@ public static function add_author_term_for_posts() private static function add_capabilities() { $role = get_role('administrator'); - $role->add_cap('ppma_edit_orphan_post'); $role->add_cap('ppma_manage_authors'); $role->add_cap('manage_options'); } diff --git a/src/core/Classes/Legacy/Util.php b/src/core/Classes/Legacy/Util.php index b78eece9..9168aa32 100644 --- a/src/core/Classes/Legacy/Util.php +++ b/src/core/Classes/Legacy/Util.php @@ -15,37 +15,72 @@ class Util * Checks for the current post type * * @return string|null $post_type The post type we've found, or null if no post type + * + * @deprecated getCurrentPostType */ public static function get_current_post_type() + { + return static::getCurrentPostType(); + } + + /** + * Checks for the current post type + * + * @return string|null $post_type The post type we've found, or null if no post type + */ + public static function getCurrentPostType() { global $post, $typenow, $pagenow, $current_screen; - // get_post() needs a variable $post_id = isset($_REQUEST['post']) ? (int)$_REQUEST['post'] : false; + $post_type = null; + if ($post && $post->post_type) { - $post_type = $post->post_type; + $post_type = static::getPostPostType($post); } elseif ($typenow) { $post_type = $typenow; } elseif ($current_screen && !empty($current_screen->post_type)) { $post_type = $current_screen->post_type; - } elseif (isset($_REQUEST['post_type'])) { + } elseif (isset($_REQUEST['post_type']) && !empty($_REQUEST['post_type'])) { $post_type = sanitize_key($_REQUEST['post_type']); - } elseif ('post.php' == $pagenow - && $post_id - && !empty(get_post($post_id)->post_type)) { - $post_type = get_post($post_id)->post_type; + } elseif ('post.php' == $pagenow && !empty($post_id)) { + $post_type = static::getPostPostType($post_id); } elseif ('edit.php' == $pagenow && empty($_REQUEST['post_type'])) { $post_type = 'post'; } elseif (self::isAuthor()) { $post_type = 'post'; - } else { - $post_type = null; } return $post_type; } + /** + * @param \WP_Post|int $postOrPostId + * + * @return string|false + */ + public static function getPostPostType($postOrPostId) + { + $post = null; + + if (is_numeric($postOrPostId)) { + $postOrPostId = (int)$postOrPostId; + + if (!empty($postOrPostId)) { + $post = get_post($postOrPostId); + } + } else { + $post = $postOrPostId; + } + + if (!$post instanceof \WP_Post) { + return false; + } + + return $post->post_type; + } + /** * @return bool|void */ diff --git a/src/core/Classes/Objects/Author.php b/src/core/Classes/Objects/Author.php index cca57148..f152b593 100644 --- a/src/core/Classes/Objects/Author.php +++ b/src/core/Classes/Objects/Author.php @@ -171,6 +171,8 @@ public static function create_from_user($user) return false; } + $author->userObject = $user; + self::update_author_from_user($author->term_id, $user->ID); return $author; @@ -430,11 +432,12 @@ public function __get($attribute) break; case 'name': - if (!$this->is_guest()) { + $return = get_term_field('name', $this->term_id, 'author', 'raw'); + + if (empty($return) && !$this->is_guest()) { $return = $this->get_user_object()->display_name; - } else { - $return = get_term_field('name', $this->term_id, 'author', 'raw'); } + break; case 'slug': @@ -456,6 +459,19 @@ public function __get($attribute) } } + if (is_wp_error($return)) { + $return = false; + + error_log( + sprintf( + '[PublishPress Authors] Error found while getting author\'s %s attribute (term_id = %d): %s', + $attribute, + $this->term_id, + $return->get_error_message() + ) + ); + } + $return = apply_filters('publishpress_authors_author_attribute', $return, $this->term_id, $attribute); return $return; diff --git a/src/core/Classes/Query.php b/src/core/Classes/Query.php index 826168bb..c6fc574e 100644 --- a/src/core/Classes/Query.php +++ b/src/core/Classes/Query.php @@ -150,11 +150,6 @@ public static function filter_posts_where($where, $query) $where = preg_replace($regex, '(' . $maybe_both_query . ' ' . $terms_implode . ')', $where, -1); } - // Allow users to edit orphan posts. - if (current_user_can('ppma_edit_orphan_post')) { - $where .= " OR (post_author = 0 && {$wpdb->posts}.post_type = 'post' && {$wpdb->posts}.post_status IN ('publish', 'private'))"; - } - return $where; } diff --git a/src/core/Classes/Utils.php b/src/core/Classes/Utils.php index d84fe091..3e585cc9 100644 --- a/src/core/Classes/Utils.php +++ b/src/core/Classes/Utils.php @@ -381,10 +381,6 @@ public static function current_user_can_set_authors($post = null) $can_set_authors = isset($current_user->allcaps['edit_others_posts']) ? $current_user->allcaps['edit_others_posts'] : false; - if (!$can_set_authors) { - $can_set_authors = isset($current_user->allcaps['ppma_edit_orphan_post']) ? $current_user->allcaps['ppma_edit_orphan_post'] : false; - } - return apply_filters('coauthors_plus_edit_authors', $can_set_authors); } diff --git a/src/core/Plugin.php b/src/core/Plugin.php index a9e3b049..de5cc790 100644 --- a/src/core/Plugin.php +++ b/src/core/Plugin.php @@ -73,7 +73,7 @@ public function __construct() add_filter('get_authornumposts', [$this, 'filter_count_author_posts'], 10, 2); // Filter to allow coauthors to edit posts - add_filter('user_has_cap', [$this, 'filter_user_has_cap'], 10, 3); + add_filter('user_has_cap', [$this, 'filter_user_has_cap'], 10, 4); // Restricts WordPress from blowing away term order on bulk edit add_filter('wp_get_object_terms', [$this, 'filter_wp_get_object_terms'], 10, 4); @@ -1332,13 +1332,14 @@ public function filter_views($views) /** * Allows coauthors to edit the post they're coauthors of */ - public function filter_user_has_cap($allcaps, $caps, $args) + public function filter_user_has_cap($allcaps, $caps, $args, $user) { $cap = $args[0]; - $user_id = isset($args[1]) ? $args[1] : 0; $post_id = isset($args[2]) ? $args[2] : 0; - $obj = get_post_type_object(Util::get_current_post_type($post_id)); + $postType = empty($post_id) ? Util::getCurrentPostType() : Util::getPostPostType($post_id); + $obj = get_post_type_object($postType); + if (!$obj || 'revision' == $obj->name) { return $allcaps; } @@ -1356,26 +1357,16 @@ public function filter_user_has_cap($allcaps, $caps, $args) return $allcaps; } - $allowEdit = is_multiple_author_for_post($user_id, $post_id); - - // Not an author, does the post has an author? If not, can we edit it? - if (!$allowEdit) { - $post_authors = get_multiple_authors($post_id); - - if (empty($post_authors) && isset($allcaps['ppma_edit_orphan_post']) && $allcaps['ppma_edit_orphan_post']) { - $allowEdit = true; - } - } + $allowEdit = is_multiple_author_for_post($user->ID, $post_id); if ($allowEdit) { - $current_user = wp_get_current_user(); $post_status = get_post_status($post_id); if ('publish' == $post_status && - (isset($obj->cap->edit_published_posts) && !empty($current_user->allcaps[$obj->cap->edit_published_posts]))) { + (isset($obj->cap->edit_published_posts) && !empty($user->allcaps[$obj->cap->edit_published_posts]))) { $allcaps[$obj->cap->edit_published_posts] = true; } elseif ('private' == $post_status && - (isset($obj->cap->edit_private_posts) && !empty($current_user->allcaps[$obj->cap->edit_private_posts]))) { + (isset($obj->cap->edit_private_posts) && !empty($user->allcaps[$obj->cap->edit_private_posts]))) { $allcaps[$obj->cap->edit_private_posts] = true; } diff --git a/src/defines.php b/src/defines.php index 2d6e7a2c..cacd0a62 100644 --- a/src/defines.php +++ b/src/defines.php @@ -11,13 +11,15 @@ defined('ABSPATH') or die('No direct script access allowed.'); -define('PP_AUTHORS_VERSION', '3.5.0'); -define('PP_AUTHORS_FILE', 'publishpress-authors/publishpress-authors.php'); -define('PP_AUTHORS_BASE_PATH', plugin_dir_path(realpath(__DIR__ . '/../publishpress-authors.php'))); -define('PP_AUTHORS_SRC_PATH', PP_AUTHORS_BASE_PATH . 'src/'); -define('PP_AUTHORS_MODULES_PATH', PP_AUTHORS_SRC_PATH . 'modules/'); -define('PP_AUTHORS_TWIG_PATH', PP_AUTHORS_SRC_PATH . 'twig/'); -define('PP_AUTHORS_VENDOR_PATH', PP_AUTHORS_BASE_PATH . 'vendor/'); -define('PP_AUTHORS_URL', plugins_url('/', PP_AUTHORS_BASE_PATH . 'publishpress-authors.php')); -define('PP_AUTHORS_ASSETS_URL', plugins_url('/src/assets/', PP_AUTHORS_SRC_PATH)); -define('PP_AUTHORS_AUTOLOAD_CLASS_NAME', 'ComposerStaticInit861037e2d826162de71f57dffe180138'); +if (!defined('PP_AUTHORS_VERSION')) { + define('PP_AUTHORS_VERSION', '3.5.1'); + define('PP_AUTHORS_FILE', 'publishpress-authors/publishpress-authors.php'); + define('PP_AUTHORS_BASE_PATH', plugin_dir_path(realpath(__DIR__ . '/../publishpress-authors.php'))); + define('PP_AUTHORS_SRC_PATH', PP_AUTHORS_BASE_PATH . 'src/'); + define('PP_AUTHORS_MODULES_PATH', PP_AUTHORS_SRC_PATH . 'modules/'); + define('PP_AUTHORS_TWIG_PATH', PP_AUTHORS_SRC_PATH . 'twig/'); + define('PP_AUTHORS_VENDOR_PATH', PP_AUTHORS_BASE_PATH . 'vendor/'); + define('PP_AUTHORS_URL', plugins_url('/', PP_AUTHORS_BASE_PATH . 'publishpress-authors.php')); + define('PP_AUTHORS_ASSETS_URL', plugins_url('/src/assets/', PP_AUTHORS_SRC_PATH)); + define('PP_AUTHORS_AUTOLOAD_CLASS_NAME', 'ComposerStaticInit92fc51e620da052063312bd38c6157a4'); +} diff --git a/src/functions/template-tags.php b/src/functions/template-tags.php index 6b65f5ec..fb2bb23c 100644 --- a/src/functions/template-tags.php +++ b/src/functions/template-tags.php @@ -27,17 +27,44 @@ function get_multiple_authors($post = 0, $filter_the_author = true, $archive = f { global $multipleAuthorsForPost; - $cacheKey = null; + if (empty($multipleAuthorsForPost)) { + $multipleAuthorsForPost = []; + } + + if (empty($post)) { + $post = get_post(); + } + + $postId = 0; if (is_object($post)) { - $cacheKey = $post->ID; - } else { - $cacheKey = (int)$post; + $postId = $post->ID; + } elseif (is_int($post) || is_numeric($post)) { + $postId = (int)$post; + } + + if ((empty($post) || empty($postId)) && !$archive) { + return []; } - $cacheKey .= $filter_the_author ? 1 : 0; - $cacheKey .= $archive ? 1 : 0; - $authors = []; - if (empty($multipleAuthorsForPost) || !isset($multipleAuthorsForPost[$cacheKey])) { + $cacheKey = [ + 'post-id' => $postId, + 'filter-the-author' => $filter_the_author ? 1 : 0, + 'archive' => $archive ? 1 : 0, + 'author_name' => '', // Needed for the author page (archive) + ]; + + $authorName = ''; + if ($archive) { + $authorName = get_query_var('author_name'); + + $cacheKey['author_name'] = $authorName; + } + + $cacheKey = md5(json_encode($cacheKey)); + + $authors = []; + + if (!isset($multipleAuthorsForPost[$cacheKey])) { if (!$archive) { // If not archive, we get the authors from the current post, or from the given post. if (is_null($post)) { @@ -54,8 +81,7 @@ function get_multiple_authors($post = 0, $filter_the_author = true, $archive = f $terms = wp_get_post_terms($post->ID, $taxonomy, ['fields' => 'ids']); } else { // Get the term related to the current author from the archive page. - $authorName = get_query_var('author_name'); - $terms = []; + $terms = []; if (!empty($authorName)) { $terms[] = get_term_by('slug', $authorName, 'author'); @@ -63,6 +89,7 @@ function get_multiple_authors($post = 0, $filter_the_author = true, $archive = f } if ($terms && !is_wp_error($terms)) { + // We found authors foreach ($terms as $term) { if (is_numeric($term)) { $term = get_term($term); @@ -77,6 +104,7 @@ function get_multiple_authors($post = 0, $filter_the_author = true, $archive = f $authors[] = $author; } } elseif (!$terms) { + // Fallback to the post author $user = get_user_by('id', $post->post_author); if ($user) { @@ -111,12 +139,12 @@ function multiple_authors_get_all_authors($args = []) $args = wp_parse_args($args, $defaults); - $terms = get_terms('author', $args); + $terms = get_terms('author', $args); $authors = []; foreach ($terms as $term) { - $author = Author::get_by_term_id($term->term_id); + $author = Author::get_by_term_id($term->term_id); $author->display_name = apply_filters('the_author', $author->display_name); - $authors[] = $author; + $authors[] = $author; } return $authors; diff --git a/src/modules/multiple-authors/multiple-authors.php b/src/modules/multiple-authors/multiple-authors.php index 27dc176a..3ae89972 100644 --- a/src/modules/multiple-authors/multiple-authors.php +++ b/src/modules/multiple-authors/multiple-authors.php @@ -72,11 +72,11 @@ public function __construct() $args = [ 'title' => __('Multiple Authors', 'publishpress-authors'), 'short_description' => __( - 'Add support for multiple authors on your content', + 'PublishPress Authors allows you to add multiple authors and guest authors to WordPress posts', 'publishpress-authors' ), 'extended_description' => __( - 'Add support for multiple authors on your content', + 'PublishPress Authors allows you to add multiple authors and guest authors to WordPress posts', 'publishpress-authors' ), 'module_url' => $this->module_url, diff --git a/src/plugin.php b/src/plugin.php index f0f9c74b..ba82121d 100644 --- a/src/plugin.php +++ b/src/plugin.php @@ -13,7 +13,7 @@ * Plugin Name: PublishPress Authors * Plugin URI: https://publishpress.com/ * Version: 3.2.5-beta.8 - * Description: Add support for multiple authors + * Description: PublishPress Authors allows you to add multiple authors and guest authors to WordPress posts * Author: PublishPress * Author URI: https://publishpress.com * diff --git a/tests/integration/core/Classes/Legacy/UtilCest.php b/tests/integration/core/Classes/Legacy/UtilCest.php new file mode 100644 index 00000000..bfb46043 --- /dev/null +++ b/tests/integration/core/Classes/Legacy/UtilCest.php @@ -0,0 +1,179 @@ +factory('a new post')->post->create(['post_type' => $expectedPostType]); + + $postType = Util::getPostPostType($postId); + + $I->assertEquals($expectedPostType, $postType); + } + + /** + * @before cleanup + */ + public function testGetPostPostType_WithExistingPost_ReturnsThePostTypeForThePost(\WpunitTester $I) + { + $expectedPostType = 'page'; + + $newPostId = $I->factory('a new post')->post->create(['post_type' => $expectedPostType]); + $newPost = get_post($newPostId); + + $postType = Util::getPostPostType($newPost); + + $I->assertEquals($expectedPostType, $postType); + } + + /** + * @example [9999999999] + * @example [0] + * @example [""] + * @example ["0"] + * @example [-1] + * @example ["-1"] + * @example [false] + * @example [null] + * + * @before cleanup + */ + public function testGetPostPostType_WithNonExistingPostId_ReturnsFalse(\WpunitTester $I, Example $example) + { + $postType = Util::getPostPostType($example[0]); + + $I->assertFalse($postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForPostInTheGlobalVar_ReturnsPostPostType(\WpunitTester $I) + { + $expectedPostType = 'page'; + + $newPostId = $I->factory('a new post')->post->create(['post_type' => $expectedPostType]); + $newPost = get_post($newPostId); + + global $post; + $post = $newPost; + + $postType = Util::getCurrentPostType(); + + $I->assertEquals($expectedPostType, $postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForTypenowGlobalVar_ReturnsPostPostType(\WpunitTester $I) + { + global $typenow; + + $typenow = 'page'; + + $postType = Util::getCurrentPostType(); + + $I->assertEquals($typenow, $postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForCurrentScreenPostType_ReturnsPostPostType(\WpunitTester $I) + { + global $current_screen; + + $expectedPostType = 'page'; + + $current_screen = \WP_Screen::get('pp_authors_test'); + $current_screen->post_type = $expectedPostType; + + $postType = Util::getCurrentPostType(); + + $I->assertEquals($expectedPostType, $postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForRequestVar_ReturnsPostPostType(\WpunitTester $I) + { + $expectedPostType = 'page'; + + $_REQUEST['post_type'] = $expectedPostType; + + $postType = Util::getCurrentPostType(); + + $I->assertEquals($expectedPostType, $postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForPostPagenow_ReturnsPostPostType(\WpunitTester $I) + { + global $pagenow; + + $pagenow = 'post.php'; + $expectedPostType = 'page'; + + $_REQUEST['post'] = $I->factory('a new post')->post->create(['post_type' => $expectedPostType]); + + $postType = Util::getCurrentPostType(); + + $I->assertEquals($expectedPostType, $postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForEditPagenowWithNoGetParam_ReturnsPost(\WpunitTester $I) + { + global $pagenow; + + $pagenow = 'edit.php'; + + $postType = Util::getCurrentPostType(); + + $I->assertEquals('post', $postType); + } + + /** + * @before cleanup + */ + public function testGetCurrentPostType_ForAuthorPage_ReturnsPost(\WpunitTester $I) + { + global $wp_query; + + $wp_query = new \WP_Query(); + $wp_query->is_author = true; + + $postType = Util::getCurrentPostType(); + + $I->assertEquals('post', $postType); + } +} diff --git a/tests/integration/core/Classes/Objects/AuthorCest.php b/tests/integration/core/Classes/Objects/AuthorCest.php index 28ceb610..99eb877b 100644 --- a/tests/integration/core/Classes/Objects/AuthorCest.php +++ b/tests/integration/core/Classes/Objects/AuthorCest.php @@ -287,7 +287,7 @@ public function tryToGetLinkForGuestAuthors(\WpunitTester $I) ); } - public function tryToGetNameForMappedToUserAuthor(\WpunitTester $I) + public function tryToGetNameForMappedToUserAuthorWithoutChangingAuthorsName(\WpunitTester $I) { $userAuthorID = $I->factory('a new user')->user->create( [ @@ -295,13 +295,49 @@ public function tryToGetNameForMappedToUserAuthor(\WpunitTester $I) ] ); - $user = get_user_by('id', $userAuthorID); + $user = get_user_by('id', $userAuthorID); $author = Author::create_from_user($userAuthorID); $I->assertEquals( $user->display_name, $author->name ); + + $I->assertEquals( + $user->display_name, + $author->display_name + ); + } + + public function tryToGetAuthorsDisplayNameForMappedToUserAuthorChangingAuthorsName(\WpunitTester $I) + { + $expected = 'Aslam Jorge'; + + $userAuthorID = $I->factory('a new user')->user->create( + [ + 'role' => 'author', + ] + ); + + $user = get_user_by('id', $userAuthorID); + $author = Author::create_from_user($userAuthorID); + wp_update_term($author->term_id, 'author', ['name' => $expected]); + + $I->assertEquals( + $expected, + $author->display_name, + ); + + $I->assertEquals( + $expected, + $author->name, + ); + + $I->assertNotEquals( + $user->display_name, + $author->display_name, + 'If the author has a different display_name, that is the expected value, not the user\'s display_name.' + ); } public function tryToGetNameForGuestAuthors(\WpunitTester $I) @@ -329,7 +365,7 @@ public function tryToGetSlugForMappedToUserAuthor(\WpunitTester $I) ] ); - $user = get_user_by('id', $userAuthorID); + $user = get_user_by('id', $userAuthorID); $author = Author::create_from_user($userAuthorID); $I->assertEquals( diff --git a/tests/integration/core/functions/get_multiple_authorsCest.php b/tests/integration/core/functions/get_multiple_authorsCest.php new file mode 100644 index 00000000..be86f27f --- /dev/null +++ b/tests/integration/core/functions/get_multiple_authorsCest.php @@ -0,0 +1,429 @@ +factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId = $I->factory('create a new post')->post->create(); + $post = get_post($postId); + + wp_set_post_terms($postId, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + $authorsList = get_multiple_authors($post, false, false); + + $I->assertIsArray($authorsList); + $I->assertCount(3, $authorsList); + $I->assertInstanceOf(Author::class, $authorsList[0]); + $I->assertInstanceOf(Author::class, $authorsList[1]); + $I->assertInstanceOf(Author::class, $authorsList[2]); + $I->assertEquals($author0->term_id, $authorsList[0]->term_id); + $I->assertEquals($author1->term_id, $authorsList[1]->term_id); + $I->assertEquals($author2->term_id, $authorsList[2]->term_id); + } + + public function testGetMultipleAuthors_WithPostAsInt_ReturnListOfAuthors(WpunitTester $I) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId = $I->factory('create a new post')->post->create(); + + wp_set_post_terms($postId, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + $authorsList = get_multiple_authors($postId, false, false); + + $I->assertIsArray($authorsList); + $I->assertCount(3, $authorsList); + $I->assertInstanceOf(Author::class, $authorsList[0]); + $I->assertInstanceOf(Author::class, $authorsList[1]); + $I->assertInstanceOf(Author::class, $authorsList[2]); + $I->assertEquals($author0->term_id, $authorsList[0]->term_id); + $I->assertEquals($author1->term_id, $authorsList[1]->term_id); + $I->assertEquals($author2->term_id, $authorsList[2]->term_id); + } + + public function testGetMultipleAuthors_WithPostAsString_ReturnListOfAuthors(WpunitTester $I) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId = $I->factory('create a new post')->post->create(); + + wp_set_post_terms($postId, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + $authorsList = get_multiple_authors("$postId", false, false); + + $I->assertIsArray($authorsList); + $I->assertCount(3, $authorsList); + $I->assertInstanceOf(Author::class, $authorsList[0]); + $I->assertInstanceOf(Author::class, $authorsList[1]); + $I->assertInstanceOf(Author::class, $authorsList[2]); + $I->assertEquals($author0->term_id, $authorsList[0]->term_id); + $I->assertEquals($author1->term_id, $authorsList[1]->term_id); + $I->assertEquals($author2->term_id, $authorsList[2]->term_id); + } + + /** + * @example [0] + * @example [false] + * @example [null] + * @example [""] + */ + public function testGetMultipleAuthors_WithGlobalPost_ReturnListOfAuthors(WpunitTester $I, Example $example) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId = $I->factory('create a new post')->post->create(); + $post = get_post($postId); + + wp_set_post_terms($postId, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + $GLOBALS['post'] = $post; + + $authorsList = get_multiple_authors($example[0], false, false); + + $I->assertIsArray($authorsList); + $I->assertCount(3, $authorsList); + $I->assertInstanceOf(Author::class, $authorsList[0]); + $I->assertInstanceOf(Author::class, $authorsList[1]); + $I->assertInstanceOf(Author::class, $authorsList[2]); + $I->assertEquals($author0->term_id, $authorsList[0]->term_id); + $I->assertEquals($author1->term_id, $authorsList[1]->term_id); + $I->assertEquals($author2->term_id, $authorsList[2]->term_id); + } + + public function testGetMultipleAuthors_WithFilterAuthor_ShouldFilterTheAuthorsDisplayName(WpunitTester $I) + { + global $multipleAuthorsForPost, $testFilterAdded; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId = $I->factory('create a new post')->post->create(); + $post = get_post($postId); + + wp_set_post_terms($postId, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + if (empty($testFilterAdded)) { + \add_filter( + 'the_author', + function ($displayName) { + return $displayName . '--filtered'; + } + ); + + $testFilterAdded = true; + } + + $authorsList = get_multiple_authors($post, true, false); + + $I->assertIsArray($authorsList); + $I->assertCount(3, $authorsList); + $I->assertInstanceOf(Author::class, $authorsList[0]); + $I->assertInstanceOf(Author::class, $authorsList[1]); + $I->assertInstanceOf(Author::class, $authorsList[2]); + $I->assertEquals($author0->display_name . '--filtered', $authorsList[0]->display_name); + $I->assertEquals($author1->display_name . '--filtered', $authorsList[1]->display_name); + $I->assertEquals($author2->display_name . '--filtered', $authorsList[2]->display_name); + + remove_all_filters('the_author'); + } + + public function testGetMultipleAuthors_WithArchiveParam_ShouldReturnCurrentAuthor(WpunitTester $I) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + + $author0 = Author::create_from_user($userId0); + + set_query_var('author_name', $author0->slug); + + $authorsList = get_multiple_authors(0, false, true); + + $I->assertIsArray($authorsList); + $I->assertCount(1, $authorsList); + $I->assertInstanceOf(Author::class, $authorsList[0]); + $I->assertEquals($author0->term_id, $authorsList[0]->term_id); + } + + protected function serializeArrayOfAuthors($authorsArray) + { + $data = []; + + foreach ($authorsArray as $author) { + $data[] = [ + 'term_id' => $author->term_id, + 'user_id' => $author->user_id, + 'display_name' => $author->display_name, + 'slug' => $author->slug, + ]; + } + + return maybe_serialize($data); + } + + public function testGetMultipleAuthors_ForCallingSamePostTwice_isCachingAuthorList(WpunitTester $I) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId0 = $I->factory('create post0')->post->create(); + + wp_set_post_terms($postId0, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + $returnedAuthorList = get_multiple_authors($postId0, false, false); + + // Created a cache entry + $I->assertCount(1, $multipleAuthorsForPost, 'We called once, so only one item should be in the cache'); + // The returned list is the same as the cached one + reset($multipleAuthorsForPost); + $cachedAuthorList = current($multipleAuthorsForPost); + $I->assertCount(3, $cachedAuthorList, 'Like the expected list, the cached list should have 3 items'); + $I->assertEquals( + $this->serializeArrayOfAuthors($cachedAuthorList), + $this->serializeArrayOfAuthors($returnedAuthorList) + ); + $I->assertEquals($author0, $cachedAuthorList[0]); + $I->assertEquals($author1, $cachedAuthorList[1]); + $I->assertEquals($author2, $cachedAuthorList[2]); + + // Call the function again and check if the cached value is still returned + $returnedAuthorList = get_multiple_authors($postId0, false, false); + + // Created a cache entry + $I->assertCount(1, $multipleAuthorsForPost, 'We twice, but only one item should be in the cache'); + // The returned list is the same as the cached one + reset($multipleAuthorsForPost); + $cachedAuthorList = current($multipleAuthorsForPost); + $I->assertCount(3, $cachedAuthorList, 'Like the expected list, the cached list should have 3 items'); + $I->assertEquals( + $this->serializeArrayOfAuthors($cachedAuthorList), + $this->serializeArrayOfAuthors($returnedAuthorList) + ); + $I->assertEquals($author0, $cachedAuthorList[0]); + $I->assertEquals($author1, $cachedAuthorList[1]); + $I->assertEquals($author2, $cachedAuthorList[2]); + } + + public function testGetMultipleAuthors_ForCallingSamePostTwiceWithDifferentParams_isCachingBothAuthorLists( + WpunitTester $I + ) { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId0 = $I->factory('create post0')->post->create(); + + wp_set_post_terms($postId0, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + get_multiple_authors($postId0, true, false); + get_multiple_authors($postId0, false, false); + + reset($multipleAuthorsForPost); + + $I->assertCount(2, $multipleAuthorsForPost, 'Should create 3 entries in the cache'); + + $I->assertCount(3, current($multipleAuthorsForPost)); + next($multipleAuthorsForPost); + $I->assertCount(3, current($multipleAuthorsForPost)); + } + + public function testGetMultipleAuthors_ForDifferentPosts_isCachingBothAuthorList(WpunitTester $I) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId0 = $I->factory('create post0')->post->create(); + $postId1 = $I->factory('create post1')->post->create(); + + wp_set_post_terms($postId0, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + wp_set_post_terms($postId1, [$author0->term_id], 'author'); + + $returnedAuthorList0 = get_multiple_authors($postId0, false, false); + + $I->assertCount(1, $multipleAuthorsForPost, 'We called once, so only one item should be in the cache'); + // The returned list is the same as the cached one + reset($multipleAuthorsForPost); + $cachedAuthorList = current($multipleAuthorsForPost); + $I->assertCount(3, $cachedAuthorList, 'Like the expected list, the cached list should have 3 items'); + $I->assertEquals( + $this->serializeArrayOfAuthors($cachedAuthorList), + $this->serializeArrayOfAuthors($returnedAuthorList0) + ); + $I->assertEquals($author0, $cachedAuthorList[0]); + $I->assertEquals($author1, $cachedAuthorList[1]); + $I->assertEquals($author2, $cachedAuthorList[2]); + + // Call the function again for a different post and check if the new author list is cached + $returnedAuthorList1 = get_multiple_authors($postId1, false, false); + + // Created a cache entry + $I->assertCount( + 2, + $multipleAuthorsForPost, + 'We are calling the function for different posts, so we should have 2 cached values' + ); + // The returned list is the same as the cached one + reset($multipleAuthorsForPost); + next($multipleAuthorsForPost); + $cachedAuthorList = current($multipleAuthorsForPost); + $I->assertCount(1, $cachedAuthorList, 'Like the expected list, the cached list should have 1 items'); + $I->assertEquals( + $this->serializeArrayOfAuthors($cachedAuthorList), + $this->serializeArrayOfAuthors($returnedAuthorList1) + ); + $I->assertEquals($author0, $cachedAuthorList[0]); + } + + public function testGetMultipleAuthors_ForArchive_isCachingTheAuthorFromAuthorPage(WpunitTester $I) + { + global $multipleAuthorsForPost; + + $multipleAuthorsForPost = []; + + $userId0 = $I->factory('create user0')->user->create(); + $userId1 = $I->factory('create user1')->user->create(); + $userId2 = $I->factory('create user2')->user->create(); + + $author0 = Author::create_from_user($userId0); + $author1 = Author::create_from_user($userId1); + $author2 = Author::create_from_user($userId2); + + $postId0 = $I->factory('create post0')->post->create(); + $post0 = get_post($postId0); + + $GLOBALS['post'] = $post0; + + wp_set_post_terms($postId0, [$author0->term_id, $author1->term_id, $author2->term_id], 'author'); + + // Call without a post id so it gets the global post, similar to the call with the archive param = true. + get_multiple_authors(0, false, false); + + $I->assertCount(1, $multipleAuthorsForPost, 'We called once, so only one item should be in the cache'); + // The returned list is the same as the cached one + reset($multipleAuthorsForPost); + $cachedAuthorList = current($multipleAuthorsForPost); + $I->assertCount(3, $cachedAuthorList, 'Like the expected list, the cached list should have 3 items'); + + // Call the function again for the archive page and check if the new author list is cached + set_query_var('author_name', $author2->slug); + $returnedAuthorList1 = get_multiple_authors(0, false, true); + + // Created a cache entry + $I->assertCount( + 2, + $multipleAuthorsForPost, + 'We are calling the function for a post and archive, so we should have 2 cached values' + ); + // The returned list is the same as the cached one + reset($multipleAuthorsForPost); + next($multipleAuthorsForPost); + $cachedAuthorList = current($multipleAuthorsForPost); + $I->assertCount( + 1, + $cachedAuthorList, + 'Since we are calling for the author page, only the current author is returned' + ); + $I->assertEquals( + $this->serializeArrayOfAuthors($cachedAuthorList), + $this->serializeArrayOfAuthors($returnedAuthorList1) + ); + $I->assertEquals($author2, $cachedAuthorList[0]); + + // Try calling the method again and double check if we used the cached value. + $returnedAuthorList1 = get_multiple_authors(0, false, true); + $I->assertCount( + 2, + $multipleAuthorsForPost, + 'We are calling the function archive again, but we should not have a new cached value' + ); + $I->assertEquals( + $this->serializeArrayOfAuthors($cachedAuthorList), + $this->serializeArrayOfAuthors($returnedAuthorList1) + ); + } +}