@@ -424,8 +424,7 @@ public function create( $args, $assoc_args ) {
424
424
425
425
// If not a subdomain install, make sure the domain isn't a reserved word
426
426
if ( ! is_subdomain_install () ) {
427
- // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling WordPress native hook.
428
- $ subdirectory_reserved_names = apply_filters ( 'subdirectory_reserved_names ' , [ 'page ' , 'comments ' , 'blog ' , 'files ' , 'feed ' ] );
427
+ $ subdirectory_reserved_names = $ this ->get_subdirectory_reserved_names ();
429
428
if ( in_array ( $ base , $ subdirectory_reserved_names , true ) ) {
430
429
WP_CLI ::error ( 'The following words are reserved and cannot be used as blog names: ' . implode ( ', ' , $ subdirectory_reserved_names ) );
431
430
}
@@ -487,6 +486,194 @@ public function create( $args, $assoc_args ) {
487
486
}
488
487
}
489
488
489
+ /**
490
+ * Generate some sites.
491
+ *
492
+ * Creates a specified number of new sites.
493
+ *
494
+ * ## OPTIONS
495
+ *
496
+ * [--count=<number>]
497
+ * : How many sites to generates?
498
+ * ---
499
+ * default: 100
500
+ * ---
501
+ *
502
+ * [--slug=<slug>]
503
+ * : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs.
504
+ *
505
+ * [--email=<email>]
506
+ * : Email for admin user. User will be created if none exists. Assignment to super admin if not included.
507
+ *
508
+ * [--network_id=<network-id>]
509
+ * : Network to associate new site with. Defaults to current network (typically 1).
510
+ *
511
+ * [--private]
512
+ * : If set, the new site will be non-public (not indexed)
513
+ *
514
+ * [--format=<format>]
515
+ * : Render output in a particular format.
516
+ * ---
517
+ * default: progress
518
+ * options:
519
+ * - progress
520
+ * - ids
521
+ * ---
522
+ *
523
+ * ## EXAMPLES
524
+ *
525
+ * # Generate 10 sites.
526
+ * $ wp site generate --count=10
527
+ * Generating sites 100% [================================================] 0:01 / 0:04
528
+ */
529
+ public function generate ( $ args , $ assoc_args ) {
530
+ if ( ! is_multisite () ) {
531
+ WP_CLI ::error ( 'This is not a multisite installation. ' );
532
+ }
533
+
534
+ global $ wpdb , $ current_site ;
535
+
536
+ $ defaults = [
537
+ 'count ' => 100 ,
538
+ 'email ' => '' ,
539
+ 'network_id ' => 1 ,
540
+ 'slug ' => 'site ' ,
541
+ ];
542
+
543
+ $ assoc_args = array_merge ( $ defaults , $ assoc_args );
544
+
545
+ // Base.
546
+ $ base = $ assoc_args ['slug ' ];
547
+ if ( preg_match ( '|^([a-zA-Z0-9-])+$| ' , $ base ) ) {
548
+ $ base = strtolower ( $ base );
549
+ }
550
+
551
+ $ is_subdomain_install = is_subdomain_install ();
552
+ // If not a subdomain install, make sure the domain isn't a reserved word
553
+ if ( ! $ is_subdomain_install ) {
554
+ $ subdirectory_reserved_names = $ this ->get_subdirectory_reserved_names ();
555
+ if ( in_array ( $ base , $ subdirectory_reserved_names , true ) ) {
556
+ WP_CLI ::error ( 'The following words are reserved and cannot be used as blog names: ' . implode ( ', ' , $ subdirectory_reserved_names ) );
557
+ }
558
+ }
559
+
560
+ // Network.
561
+ if ( ! empty ( $ assoc_args ['network_id ' ] ) ) {
562
+ $ network = $ this ->get_network ( $ assoc_args ['network_id ' ] );
563
+ if ( false === $ network ) {
564
+ WP_CLI ::error ( "Network with id {$ assoc_args ['network_id ' ]} does not exist. " );
565
+ }
566
+ } else {
567
+ $ network = $ current_site ;
568
+ }
569
+
570
+ // Public.
571
+ $ public = ! Utils \get_flag_value ( $ assoc_args , 'private ' );
572
+
573
+ // Limit.
574
+ $ limit = $ assoc_args ['count ' ];
575
+
576
+ // Email.
577
+ $ email = sanitize_email ( $ assoc_args ['email ' ] );
578
+ if ( empty ( $ email ) || ! is_email ( $ email ) ) {
579
+ $ super_admins = get_super_admins ();
580
+ $ email = '' ;
581
+ if ( ! empty ( $ super_admins ) && is_array ( $ super_admins ) ) {
582
+ $ super_login = reset ( $ super_admins );
583
+ $ super_user = get_user_by ( 'login ' , $ super_login );
584
+ if ( $ super_user ) {
585
+ $ email = $ super_user ->user_email ;
586
+ }
587
+ }
588
+ }
589
+
590
+ $ user_id = email_exists ( $ email );
591
+ if ( ! $ user_id ) {
592
+ $ password = wp_generate_password ( 24 , false );
593
+ $ user_id = wpmu_create_user ( $ base . '-admin ' , $ password , $ email );
594
+
595
+ if ( false === $ user_id ) {
596
+ WP_CLI ::error ( "Can't create user. " );
597
+ } else {
598
+ User_Command::wp_new_user_notification ( $ user_id , $ password );
599
+ }
600
+ }
601
+
602
+ $ format = Utils \get_flag_value ( $ assoc_args , 'format ' , 'progress ' );
603
+
604
+ $ notify = false ;
605
+ if ( 'progress ' === $ format ) {
606
+ $ notify = Utils \make_progress_bar ( 'Generating sites ' , $ limit );
607
+ }
608
+
609
+ for ( $ index = 1 ; $ index <= $ limit ; $ index ++ ) {
610
+ $ current_base = $ base . $ index ;
611
+ $ title = ucfirst ( $ base ) . ' ' . $ index ;
612
+
613
+ if ( $ is_subdomain_install ) {
614
+ $ new_domain = $ current_base . '. ' . preg_replace ( '|^www\.| ' , '' , $ network ->domain );
615
+ $ path = $ network ->path ;
616
+ } else {
617
+ $ new_domain = $ network ->domain ;
618
+ $ path = $ network ->path . $ current_base . '/ ' ;
619
+ }
620
+
621
+ $ wpdb ->hide_errors ();
622
+ $ title = wp_slash ( $ title );
623
+ $ id = wpmu_create_blog ( $ new_domain , $ path , $ title , $ user_id , [ 'public ' => $ public ], $ network ->id );
624
+ $ wpdb ->show_errors ();
625
+ if ( ! is_wp_error ( $ id ) ) {
626
+ if ( ! is_super_admin ( $ user_id ) && ! get_user_option ( 'primary_blog ' , $ user_id ) ) {
627
+ update_user_option ( $ user_id , 'primary_blog ' , $ id , true );
628
+ }
629
+ } else {
630
+ WP_CLI ::error ( $ id ->get_error_message () );
631
+ }
632
+
633
+ if ( 'progress ' === $ format ) {
634
+ $ notify ->tick ();
635
+ } else {
636
+ echo $ id ;
637
+ if ( $ index < $ limit - 1 ) {
638
+ echo ' ' ;
639
+ }
640
+ }
641
+ }
642
+
643
+ if ( 'progress ' === $ format ) {
644
+ $ notify ->finish ();
645
+ }
646
+ }
647
+
648
+ /**
649
+ * Retrieves a list of reserved site on a sub-directory Multisite installation.
650
+ *
651
+ * Works on older WordPress versions where get_subdirectory_reserved_names() does not exist.
652
+ *
653
+ * @return string[] Array of reserved names.
654
+ */
655
+ private function get_subdirectory_reserved_names () {
656
+ if ( function_exists ( 'get_subdirectory_reserved_names ' ) ) {
657
+ return get_subdirectory_reserved_names ();
658
+ }
659
+
660
+ $ names = array (
661
+ 'page ' ,
662
+ 'comments ' ,
663
+ 'blog ' ,
664
+ 'files ' ,
665
+ 'feed ' ,
666
+ 'wp-admin ' ,
667
+ 'wp-content ' ,
668
+ 'wp-includes ' ,
669
+ 'wp-json ' ,
670
+ 'embed ' ,
671
+ );
672
+
673
+ // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling WordPress native hook.
674
+ return apply_filters ( 'subdirectory_reserved_names ' , $ names );
675
+ }
676
+
490
677
/**
491
678
* Gets network data for a given id.
492
679
*
0 commit comments