diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8bff772..33b56d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,15 +10,15 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' - name: Install PHP - uses: shivammathur/setup-php@2.7.0 + uses: shivammathur/setup-php@v2 with: php-version: 7.4 extensions: mysqli, xmlwriter @@ -28,13 +28,13 @@ jobs: - name: Get Composer Cache Directory id: composer-cache-dir run: | - echo "::set-output name=dir::$(composer config cache-files-dir)" + echo "DIR=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache PHP Dependencies id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ${{ steps.composer-cache-dir.outputs.dir }} + path: ${{ steps.composer-cache-dir.outputs.DIR }} key: ${{ runner.os }}-composer-7.4-${{ hashFiles('composer.lock') }} - name: Install PHP Dependencies @@ -43,16 +43,16 @@ jobs: - name: Get npm cache directory id: npm-cache-dir run: | - echo "::set-output name=dir::$(npm config get cache)" - echo "::set-output name=npm-version::$(npm -v)" - echo "::set-output name=node-version::$(node -v)" + echo "DIR=$(npm config get cache)" >> $GITHUB_OUTPUT + echo "NPM_VERSION=$(npm -v)" >> $GITHUB_OUTPUT + echo "NODE_VERSION=$(node -v)" >> $GITHUB_OUTPUT - name: Cache JS Dependencies id: npm-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ${{ steps.npm-cache-dir.outputs.dir }} - key: ${{ runner.os }}-npm-${{ steps.npm-cache-dir.outputs.node-version }}-${{ steps.npm-cache-dir.outputs.npm-version }}-${{ hashFiles('package-lock.json') }} + path: ${{ steps.npm-cache-dir.outputs.DIR }} + key: ${{ runner.os }}-npm-${{ steps.npm-cache-dir.outputs.NODE_VERSION }}-${{ steps.npm-cache-dir.outputs.NPM_VERSION }}-${{ hashFiles('package-lock.json') }} - name: Install JS Dependencies run: npm install --legacy-peer-deps diff --git a/.github/workflows/js-tests.yml b/.github/workflows/js-tests.yml index b59e752..5fd7330 100644 --- a/.github/workflows/js-tests.yml +++ b/.github/workflows/js-tests.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' @@ -29,16 +29,16 @@ jobs: - name: Get npm cache directory id: npm-cache-dir run: | - echo "::set-output name=dir::$(npm config get cache)" - echo "::set-output name=npm-version::$(npm -v)" - echo "::set-output name=node-version::$(node-v)" + echo "DIR=$(npm config get cache)" >> $GITHUB_OUTPUT + echo "NPM_VERSION=$(npm -v)" >> $GITHUB_OUTPUT + echo "NODE_VERSION=$(node -v)" >> $GITHUB_OUTPUT - name: Cache Dependencies id: npm-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ${{ steps.npm-cache-dir.outputs.dir }} - key: ${{ runner.os }}-npm-${{ steps.npm-cache-dir.outputs.node-version }}-${{ steps.npm-cache-dir.outputs.npm-version }}-${{ hashFiles('package-lock.json') }} + path: ${{ steps.npm-cache-dir.outputs.DIR }} + key: ${{ runner.os }}-npm-${{ steps.npm-cache-dir.outputs.NODE_VERSION }}-${{ steps.npm-cache-dir.outputs.NPM_VERSION }}-${{ hashFiles('package-lock.json') }} - name: Install Dependencies run: npm install --legacy-peer-deps diff --git a/.github/workflows/php-standards.yml b/.github/workflows/php-standards.yml index a5fddc4..f9f9f9b 100644 --- a/.github/workflows/php-standards.yml +++ b/.github/workflows/php-standards.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Install PHP - uses: shivammathur/setup-php@2.7.0 + uses: shivammathur/setup-php@v2 with: php-version: '7.4' coverage: none @@ -31,13 +31,13 @@ jobs: - name: Get Composer Cache Directory id: composer-cache-dir run: | - echo "::set-output name=dir::$(composer config cache-files-dir)" + echo "DIR=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache PHP Dependencies id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ${{ steps.composer-cache-dir.outputs.dir }} + path: ${{ steps.composer-cache-dir.outputs.DIR }} key: ${{ runner.os }}-composer-7.2-${{ hashFiles('composer.lock') }} - name: Install PHP Dependencies @@ -45,7 +45,7 @@ jobs: composer install --prefer-dist --no-progress --no-suggest --no-interaction - name: PHPCS cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: tests/cache key: ${{ runner.os }}-phpcs-7.2-${{ hashFiles('plugin.php') }} diff --git a/.github/workflows/test-nightly.yml b/.github/workflows/test-nightly.yml index 114edf0..faaa778 100644 --- a/.github/workflows/test-nightly.yml +++ b/.github/workflows/test-nightly.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Install PHP - uses: shivammathur/setup-php@2.7.0 + uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: mysqli, xmlwriter @@ -38,19 +38,19 @@ jobs: - name: Get Composer Cache Directory id: composer-cache-dir run: | - echo "::set-output name=dir::$(composer config cache-files-dir)" + echo "DIR=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache PHP Dependencies id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ${{ steps.composer-cache-dir.outputs.dir }} + path: ${{ steps.composer-cache-dir.outputs.DIR }} key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('composer.lock') }} - name: Install PHP Dependencies run: | composer install --prefer-dist --no-progress --no-suggest --no-interaction --ignore-platform-reqs - composer require --dev --update-with-dependencies --prefer-dist roots/wordpress="dev-nightly" wp-phpunit/wp-phpunit="dev-master" + composer require --dev --update-with-dependencies --prefer-dist roots/wordpress="dev-main" wp-phpunit/wp-phpunit="dev-master" - name: Run the tests run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4f4e9af..0f13dc4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,14 +19,14 @@ jobs: - '8.2' - '8.3' fail-fast: false - name: WP 6.4 / PHP ${{ matrix.php }} + name: WP 6.6 / PHP ${{ matrix.php }} runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Install PHP - uses: shivammathur/setup-php@2.7.0 + uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: mysqli, xmlwriter @@ -43,14 +43,14 @@ jobs: - name: Get Composer Cache Directory id: composer-cache-dir run: | - echo "::set-output name=dir::$(composer config cache-files-dir)" + echo "DIR=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache PHP Dependencies id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache-dir.outputs.dir }} - key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('composer.lock') }}-wp6.4 + key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('composer.lock') }}-wp6.6 - name: Install PHP Dependencies run: | diff --git a/README.md b/README.md index 050a7bb..70e4054 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Authorship -Stable tag: 0.2.16 +Stable tag: 0.2.17 Requires at least: 5.4 Tested up to: 6.2 Requires PHP: 7.2 @@ -61,9 +61,10 @@ _Features without a checkmark are still work in progress._ ### For development use * Clone this repo into your plugins directory -* Install the dependencies: +* Ensure you have Composer v2 and Node v16 installed +* Install the dependencies: `composer install && npm install` -* Start the dev server: +* Start the dev server: `npm run start` ## Design Decisions @@ -133,7 +134,7 @@ This endpoint allows: ### `authorship` field -This field is added to the endpoint for all suported post types (by default, ones which that have post type support for `author`), for example `wp/v2/posts`. This field is readable and writable and accepts and provides an array of IDs of users attributed to the post. +This field is added to the endpoint for all supported post types (by default, ones which that have post type support for `author`), for example `wp/v2/posts`. This field is readable and writable and accepts and provides an array of IDs of users attributed to the post. In addition, user objects are embedded in the `_embedded['wp:authorship']` field in the response if `_embed` is set and the authenticated user can list users. diff --git a/inc/class-insert-post-handler.php b/inc/class-insert-post-handler.php new file mode 100644 index 0000000..59d9fa9 --- /dev/null +++ b/inc/class-insert-post-handler.php @@ -0,0 +1,91 @@ + + */ + private $postarr = []; + + /** + * Filters slashed post data just before it is inserted into the database. + * + * @param mixed[] $data An array of slashed, sanitized, and processed post data. + * @param mixed[] $postarr An array of sanitized (and slashed) but otherwise unmodified post data. + * @param mixed $unsanitized_postarr An array (or object that implements array access, like a WP_Post) of + * slashed yet _unsanitized_ and unprocessed post data as originally passed + * to wp_insert_post(). + * @return mixed[] An array of slashed, sanitized, and processed post data. + */ + function filter_wp_insert_post_data( array $data, array $postarr, $unsanitized_postarr ) : array { + // Make sure the unsanitized post array is actually an array. Core sometimes passes it as a WP_Post object. + $this->postarr = (array) $unsanitized_postarr; + + return $data; + } + + /** + * Fires once a post has been saved. + * + * @param int $post_ID Post ID. + * @param WP_Post $post Post object. + * @param bool $update Whether this is an existing post being updated. + */ + function action_wp_insert_post( int $post_ID, WP_Post $post, bool $update ) : void { + $unsanitized_postarr = $this->postarr; + + $this->postarr = []; + + if ( isset( $unsanitized_postarr['tax_input'] ) && ! empty( $unsanitized_postarr['tax_input'][ TAXONOMY ] ) ) { + return; + } + + $existing_authors = get_authors( $post ); + + if ( $update && ! isset( $unsanitized_postarr[ POSTS_PARAM ] ) && $existing_authors ) { + return; + } + + if ( isset( $unsanitized_postarr[ POSTS_PARAM ] ) ) { + $authors = $unsanitized_postarr[ POSTS_PARAM ]; + } else { + /** + * Set the default authorship author. Defaults to the original post author. + * + * @param array $authors Authors to add to a post on insert if none have been passed. Default to post author. + * @param WP_Post $post Post object. + */ + $authors = array_filter( apply_filters( + 'authorship_default_author', + [ isset( $unsanitized_postarr['post_author'] ) ? $unsanitized_postarr['post_author'] : null ], + $post + ) ); + } + + if ( empty( $authors ) ) { + return; + } + + try { + set_authors( $post, wp_parse_id_list( $authors ) ); + } catch ( Exception $e ) { + // Nothing at the moment. + } + } +} diff --git a/inc/cli/class-migrate-command.php b/inc/cli/class-migrate-command.php index c8d5893..cc86bcc 100644 --- a/inc/cli/class-migrate-command.php +++ b/inc/cli/class-migrate-command.php @@ -49,6 +49,12 @@ class Migrate_Command extends WP_CLI_Command { * - false * --- * + * [--post-type=] + * : Post type, or comma separated list of post types. + * --- + * default: post + * --- + * * ## EXAMPLES * * wp authorship migrate wp-authors --dry-run=true @@ -79,6 +85,9 @@ public function wp_authors( $args, $assoc_args ) : void { WP_CLI::warning( 'Overwriting of previous Authorship data is set to true.' ); } + $post_types = explode( ',', $assoc_args['post-type'] ); + WP_CLI::line( sprintf( 'Updating post types: %s', implode( ', ', $post_types ) ) ); + $tax_query = $overwrite ? [] : [ [ 'taxonomy' => 'authorship', @@ -93,6 +102,7 @@ public function wp_authors( $args, $assoc_args ) : void { $posts = get_posts( [ 'posts_per_page' => $posts_per_page, 'paged' => $paged, + 'post_type' => $post_types, 'post_status' => 'any', 'ignore_sticky_posts' => true, 'suppress_filters' => false, @@ -249,8 +259,8 @@ function ppa( $args, $assoc_args ) : void { // Usually invalid taxonomy, lets catch and report this. if ( is_wp_error( $ppa_terms ) ) { WP_CLI::error( 'There was an error fetching the PublishPress Author data, is the plugin activated?', false ); - WP_CLI::error( $ppa_terms ); - exit; + WP_CLI::error( $ppa_terms, false ); + exit( 1 ); } /** @@ -351,9 +361,9 @@ private function get_ppa_user_id( WP_Term $ppa_author, bool $create_users = fals // If this fails we want the debug data, so print out the // arguments so we can reproduce later. if ( is_wp_error( $ppa_user_id ) ) { - WP_CLI::error( 'Could not create Authorship user with these arguments:' ); - WP_CLI::error( $ppa_user_id ); - return -1; + WP_CLI::error( 'Could not create Authorship user with these arguments:', false ); + WP_CLI::error( $ppa_user_id, false ); + exit( 1 ); } return $ppa_user_id; diff --git a/inc/namespace.php b/inc/namespace.php index 6699f22..6b5524d 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -37,6 +37,8 @@ * Bootstraps the main actions and filters. */ function bootstrap() : void { + $insert_post_handler = new InsertPostHandler(); + // Actions. add_action( 'init', __NAMESPACE__ . '\\init_taxonomy', 99 ); add_action( 'init', __NAMESPACE__ . '\\register_roles_and_caps', 1 ); @@ -44,9 +46,10 @@ function bootstrap() : void { add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\\enqueue_assets' ); add_action( 'pre_get_posts', __NAMESPACE__ . '\\action_pre_get_posts', 9999 ); add_action( 'wp', __NAMESPACE__ . '\\action_wp' ); + add_action( 'wp_insert_post', [ $insert_post_handler, 'action_wp_insert_post' ], 10, 3 ); // Filters. - add_filter( 'wp_insert_post_data', __NAMESPACE__ . '\\filter_wp_insert_post_data', 10, 3 ); + add_filter( 'wp_insert_post_data', [ $insert_post_handler, 'filter_wp_insert_post_data' ], 10, 3 ); add_filter( 'rest_request_after_callbacks', __NAMESPACE__ . '\\filter_rest_request_after_callbacks', 10, 3 ); add_filter( 'map_meta_cap', __NAMESPACE__ . '\\filter_map_meta_cap_for_editing', 10, 4 ); add_filter( 'user_has_cap', __NAMESPACE__ . '\\filter_user_has_cap', 10, 4 ); @@ -54,6 +57,7 @@ function bootstrap() : void { add_filter( 'the_author', __NAMESPACE__ . '\\filter_the_author_for_rss' ); add_filter( 'comment_moderation_recipients', __NAMESPACE__ . '\\filter_comment_moderation_recipients', 10, 2 ); add_filter( 'comment_notification_recipients', __NAMESPACE__ . '\\filter_comment_notification_recipients', 10, 2 ); + add_filter( 'quick_edit_dropdown_authors_args', __NAMESPACE__ . '\\hide_quickedit_authors' ); } /** @@ -330,71 +334,6 @@ function filter_rest_request_after_callbacks( $result, array $handler, WP_REST_R return $result; } -/** - * Filters slashed post data just before it is inserted into the database. - * - * @param mixed[] $data An array of slashed, sanitized, and processed post data. - * @param mixed[] $postarr An array of sanitized (and slashed) but otherwise unmodified post data. - * @param mixed $unsanitized_postarr An array (or object that implements array access, like a WP_Post) of - * slashed yet _unsanitized_ and unprocessed post data as originally passed - * to wp_insert_post(). - * @return mixed[] An array of slashed, sanitized, and processed post data. - */ -function filter_wp_insert_post_data( array $data, array $postarr, $unsanitized_postarr ) : array { - - // Make sure the unsanitized post array is actually an array. Core sometimes passes it as a WP_Post object. - if ( ! is_array( $unsanitized_postarr ) ) { - $unsanitized_postarr = (array) $unsanitized_postarr; - } - - /** - * Fires once a post has been saved. - * - * @param int $post_ID Post ID. - * @param WP_Post $post Post object. - * @param bool $update Whether this is an existing post being updated. - */ - add_action( 'wp_insert_post', function( int $post_ID, WP_Post $post, bool $update ) use ( $unsanitized_postarr ) : void { - if ( isset( $unsanitized_postarr['tax_input'] ) && ! empty( $unsanitized_postarr['tax_input'][ TAXONOMY ] ) ) { - return; - } - - $existing_authors = get_authors( $post ); - - if ( $update && ! isset( $unsanitized_postarr[ POSTS_PARAM ] ) && $existing_authors ) { - return; - } - - if ( isset( $unsanitized_postarr[ POSTS_PARAM ] ) ) { - $authors = $unsanitized_postarr[ POSTS_PARAM ]; - } else { - /** - * Set the default authorship author. Defaults to the orignal post author. - * - * @param array $authors Authors to add to a post on insert if none have been passed. Default to post author. - * @param WP_Post $post Post object. - */ - $authors = array_filter( apply_filters( - 'authorship_default_author', - [ isset( $unsanitized_postarr['post_author'] ) ? $unsanitized_postarr['post_author'] : null ], - $post - ) ); - } - - if ( empty( $authors ) ) { - return; - } - - try { - set_authors( $post, wp_parse_id_list( $authors ) ); - } catch ( Exception $e ) { - // Nothing at the moment. - } - }, 10, 3 ); - - return $data; -} - /** * Adds the authorship field to the REST API for post objects. * @@ -814,3 +753,18 @@ function filter_comment_notification_recipients( array $emails, int $comment_id return array_unique( array_merge( $emails, $additional_emails ) ); } + +/** + * Hide author select from quick edit. + * + * Bit of a hack, but filter filter_quickedit_authors and include only author with ID 0. + * Also hide if only one author just in case someone someone has created author with 0. + * + * @param array $options Options. + * @return array Options. + */ +function hide_quickedit_authors( array $options ) : array { + $users_opt['hide_if_only_one_author'] = true; + $users_opt['include'] = [ 0 ]; + return $users_opt; +} diff --git a/package-lock.json b/package-lock.json index e6f93e8..7fcb779 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@humanmade/authorship", - "version": "0.2.16", + "version": "0.2.17", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@humanmade/authorship", - "version": "0.2.14", + "version": "0.2.17", "license": "GPL-3.0-or-later", "dependencies": { "@types/react-select": "^3.0.26", diff --git a/package.json b/package.json index 32566c4..a99b5f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@humanmade/authorship", - "version": "0.2.16", + "version": "0.2.17", "description": "Authorship", "private": true, "main": "src/index.tsx", @@ -9,12 +9,15 @@ "lint": "concurrently -n CSS,JS -c cyan.bold,yellow.bold \"npm run lint:css\" \"npm run lint:js\"", "lint:css": "stylelint src/", "lint:js": "eslint --ext .js,.jsx,.ts,.tsx src/", - "start": "webpack-dev-server --config=.config/webpack.config.dev.js", + "start": "webpack serve --config=.config/webpack.config.dev.js", "build": "webpack --config=.config/webpack.config.prod.js", "bump:patch": "bump patch --commit 'The v%s release' package.json package-lock.json README.md plugin.php", "bump:minor": "bump minor --commit 'The v%s release' package.json package-lock.json README.md plugin.php", "bump:major": "bump major --commit 'The v%s release' package.json package-lock.json README.md plugin.php" }, + "engines": { + "node": "16" + }, "dependencies": { "@types/react-select": "^3.0.26", "@wordpress/editor": "^9.24.3", diff --git a/plugin.php b/plugin.php index 4369d15..088fd1f 100644 --- a/plugin.php +++ b/plugin.php @@ -9,7 +9,7 @@ * * Plugin Name: Authorship * Description: Authorship plugin for WordPress. - * Version: 0.2.16 + * Version: 0.2.17 * Plugin URI: https://github.com/humanmade/authorship * Author: Human Made, initially funded by Siemens. * Author URI: https://humanmade.com/ @@ -43,6 +43,7 @@ require_once __DIR__ . '/inc/namespace.php'; require_once __DIR__ . '/inc/taxonomy.php'; require_once __DIR__ . '/inc/class-users-controller.php'; +require_once __DIR__ . '/inc/class-insert-post-handler.php'; require_once __DIR__ . '/inc/template.php'; if ( is_admin() ) { diff --git a/src/components/AuthorsSelect.tsx b/src/components/AuthorsSelect.tsx index 5c90ae7..071d600 100644 --- a/src/components/AuthorsSelect.tsx +++ b/src/components/AuthorsSelect.tsx @@ -58,7 +58,7 @@ const AuthorsSelect = ( props: AuthorsSelectProps ): ReactElement => { if ( ! selected.length && isEqual( preloadedAuthorIDs, currentAuthorIDs ) ) { setSelected( preloadedAuthorOptions.authors ); - } else if ( currentAuthorIDs.length && ! selected.length ) { + } else if ( currentAuthorIDs !== undefined && currentAuthorIDs.length && ! selected.length ) { const path = addQueryArgs( '/authorship/v1/users/', diff --git a/tests/phpunit/test-cli.php b/tests/phpunit/test-cli.php new file mode 100644 index 0000000..42f7392 --- /dev/null +++ b/tests/phpunit/test-cli.php @@ -0,0 +1,78 @@ +post; + + // Post. Owned by editor, attributed to nobody. + $post1 = $factory->create_and_get( [ + 'post_author' => self::$users['editor']->ID, + ] ); + + // Unset author data. + wp_set_post_terms( $post1->ID, [], TAXONOMY ); + + // Check initial authorship data unset. + $authorship_authors = \Authorship\get_authors( $post1 ); + $this->assertCount( 0, $authorship_authors ); + + $command = new CLI\Migrate_Command; + $command->wp_authors( [], [ + 'dry-run' => false, + 'post-type' => 'post', // Note, have to set default values manually. + ] ); + + // Check migration command has correctly set the author. + $authorship_authors = \Authorship\get_authors( $post1 ); + $this->assertCount( 1, $authorship_authors ); + $this->assertSame( self::$users['editor']->ID, $authorship_authors[0]->ID ); + } + + public function testMigratePostTypePage() : void { + $factory = self::factory()->post; + + // Page. Owned by editor, attributed to nobody. + $page1 = $factory->create_and_get( [ + 'post_author' => self::$users['editor']->ID, + 'post_type' => 'page', + ] ); + + // Unset author data. + wp_set_post_terms( $page1->ID, [], TAXONOMY ); + + // Check initial authorship data unset. + $authorship_authors = \Authorship\get_authors( $page1 ); + $this->assertCount( 0, $authorship_authors ); + + $command = new CLI\Migrate_Command(); + $command->wp_authors( [], [ + 'dry-run' => false, + 'post-type' => 'post,page', + ] ); + + // Check migration command has correctly set the author. + $authorship_authors = \Authorship\get_authors( $page1 ); + $this->assertCount( 1, $authorship_authors ); + $this->assertSame( self::$users['editor']->ID, $authorship_authors[0]->ID ); + } +} diff --git a/tests/phpunit/test-post-saving.php b/tests/phpunit/test-post-saving.php index 069e242..db82d27 100644 --- a/tests/phpunit/test-post-saving.php +++ b/tests/phpunit/test-post-saving.php @@ -137,4 +137,20 @@ public function testPostAuthorshipIsSetToEmptyWhenUpdatingPostWithNoExistingAuth remove_filter( 'authorship_default_author', '__return_empty_array' ); } + + public function testMultiplePostInsertionDoesNotCompoundActions() : void { + global $wp_filter; + + $before = count( $wp_filter['wp_insert_post']->callbacks ); + + for ( $i = 0; $i < 3; $i++ ) { + wp_insert_post( [ + 'post_title' => "Testing $i", + ] ); + } + + $after = count( $wp_filter['wp_insert_post']->callbacks ); + + $this->assertSame( $before, $after ); + } }