Skip to content

Commit

Permalink
Merge pull request #498 from i-am-chitti/GH-231/site-generate
Browse files Browse the repository at this point in the history
  • Loading branch information
swissspidy authored May 4, 2024
2 parents 3648d0e + 9bd8441 commit 93476c2
Show file tree
Hide file tree
Showing 3 changed files with 297 additions and 2 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"site activate",
"site archive",
"site create",
"site generate",
"site deactivate",
"site delete",
"site empty",
Expand Down
107 changes: 107 additions & 0 deletions features/site-generate.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
Feature: Generate new WordPress sites

Scenario: Generate on single site
Given a WP install
When I try `wp site generate`
Then STDERR should contain:
"""
This is not a multisite installation.
"""
And STDOUT should be empty
And the return code should be 1

Scenario: Generate a specific number of sites
Given a WP multisite install
When I run `wp site generate --count=10`
And I run `wp site list --format=count`
Then STDOUT should be:
"""
11
"""

Scenario: Generate sites assigned to a specific network
Given a WP multisite install
When I try `wp site generate --count=4 --network_id=2`
Then STDERR should contain:
"""
Network with id 2 does not exist.
"""
And STDOUT should be empty
And the return code should be 1

Scenario: Generate sites and output ids
Given a WP multisite install
When I run `wp site generate --count=3 --format=ids`
When I run `wp site list --format=ids`
Then STDOUT should be:
"""
1 2 3 4
"""
And STDERR should be empty
And the return code should be 0

Scenario: Generate subdomain sites
Given a WP multisite subdomain install

When I run `wp site generate --count=1`
Then STDOUT should be empty

When I run `wp site list --fields=blog_id,url`
Then STDOUT should be a table containing rows:
| blog_id | url |
| 1 | https://example.com/ |
| 2 | http://site1.example.com/ |
When I run `wp site list --format=ids`
Then STDOUT should be:
"""
1 2
"""

Scenario: Generate subdirectory sites
Given a WP multisite subdirectory install
When I run `wp site generate --count=1`
Then STDOUT should be empty
And I run `wp site list --site__in=2 --field=url | sed -e's,^\(.*\)://.*,\1,g'`
And save STDOUT as {SCHEME}

When I run `wp site list --fields=blog_id,url`
Then STDOUT should be a table containing rows:
| blog_id | url |
| 1 | https://example.com/ |
| 2 | {SCHEME}://example.com/site1/ |
When I run `wp site list --format=ids`
Then STDOUT should be:
"""
1 2
"""

Scenario: Generate sites with a slug
Given a WP multisite subdirectory install
When I run `wp site generate --count=2 --slug=subsite`
Then STDOUT should be empty
And I run `wp site list --site__in=2 --field=url | sed -e's,^\(.*\)://.*,\1,g'`
And save STDOUT as {SCHEME1}
And I run `wp site list --site__in=3 --field=url | sed -e's,^\(.*\)://.*,\1,g'`
And save STDOUT as {SCHEME2}

When I run `wp site list --fields=blog_id,url`
Then STDOUT should be a table containing rows:
| blog_id | url |
| 1 | https://example.com/ |
| 2 | {SCHEME1}://example.com/subsite1/ |
| 3 | {SCHEME2}://example.com/subsite2/ |
When I run `wp site list --format=ids`
Then STDOUT should be:
"""
1 2 3
"""

Scenario: Generate sites with reserved slug
Given a WP multisite subdirectory install
When I try `wp site generate --count=2 --slug=page`
Then STDERR should contain:
"""
The following words are reserved and cannot be used as blog names: page, comments, blog, files, feed
"""
And STDOUT should be empty
And the return code should be 1
191 changes: 189 additions & 2 deletions src/Site_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,7 @@ public function create( $args, $assoc_args ) {

// If not a subdomain install, make sure the domain isn't a reserved word
if ( ! is_subdomain_install() ) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling WordPress native hook.
$subdirectory_reserved_names = apply_filters( 'subdirectory_reserved_names', [ 'page', 'comments', 'blog', 'files', 'feed' ] );
$subdirectory_reserved_names = $this->get_subdirectory_reserved_names();
if ( in_array( $base, $subdirectory_reserved_names, true ) ) {
WP_CLI::error( 'The following words are reserved and cannot be used as blog names: ' . implode( ', ', $subdirectory_reserved_names ) );
}
Expand Down Expand Up @@ -487,6 +486,194 @@ public function create( $args, $assoc_args ) {
}
}

/**
* Generate some sites.
*
* Creates a specified number of new sites.
*
* ## OPTIONS
*
* [--count=<number>]
* : How many sites to generates?
* ---
* default: 100
* ---
*
* [--slug=<slug>]
* : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs.
*
* [--email=<email>]
* : Email for admin user. User will be created if none exists. Assignment to super admin if not included.
*
* [--network_id=<network-id>]
* : Network to associate new site with. Defaults to current network (typically 1).
*
* [--private]
* : If set, the new site will be non-public (not indexed)
*
* [--format=<format>]
* : Render output in a particular format.
* ---
* default: progress
* options:
* - progress
* - ids
* ---
*
* ## EXAMPLES
*
* # Generate 10 sites.
* $ wp site generate --count=10
* Generating sites 100% [================================================] 0:01 / 0:04
*/
public function generate( $args, $assoc_args ) {
if ( ! is_multisite() ) {
WP_CLI::error( 'This is not a multisite installation.' );
}

global $wpdb, $current_site;

$defaults = [
'count' => 100,
'email' => '',
'network_id' => 1,
'slug' => 'site',
];

$assoc_args = array_merge( $defaults, $assoc_args );

// Base.
$base = $assoc_args['slug'];
if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) {
$base = strtolower( $base );
}

$is_subdomain_install = is_subdomain_install();
// If not a subdomain install, make sure the domain isn't a reserved word
if ( ! $is_subdomain_install ) {
$subdirectory_reserved_names = $this->get_subdirectory_reserved_names();
if ( in_array( $base, $subdirectory_reserved_names, true ) ) {
WP_CLI::error( 'The following words are reserved and cannot be used as blog names: ' . implode( ', ', $subdirectory_reserved_names ) );
}
}

// Network.
if ( ! empty( $assoc_args['network_id'] ) ) {
$network = $this->get_network( $assoc_args['network_id'] );
if ( false === $network ) {
WP_CLI::error( "Network with id {$assoc_args['network_id']} does not exist." );
}
} else {
$network = $current_site;
}

// Public.
$public = ! Utils\get_flag_value( $assoc_args, 'private' );

// Limit.
$limit = $assoc_args['count'];

// Email.
$email = sanitize_email( $assoc_args['email'] );
if ( empty( $email ) || ! is_email( $email ) ) {
$super_admins = get_super_admins();
$email = '';
if ( ! empty( $super_admins ) && is_array( $super_admins ) ) {
$super_login = reset( $super_admins );
$super_user = get_user_by( 'login', $super_login );
if ( $super_user ) {
$email = $super_user->user_email;
}
}
}

$user_id = email_exists( $email );
if ( ! $user_id ) {
$password = wp_generate_password( 24, false );
$user_id = wpmu_create_user( $base . '-admin', $password, $email );

if ( false === $user_id ) {
WP_CLI::error( "Can't create user." );
} else {
User_Command::wp_new_user_notification( $user_id, $password );
}
}

$format = Utils\get_flag_value( $assoc_args, 'format', 'progress' );

$notify = false;
if ( 'progress' === $format ) {
$notify = Utils\make_progress_bar( 'Generating sites', $limit );
}

for ( $index = 1; $index <= $limit; $index++ ) {
$current_base = $base . $index;
$title = ucfirst( $base ) . ' ' . $index;

if ( $is_subdomain_install ) {
$new_domain = $current_base . '.' . preg_replace( '|^www\.|', '', $network->domain );
$path = $network->path;
} else {
$new_domain = $network->domain;
$path = $network->path . $current_base . '/';
}

$wpdb->hide_errors();
$title = wp_slash( $title );
$id = wpmu_create_blog( $new_domain, $path, $title, $user_id, [ 'public' => $public ], $network->id );
$wpdb->show_errors();
if ( ! is_wp_error( $id ) ) {
if ( ! is_super_admin( $user_id ) && ! get_user_option( 'primary_blog', $user_id ) ) {
update_user_option( $user_id, 'primary_blog', $id, true );
}
} else {
WP_CLI::error( $id->get_error_message() );
}

if ( 'progress' === $format ) {
$notify->tick();
} else {
echo $id;
if ( $index < $limit - 1 ) {
echo ' ';
}
}
}

if ( 'progress' === $format ) {
$notify->finish();
}
}

/**
* Retrieves a list of reserved site on a sub-directory Multisite installation.
*
* Works on older WordPress versions where get_subdirectory_reserved_names() does not exist.
*
* @return string[] Array of reserved names.
*/
private function get_subdirectory_reserved_names() {
if ( function_exists( 'get_subdirectory_reserved_names' ) ) {
return get_subdirectory_reserved_names();
}

$names = array(
'page',
'comments',
'blog',
'files',
'feed',
'wp-admin',
'wp-content',
'wp-includes',
'wp-json',
'embed',
);

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling WordPress native hook.
return apply_filters( 'subdirectory_reserved_names', $names );
}

/**
* Gets network data for a given id.
*
Expand Down

0 comments on commit 93476c2

Please sign in to comment.