From 216a6a1be85f391c5e8ecc8fd8e9caf3b9448c59 Mon Sep 17 00:00:00 2001 From: Tunbosun Ayinla Date: Mon, 18 Sep 2023 21:58:30 +0100 Subject: [PATCH] Add `--slug=` as an available parameter to `wp site` commands (#416) --------- Co-authored-by: Daniel Bachhuber --- README.md | 118 +++++++++++++++------ features/site.feature | 237 +++++++++++++++++++++++++++++++++++++++++ src/Site_Command.php | 240 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 521 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index a18ed6794..0498bda27 100644 --- a/README.md +++ b/README.md @@ -3271,19 +3271,25 @@ wp site Activates one or more sites. ~~~ -wp site activate ... +wp site activate [...] [--slug=] ~~~ **OPTIONS** - ... - One or more IDs of sites to activate. + [...] + One or more IDs of sites to activate. If not provided, you must set the --slug parameter. + + [--slug=] + Path of the site to be activated. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site activate 123 Success: Site 123 activated. + $ wp site activate --slug=demo + Success: Site 123 marked as activated. + ### wp site archive @@ -3291,19 +3297,25 @@ wp site activate ... Archives one or more sites. ~~~ -wp site archive ... +wp site archive [...] [--slug=] ~~~ **OPTIONS** - ... - One or more IDs of sites to archive. + [...] + One or more IDs of sites to archive. If not provided, you must set the --slug parameter. + + [--slug=] + Path of the site to archive. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site archive 123 Success: Site 123 archived. + $ wp site archive --slug=demo + Success: Site 123 archived. + ### wp site create @@ -3346,19 +3358,25 @@ wp site create --slug= [--title=] [--email=<email>] [--network_id=< Deactivates one or more sites. ~~~ -wp site deactivate <id>... +wp site deactivate [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to deactivate. + [<id>...] + One or more IDs of sites to deactivate. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be deactivated. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site deactivate 123 Success: Site 123 deactivated. + $ wp site deactivate --slug=demo + Success: Site 123 marked as deactivated. + ### wp site delete @@ -3375,7 +3393,7 @@ wp site delete [<site-id>] [--slug=<slug>] [--yes] [--keep-tables] The id of the site to delete. If not provided, you must set the --slug parameter. [--slug=<slug>] - Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. + Path of the site to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. [--yes] Answer yes to the confirmation message. @@ -3508,19 +3526,25 @@ These fields are optionally available: Sets one or more sites as mature. ~~~ -wp site mature <id>... +wp site mature [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to set as mature. + [<id>...] + One or more IDs of sites to set as mature. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be set as mature. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site mature 123 Success: Site 123 marked as mature. + $ wp site mature --slug=demo + Success: Site 123 marked as mature. + ### wp site option @@ -3558,19 +3582,25 @@ wp site option Sets one or more sites as private. ~~~ -wp site private <id>... +wp site private [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to set as private. + [<id>...] + One or more IDs of sites to set as private. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be set as private. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site private 123 Success: Site 123 marked as private. + $ wp site private --slug=demo + Success: Site 123 marked as private. + ### wp site public @@ -3578,19 +3608,25 @@ wp site private <id>... Sets one or more sites as public. ~~~ -wp site public <id>... +wp site public [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to set as public. + [<id>...] + One or more IDs of sites to set as public. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be set as public. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site public 123 Success: Site 123 marked as public. + $ wp site public --slug=demo + Success: Site 123 marked as public. + ### wp site spam @@ -3598,13 +3634,16 @@ wp site public <id>... Marks one or more sites as spam. ~~~ -wp site spam <id>... +wp site spam [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to be marked as spam. + [<id>...] + One or more IDs of sites to be marked as spam. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be marked as spam. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** @@ -3618,19 +3657,25 @@ wp site spam <id>... Unarchives one or more sites. ~~~ -wp site unarchive <id>... +wp site unarchive [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to unarchive. + [<id>...] + One or more IDs of sites to unarchive. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to unarchive. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** $ wp site unarchive 123 Success: Site 123 unarchived. + $ wp site unarchive --slug=demo + Success: Site 123 unarchived. + ### wp site unmature @@ -3638,17 +3683,23 @@ wp site unarchive <id>... Sets one or more sites as immature. ~~~ -wp site unmature <id>... +wp site unmature [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to set as unmature. + [<id>...] + One or more IDs of sites to set as unmature. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be set as unmature. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** - $ wp site general 123 + $ wp site unmature 123 + Success: Site 123 marked as unmature. + + $ wp site unmature --slug=demo Success: Site 123 marked as unmature. @@ -3658,13 +3709,16 @@ wp site unmature <id>... Removes one or more sites from spam. ~~~ -wp site unspam <id>... +wp site unspam [<id>...] [--slug=<slug>] ~~~ **OPTIONS** - <id>... - One or more IDs of sites to remove from spam. + [<id>...] + One or more IDs of sites to remove from spam. If not provided, you must set the --slug parameter. + + [--slug=<slug>] + Path of the site to be removed from spam. Subdomain on subdomain installs, directory on subdirectory installs. **EXAMPLES** diff --git a/features/site.feature b/features/site.feature index e503f6bc4..7f343d42d 100644 --- a/features/site.feature +++ b/features/site.feature @@ -148,6 +148,38 @@ Feature: Manage sites in a multisite installation {SCHEME}://example.com/first/ """ + Scenario: Not providing a site ID or slug when running an update blog status command should throw an error + Given a WP multisite install + + When I try `wp site private` + Then the return code should be 1 + And STDERR should be: + """ + Error: Please specify one or more IDs of sites, or pass the slug for a single site using --slug. + """ + And STDOUT should be empty + + Scenario: Site IDs or a slug can be provided, but not both. + Given a WP multisite install + And I run `wp site create --slug=first --porcelain` + + When I try `wp site private 1 --slug=first` + Then the return code should be 1 + And STDERR should be: + """ + Error: Please specify one or more IDs of sites, or pass the slug for a single site using --slug. + """ + + Scenario: Errors for an invalid slug + Given a WP multisite install + + When I try `wp site private --slug=first` + Then the return code should be 1 + And STDERR should be: + """ + Error: Could not find site with slug 'first'. + """ + Scenario: Archive/unarchive a site Given a WP multisite install And I run `wp site create --slug=first --porcelain` @@ -440,3 +472,208 @@ Feature: Manage sites in a multisite installation """ My\Site """ + + Scenario: Activate/deactivate a site by slug + Given a WP multisite install + + When I run `wp site create --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 created: http + """ + And STDOUT should contain: + """ + ://example.com/first/ + """ + + When I run `wp site deactivate --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 deactivated. + """ + + When I run `wp site list --fields=blog_id,deleted` + Then STDOUT should be a table containing rows: + | blog_id | deleted | + | 2 | 1 | + + When I try `wp site deactivate --slug=first` + Then STDERR should be: + """ + Warning: Site 2 already deactivated. + """ + + When I run `wp site activate --slug=first` + Then STDOUT should be: + """ + Success: Site 2 activated. + """ + + When I run `wp site list --fields=blog_id,deleted` + Then STDOUT should be a table containing rows: + | blog_id | deleted | + | 2 | 0 | + + Scenario: Archive/unarchive a site by slug + Given a WP multisite install + + When I run `wp site create --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 created: http + """ + And STDOUT should contain: + """ + ://example.com/first/ + """ + + When I run `wp site archive --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 archived. + """ + + When I run `wp site list --fields=blog_id,archived` + Then STDOUT should be a table containing rows: + | blog_id | archived | + | 2 | 1 | + + When I try `wp site archive --slug=first` + Then STDERR should be: + """ + Warning: Site 2 already archived. + """ + + When I run `wp site unarchive --slug=first` + Then STDOUT should be: + """ + Success: Site 2 unarchived. + """ + + When I run `wp site list --fields=blog_id,archived` + Then STDOUT should be a table containing rows: + | blog_id | archived | + | 2 | 0 | + + Scenario: Mark/remove a site by slug from spam + Given a WP multisite install + + When I run `wp site create --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 created: http + """ + And STDOUT should contain: + """ + ://example.com/first/ + """ + + When I run `wp site spam --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 marked as spam. + """ + + When I run `wp site list --fields=blog_id,spam` + Then STDOUT should be a table containing rows: + | blog_id | spam | + | 2 | 1 | + + When I try `wp site spam --slug=first` + Then STDERR should be: + """ + Warning: Site 2 already marked as spam. + """ + + When I run `wp site unspam --slug=first` + Then STDOUT should be: + """ + Success: Site 2 removed from spam. + """ + + When I run `wp site list --fields=blog_id,spam` + Then STDOUT should be a table containing rows: + | blog_id | spam | + | 2 | 0 | + + Scenario: Mark/remove a site by slug as mature + Given a WP multisite install + + When I run `wp site create --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 created: http + """ + And STDOUT should contain: + """ + ://example.com/first/ + """ + + When I run `wp site mature --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 marked as mature. + """ + + When I run `wp site list --fields=blog_id,mature` + Then STDOUT should be a table containing rows: + | blog_id | mature | + | 2 | 1 | + + When I try `wp site mature --slug=first` + Then STDERR should be: + """ + Warning: Site 2 already marked as mature. + """ + + When I run `wp site unmature --slug=first` + Then STDOUT should be: + """ + Success: Site 2 marked as unmature. + """ + + When I run `wp site list --fields=blog_id,mature` + Then STDOUT should be a table containing rows: + | blog_id | mature | + | 2 | 0 | + + Scenario: Set/Unset a site by slug as public + Given a WP multisite install + + When I run `wp site create --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 created: http + """ + And STDOUT should contain: + """ + ://example.com/first/ + """ + + When I run `wp site private --slug=first` + Then STDOUT should contain: + """ + Success: Site 2 marked as private. + """ + + When I run `wp site list --fields=blog_id,public` + Then STDOUT should be a table containing rows: + | blog_id | public | + | 2 | 0 | + + When I try `wp site private --slug=first` + Then STDERR should be: + """ + Warning: Site 2 already marked as private. + """ + + When I run `wp site public --slug=first` + Then STDOUT should be: + """ + Success: Site 2 marked as public. + """ + + When I run `wp site list --fields=blog_id,public` + Then STDOUT should be a table containing rows: + | blog_id | public | + | 2 | 1 | diff --git a/src/Site_Command.php b/src/Site_Command.php index a074a9723..1721a6248 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -1,6 +1,7 @@ <?php use WP_CLI\CommandWithDBObject; +use WP_CLI\ExitException; use WP_CLI\Fetchers\Site as SiteFetcher; use WP_CLI\Iterators\Query as QueryIterator; use WP_CLI\Iterators\Table as TableIterator; @@ -311,7 +312,7 @@ public function empty_( $args, $assoc_args ) { * : The id of the site to delete. If not provided, you must set the --slug parameter. * * [--slug=<slug>] - * : Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. + * : Path of the site to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. * * [--yes] * : Answer yes to the confirmation message. @@ -638,16 +639,28 @@ function ( $blog ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to archive. + * [<id>...] + * : One or more IDs of sites to archive. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to archive. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site archive 123 * Success: Site 123 archived. + * + * $ wp site archive --slug=demo + * Success: Site 123 archived. */ - public function archive( $args ) { - $this->update_site_status( $args, 'archived', 1 ); + public function archive( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'archived', 1 ); } /** @@ -655,16 +668,28 @@ public function archive( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to unarchive. + * [<id>...] + * : One or more IDs of sites to unarchive. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to unarchive. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site unarchive 123 * Success: Site 123 unarchived. + * + * $ wp site unarchive --slug=demo + * Success: Site 123 unarchived. */ - public function unarchive( $args ) { - $this->update_site_status( $args, 'archived', 0 ); + public function unarchive( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'archived', 0 ); } /** @@ -672,16 +697,28 @@ public function unarchive( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to activate. + * [<id>...] + * : One or more IDs of sites to activate. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be activated. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site activate 123 * Success: Site 123 activated. + * + * $ wp site activate --slug=demo + * Success: Site 123 marked as activated. */ - public function activate( $args ) { - $this->update_site_status( $args, 'deleted', 0 ); + public function activate( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'deleted', 0 ); } /** @@ -689,16 +726,28 @@ public function activate( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to deactivate. + * [<id>...] + * : One or more IDs of sites to deactivate. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be deactivated. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site deactivate 123 * Success: Site 123 deactivated. + * + * $ wp site deactivate --slug=demo + * Success: Site 123 marked as deactivated. */ - public function deactivate( $args ) { - $this->update_site_status( $args, 'deleted', 1 ); + public function deactivate( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'deleted', 1 ); } /** @@ -706,16 +755,25 @@ public function deactivate( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to be marked as spam. + * [<id>...] + * : One or more IDs of sites to be marked as spam. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be marked as spam. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site spam 123 * Success: Site 123 marked as spam. */ - public function spam( $args ) { - $this->update_site_status( $args, 'spam', 1 ); + public function spam( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'spam', 1 ); } /** @@ -723,8 +781,11 @@ public function spam( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to remove from spam. + * [<id>...] + * : One or more IDs of sites to remove from spam. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be removed from spam. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * @@ -733,8 +794,14 @@ public function spam( $args ) { * * @subcommand unspam */ - public function unspam( $args ) { - $this->update_site_status( $args, 'spam', 0 ); + public function unspam( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'spam', 0 ); } /** @@ -742,16 +809,28 @@ public function unspam( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to set as mature. + * [<id>...] + * : One or more IDs of sites to set as mature. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be set as mature. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site mature 123 * Success: Site 123 marked as mature. + * + * $ wp site mature --slug=demo + * Success: Site 123 marked as mature. */ - public function mature( $args ) { - $this->update_site_status( $args, 'mature', 1 ); + public function mature( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'mature', 1 ); } /** @@ -759,16 +838,28 @@ public function mature( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to set as unmature. + * [<id>...] + * : One or more IDs of sites to set as unmature. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be set as unmature. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * - * $ wp site general 123 + * $ wp site unmature 123 + * Success: Site 123 marked as unmature. + * + * $ wp site unmature --slug=demo * Success: Site 123 marked as unmature. */ - public function unmature( $args ) { - $this->update_site_status( $args, 'mature', 0 ); + public function unmature( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'mature', 0 ); } /** @@ -776,18 +867,30 @@ public function unmature( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to set as public. + * [<id>...] + * : One or more IDs of sites to set as public. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be set as public. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site public 123 * Success: Site 123 marked as public. * + * $ wp site public --slug=demo + * Success: Site 123 marked as public. + * * @subcommand public */ - public function set_public( $args ) { - $this->update_site_status( $args, 'public', 1 ); + public function set_public( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'public', 1 ); } /** @@ -795,18 +898,30 @@ public function set_public( $args ) { * * ## OPTIONS * - * <id>... - * : One or more IDs of sites to set as private. + * [<id>...] + * : One or more IDs of sites to set as private. If not provided, you must set the --slug parameter. + * + * [--slug=<slug>] + * : Path of the site to be set as private. Subdomain on subdomain installs, directory on subdirectory installs. * * ## EXAMPLES * * $ wp site private 123 * Success: Site 123 marked as private. * + * $ wp site private --slug=demo + * Success: Site 123 marked as private. + * * @subcommand private */ - public function set_private( $args ) { - $this->update_site_status( $args, 'public', 0 ); + public function set_private( $args, $assoc_args ) { + if ( ! $this->check_site_ids_and_slug( $args, $assoc_args ) ) { + return; + } + + $ids = $this->get_sites_ids( $args, $assoc_args ); + + $this->update_site_status( $ids, 'public', 0 ); } private function update_site_status( $ids, $pref, $value ) { @@ -849,4 +964,45 @@ private function update_site_status( $ids, $pref, $value ) { WP_CLI::success( "Site {$site->blog_id} {$action}." ); } } + + /** + * Get an array of site IDs from the passed-in arguments or slug parameter. + * + * @param array $args Passed-in arguments. + * @param array $assoc_args Passed-in parameters. + * + * @return array Site IDs. + * @throws ExitException + */ + private function get_sites_ids( $args, $assoc_args ) { + $slug = Utils\get_flag_value( $assoc_args, 'slug', false ); + + if ( $slug ) { + $blog = get_blog_details( trim( $slug, '/' ) ); + if ( ! $blog ) { + WP_CLI::error( sprintf( 'Could not find site with slug \'%s\'.', $slug ) ); + } + return [ $blog->blog_id ]; + } + + return $args; + } + + /** + * Check that the site IDs or slug are provided. + * + * @param array $args Passed-in arguments. + * @param array $assoc_args Passed-in parameters. + * + * @return bool + * @throws ExitException If neither site ids nor site slug using --slug were provided. + */ + private function check_site_ids_and_slug( $args, $assoc_args ) { + if ( ( empty( $args ) && empty( $assoc_args['slug'] ) ) + || ( ! empty( $args ) && ! empty( $assoc_args['slug'] ) ) ) { + WP_CLI::error( 'Please specify one or more IDs of sites, or pass the slug for a single site using --slug.' ); + } + + return true; + } }