[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> ms-functions.php (source)

   1  <?php
   2  /**
   3   * Multisite WordPress API
   4   *
   5   * @package WordPress
   6   * @subpackage Multisite
   7   * @since 3.0.0
   8   */
   9  
  10  /**
  11   * Gets the network's site and user counts.
  12   *
  13   * @since MU (3.0.0)
  14   *
  15   * @return int[] {
  16   *     Site and user count for the network.
  17   *
  18   *     @type int $blogs Number of sites on the network.
  19   *     @type int $users Number of users on the network.
  20   * }
  21   */
  22  function get_sitestats() {
  23      $stats = array(
  24          'blogs' => get_blog_count(),
  25          'users' => get_user_count(),
  26      );
  27  
  28      return $stats;
  29  }
  30  
  31  /**
  32   * Gets one of a user's active blogs.
  33   *
  34   * Returns the user's primary blog, if they have one and
  35   * it is active. If it's inactive, function returns another
  36   * active blog of the user. If none are found, the user
  37   * is added as a Subscriber to the Dashboard Blog and that blog
  38   * is returned.
  39   *
  40   * @since MU (3.0.0)
  41   *
  42   * @param int $user_id The unique ID of the user
  43   * @return WP_Site|void The blog object
  44   */
  45  function get_active_blog_for_user( $user_id ) {
  46      $blogs = get_blogs_of_user( $user_id );
  47      if ( empty( $blogs ) ) {
  48          return;
  49      }
  50  
  51      if ( ! is_multisite() ) {
  52          return $blogs[ get_current_blog_id() ];
  53      }
  54  
  55      $primary_blog = get_user_meta( $user_id, 'primary_blog', true );
  56      $first_blog   = current( $blogs );
  57      if ( false !== $primary_blog ) {
  58          if ( ! isset( $blogs[ $primary_blog ] ) ) {
  59              update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
  60              $primary = get_site( $first_blog->userblog_id );
  61          } else {
  62              $primary = get_site( $primary_blog );
  63          }
  64      } else {
  65          // TODO: Review this call to add_user_to_blog too - to get here the user must have a role on this blog?
  66          $result = add_user_to_blog( $first_blog->userblog_id, $user_id, 'subscriber' );
  67  
  68          if ( ! is_wp_error( $result ) ) {
  69              update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
  70              $primary = $first_blog;
  71          }
  72      }
  73  
  74      if ( ( ! is_object( $primary ) ) || ( 1 == $primary->archived || 1 == $primary->spam || 1 == $primary->deleted ) ) {
  75          $blogs = get_blogs_of_user( $user_id, true ); // If a user's primary blog is shut down, check their other blogs.
  76          $ret   = false;
  77          if ( is_array( $blogs ) && count( $blogs ) > 0 ) {
  78              foreach ( (array) $blogs as $blog_id => $blog ) {
  79                  if ( get_current_network_id() != $blog->site_id ) {
  80                      continue;
  81                  }
  82                  $details = get_site( $blog_id );
  83                  if ( is_object( $details ) && 0 == $details->archived && 0 == $details->spam && 0 == $details->deleted ) {
  84                      $ret = $details;
  85                      if ( get_user_meta( $user_id, 'primary_blog', true ) != $blog_id ) {
  86                          update_user_meta( $user_id, 'primary_blog', $blog_id );
  87                      }
  88                      if ( ! get_user_meta( $user_id, 'source_domain', true ) ) {
  89                          update_user_meta( $user_id, 'source_domain', $details->domain );
  90                      }
  91                      break;
  92                  }
  93              }
  94          } else {
  95              return;
  96          }
  97          return $ret;
  98      } else {
  99          return $primary;
 100      }
 101  }
 102  
 103  /**
 104   * Gets the number of active sites on the installation.
 105   *
 106   * The count is cached and updated twice daily. This is not a live count.
 107   *
 108   * @since MU (3.0.0)
 109   * @since 3.7.0 The `$network_id` parameter has been deprecated.
 110   * @since 4.8.0 The `$network_id` parameter is now being used.
 111   *
 112   * @param int|null $network_id ID of the network. Default is the current network.
 113   * @return int Number of active sites on the network.
 114   */
 115  function get_blog_count( $network_id = null ) {
 116      return get_network_option( $network_id, 'blog_count' );
 117  }
 118  
 119  /**
 120   * Gets a blog post from any site on the network.
 121   *
 122   * This function is similar to get_post(), except that it can retrieve a post
 123   * from any site on the network, not just the current site.
 124   *
 125   * @since MU (3.0.0)
 126   *
 127   * @param int $blog_id ID of the blog.
 128   * @param int $post_id ID of the post being looked for.
 129   * @return WP_Post|null WP_Post object on success, null on failure
 130   */
 131  function get_blog_post( $blog_id, $post_id ) {
 132      switch_to_blog( $blog_id );
 133      $post = get_post( $post_id );
 134      restore_current_blog();
 135  
 136      return $post;
 137  }
 138  
 139  /**
 140   * Adds a user to a blog, along with specifying the user's role.
 141   *
 142   * Use the {@see 'add_user_to_blog'} action to fire an event when users are added to a blog.
 143   *
 144   * @since MU (3.0.0)
 145   *
 146   * @param int    $blog_id ID of the blog the user is being added to.
 147   * @param int    $user_id ID of the user being added.
 148   * @param string $role    User role.
 149   * @return true|WP_Error True on success or a WP_Error object if the user doesn't exist
 150   *                       or could not be added.
 151   */
 152  function add_user_to_blog( $blog_id, $user_id, $role ) {
 153      switch_to_blog( $blog_id );
 154  
 155      $user = get_userdata( $user_id );
 156  
 157      if ( ! $user ) {
 158          restore_current_blog();
 159          return new WP_Error( 'user_does_not_exist', __( 'The requested user does not exist.' ) );
 160      }
 161  
 162      /**
 163       * Filters whether a user should be added to a site.
 164       *
 165       * @since 4.9.0
 166       *
 167       * @param true|WP_Error $retval  True if the user should be added to the site, error
 168       *                               object otherwise.
 169       * @param int           $user_id User ID.
 170       * @param string        $role    User role.
 171       * @param int           $blog_id Site ID.
 172       */
 173      $can_add_user = apply_filters( 'can_add_user_to_blog', true, $user_id, $role, $blog_id );
 174  
 175      if ( true !== $can_add_user ) {
 176          restore_current_blog();
 177  
 178          if ( is_wp_error( $can_add_user ) ) {
 179              return $can_add_user;
 180          }
 181  
 182          return new WP_Error( 'user_cannot_be_added', __( 'User cannot be added to this site.' ) );
 183      }
 184  
 185      if ( ! get_user_meta( $user_id, 'primary_blog', true ) ) {
 186          update_user_meta( $user_id, 'primary_blog', $blog_id );
 187          $site = get_site( $blog_id );
 188          update_user_meta( $user_id, 'source_domain', $site->domain );
 189      }
 190  
 191      $user->set_role( $role );
 192  
 193      /**
 194       * Fires immediately after a user is added to a site.
 195       *
 196       * @since MU (3.0.0)
 197       *
 198       * @param int    $user_id User ID.
 199       * @param string $role    User role.
 200       * @param int    $blog_id Blog ID.
 201       */
 202      do_action( 'add_user_to_blog', $user_id, $role, $blog_id );
 203  
 204      clean_user_cache( $user_id );
 205      wp_cache_delete( $blog_id . '_user_count', 'blog-details' );
 206  
 207      restore_current_blog();
 208  
 209      return true;
 210  }
 211  
 212  /**
 213   * Removes a user from a blog.
 214   *
 215   * Use the {@see 'remove_user_from_blog'} action to fire an event when
 216   * users are removed from a blog.
 217   *
 218   * Accepts an optional `$reassign` parameter, if you want to
 219   * reassign the user's blog posts to another user upon removal.
 220   *
 221   * @since MU (3.0.0)
 222   *
 223   * @global wpdb $wpdb WordPress database abstraction object.
 224   *
 225   * @param int $user_id  ID of the user being removed.
 226   * @param int $blog_id  Optional. ID of the blog the user is being removed from. Default 0.
 227   * @param int $reassign Optional. ID of the user to whom to reassign posts. Default 0.
 228   * @return true|WP_Error True on success or a WP_Error object if the user doesn't exist.
 229   */
 230  function remove_user_from_blog( $user_id, $blog_id = 0, $reassign = 0 ) {
 231      global $wpdb;
 232  
 233      switch_to_blog( $blog_id );
 234      $user_id = (int) $user_id;
 235  
 236      /**
 237       * Fires before a user is removed from a site.
 238       *
 239       * @since MU (3.0.0)
 240       * @since 5.4.0 Added the `$reassign` parameter.
 241       *
 242       * @param int $user_id  ID of the user being removed.
 243       * @param int $blog_id  ID of the blog the user is being removed from.
 244       * @param int $reassign ID of the user to whom to reassign posts.
 245       */
 246      do_action( 'remove_user_from_blog', $user_id, $blog_id, $reassign );
 247  
 248      /*
 249       * If being removed from the primary blog, set a new primary
 250       * if the user is assigned to multiple blogs.
 251       */
 252      $primary_blog = get_user_meta( $user_id, 'primary_blog', true );
 253      if ( $primary_blog == $blog_id ) {
 254          $new_id     = '';
 255          $new_domain = '';
 256          $blogs      = get_blogs_of_user( $user_id );
 257          foreach ( (array) $blogs as $blog ) {
 258              if ( $blog->userblog_id == $blog_id ) {
 259                  continue;
 260              }
 261              $new_id     = $blog->userblog_id;
 262              $new_domain = $blog->domain;
 263              break;
 264          }
 265  
 266          update_user_meta( $user_id, 'primary_blog', $new_id );
 267          update_user_meta( $user_id, 'source_domain', $new_domain );
 268      }
 269  
 270      $user = get_userdata( $user_id );
 271      if ( ! $user ) {
 272          restore_current_blog();
 273          return new WP_Error( 'user_does_not_exist', __( 'That user does not exist.' ) );
 274      }
 275  
 276      $user->remove_all_caps();
 277  
 278      $blogs = get_blogs_of_user( $user_id );
 279      if ( count( $blogs ) === 0 ) {
 280          update_user_meta( $user_id, 'primary_blog', '' );
 281          update_user_meta( $user_id, 'source_domain', '' );
 282      }
 283  
 284      if ( $reassign ) {
 285          $reassign = (int) $reassign;
 286          $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $user_id ) );
 287          $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $user_id ) );
 288  
 289          if ( ! empty( $post_ids ) ) {
 290              $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_author = %d WHERE post_author = %d", $reassign, $user_id ) );
 291              array_walk( $post_ids, 'clean_post_cache' );
 292          }
 293  
 294          if ( ! empty( $link_ids ) ) {
 295              $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->links SET link_owner = %d WHERE link_owner = %d", $reassign, $user_id ) );
 296              array_walk( $link_ids, 'clean_bookmark_cache' );
 297          }
 298      }
 299  
 300      clean_user_cache( $user_id );
 301      restore_current_blog();
 302  
 303      return true;
 304  }
 305  
 306  /**
 307   * Gets the permalink for a post on another blog.
 308   *
 309   * @since MU (3.0.0) 1.0
 310   *
 311   * @param int $blog_id ID of the source blog.
 312   * @param int $post_id ID of the desired post.
 313   * @return string The post's permalink.
 314   */
 315  function get_blog_permalink( $blog_id, $post_id ) {
 316      switch_to_blog( $blog_id );
 317      $link = get_permalink( $post_id );
 318      restore_current_blog();
 319  
 320      return $link;
 321  }
 322  
 323  /**
 324   * Gets a blog's numeric ID from its URL.
 325   *
 326   * On a subdirectory installation like example.com/blog1/,
 327   * $domain will be the root 'example.com' and $path the
 328   * subdirectory '/blog1/'. With subdomains like blog1.example.com,
 329   * $domain is 'blog1.example.com' and $path is '/'.
 330   *
 331   * @since MU (3.0.0)
 332   *
 333   * @global wpdb $wpdb WordPress database abstraction object.
 334   *
 335   * @param string $domain Website domain.
 336   * @param string $path   Optional. Not required for subdomain installations. Default '/'.
 337   * @return int 0 if no blog found, otherwise the ID of the matching blog.
 338   */
 339  function get_blog_id_from_url( $domain, $path = '/' ) {
 340      $domain = strtolower( $domain );
 341      $path   = strtolower( $path );
 342      $id     = wp_cache_get( md5( $domain . $path ), 'blog-id-cache' );
 343  
 344      if ( -1 == $id ) { // Blog does not exist.
 345          return 0;
 346      } elseif ( $id ) {
 347          return (int) $id;
 348      }
 349  
 350      $args   = array(
 351          'domain'                 => $domain,
 352          'path'                   => $path,
 353          'fields'                 => 'ids',
 354          'number'                 => 1,
 355          'update_site_meta_cache' => false,
 356      );
 357      $result = get_sites( $args );
 358      $id     = array_shift( $result );
 359  
 360      if ( ! $id ) {
 361          wp_cache_set( md5( $domain . $path ), -1, 'blog-id-cache' );
 362          return 0;
 363      }
 364  
 365      wp_cache_set( md5( $domain . $path ), $id, 'blog-id-cache' );
 366  
 367      return $id;
 368  }
 369  
 370  //
 371  // Admin functions.
 372  //
 373  
 374  /**
 375   * Checks an email address against a list of banned domains.
 376   *
 377   * This function checks against the Banned Email Domains list
 378   * at wp-admin/network/settings.php. The check is only run on
 379   * self-registrations; user creation at wp-admin/network/users.php
 380   * bypasses this check.
 381   *
 382   * @since MU (3.0.0)
 383   *
 384   * @param string $user_email The email provided by the user at registration.
 385   * @return bool True when the email address is banned, false otherwise.
 386   */
 387  function is_email_address_unsafe( $user_email ) {
 388      $banned_names = get_site_option( 'banned_email_domains' );
 389      if ( $banned_names && ! is_array( $banned_names ) ) {
 390          $banned_names = explode( "\n", $banned_names );
 391      }
 392  
 393      $is_email_address_unsafe = false;
 394  
 395      if ( $banned_names && is_array( $banned_names ) && false !== strpos( $user_email, '@', 1 ) ) {
 396          $banned_names     = array_map( 'strtolower', $banned_names );
 397          $normalized_email = strtolower( $user_email );
 398  
 399          list( $email_local_part, $email_domain ) = explode( '@', $normalized_email );
 400  
 401          foreach ( $banned_names as $banned_domain ) {
 402              if ( ! $banned_domain ) {
 403                  continue;
 404              }
 405  
 406              if ( $email_domain === $banned_domain ) {
 407                  $is_email_address_unsafe = true;
 408                  break;
 409              }
 410  
 411              if ( str_ends_with( $normalized_email, ".$banned_domain" ) ) {
 412                  $is_email_address_unsafe = true;
 413                  break;
 414              }
 415          }
 416      }
 417  
 418      /**
 419       * Filters whether an email address is unsafe.
 420       *
 421       * @since 3.5.0
 422       *
 423       * @param bool   $is_email_address_unsafe Whether the email address is "unsafe". Default false.
 424       * @param string $user_email              User email address.
 425       */
 426      return apply_filters( 'is_email_address_unsafe', $is_email_address_unsafe, $user_email );
 427  }
 428  
 429  /**
 430   * Sanitizes and validates data required for a user sign-up.
 431   *
 432   * Verifies the validity and uniqueness of user names and user email addresses,
 433   * and checks email addresses against allowed and disallowed domains provided by
 434   * administrators.
 435   *
 436   * The {@see 'wpmu_validate_user_signup'} hook provides an easy way to modify the sign-up
 437   * process. The value $result, which is passed to the hook, contains both the user-provided
 438   * info and the error messages created by the function. {@see 'wpmu_validate_user_signup'}
 439   * allows you to process the data in any way you'd like, and unset the relevant errors if
 440   * necessary.
 441   *
 442   * @since MU (3.0.0)
 443   *
 444   * @global wpdb $wpdb WordPress database abstraction object.
 445   *
 446   * @param string $user_name  The login name provided by the user.
 447   * @param string $user_email The email provided by the user.
 448   * @return array {
 449   *     The array of user name, email, and the error messages.
 450   *
 451   *     @type string   $user_name     Sanitized and unique username.
 452   *     @type string   $orig_username Original username.
 453   *     @type string   $user_email    User email address.
 454   *     @type WP_Error $errors        WP_Error object containing any errors found.
 455   * }
 456   */
 457  function wpmu_validate_user_signup( $user_name, $user_email ) {
 458      global $wpdb;
 459  
 460      $errors = new WP_Error();
 461  
 462      $orig_username = $user_name;
 463      $user_name     = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
 464  
 465      if ( $user_name != $orig_username || preg_match( '/[^a-z0-9]/', $user_name ) ) {
 466          $errors->add( 'user_name', __( 'Usernames can only contain lowercase letters (a-z) and numbers.' ) );
 467          $user_name = $orig_username;
 468      }
 469  
 470      $user_email = sanitize_email( $user_email );
 471  
 472      if ( empty( $user_name ) ) {
 473          $errors->add( 'user_name', __( 'Please enter a username.' ) );
 474      }
 475  
 476      $illegal_names = get_site_option( 'illegal_names' );
 477      if ( ! is_array( $illegal_names ) ) {
 478          $illegal_names = array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
 479          add_site_option( 'illegal_names', $illegal_names );
 480      }
 481      if ( in_array( $user_name, $illegal_names, true ) ) {
 482          $errors->add( 'user_name', __( 'Sorry, that username is not allowed.' ) );
 483      }
 484  
 485      /** This filter is documented in wp-includes/user.php */
 486      $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
 487  
 488      if ( in_array( strtolower( $user_name ), array_map( 'strtolower', $illegal_logins ), true ) ) {
 489          $errors->add( 'user_name', __( 'Sorry, that username is not allowed.' ) );
 490      }
 491  
 492      if ( ! is_email( $user_email ) ) {
 493          $errors->add( 'user_email', __( 'Please enter a valid email address.' ) );
 494      } elseif ( is_email_address_unsafe( $user_email ) ) {
 495          $errors->add( 'user_email', __( 'You cannot use that email address to signup. There are problems with them blocking some emails from WordPress. Please use another email provider.' ) );
 496      }
 497  
 498      if ( strlen( $user_name ) < 4 ) {
 499          $errors->add( 'user_name', __( 'Username must be at least 4 characters.' ) );
 500      }
 501  
 502      if ( strlen( $user_name ) > 60 ) {
 503          $errors->add( 'user_name', __( 'Username may not be longer than 60 characters.' ) );
 504      }
 505  
 506      // All numeric?
 507      if ( preg_match( '/^[0-9]*$/', $user_name ) ) {
 508          $errors->add( 'user_name', __( 'Sorry, usernames must have letters too!' ) );
 509      }
 510  
 511      $limited_email_domains = get_site_option( 'limited_email_domains' );
 512      if ( is_array( $limited_email_domains ) && ! empty( $limited_email_domains ) ) {
 513          $limited_email_domains = array_map( 'strtolower', $limited_email_domains );
 514          $emaildomain           = strtolower( substr( $user_email, 1 + strpos( $user_email, '@' ) ) );
 515          if ( ! in_array( $emaildomain, $limited_email_domains, true ) ) {
 516              $errors->add( 'user_email', __( 'Sorry, that email address is not allowed!' ) );
 517          }
 518      }
 519  
 520      // Check if the username has been used already.
 521      if ( username_exists( $user_name ) ) {
 522          $errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
 523      }
 524  
 525      // Check if the email address has been used already.
 526      if ( email_exists( $user_email ) ) {
 527          $errors->add(
 528              'user_email',
 529              sprintf(
 530                  /* translators: %s: Link to the login page. */
 531                  __( '<strong>Error:</strong> This email address is already registered. <a href="%s">Log in</a> with this address or choose another one.' ),
 532                  wp_login_url()
 533              )
 534          );
 535      }
 536  
 537      // Has someone already signed up for this username?
 538      $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_name ) );
 539      if ( $signup instanceof stdClass ) {
 540          $registered_at = mysql2date( 'U', $signup->registered );
 541          $now           = time();
 542          $diff          = $now - $registered_at;
 543          // If registered more than two days ago, cancel registration and let this signup go through.
 544          if ( $diff > 2 * DAY_IN_SECONDS ) {
 545              $wpdb->delete( $wpdb->signups, array( 'user_login' => $user_name ) );
 546          } else {
 547              $errors->add( 'user_name', __( 'That username is currently reserved but may be available in a couple of days.' ) );
 548          }
 549      }
 550  
 551      $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE user_email = %s", $user_email ) );
 552      if ( $signup instanceof stdClass ) {
 553          $diff = time() - mysql2date( 'U', $signup->registered );
 554          // If registered more than two days ago, cancel registration and let this signup go through.
 555          if ( $diff > 2 * DAY_IN_SECONDS ) {
 556              $wpdb->delete( $wpdb->signups, array( 'user_email' => $user_email ) );
 557          } else {
 558              $errors->add( 'user_email', __( 'That email address has already been used. Please check your inbox for an activation email. It will become available in a couple of days if you do nothing.' ) );
 559          }
 560      }
 561  
 562      $result = array(
 563          'user_name'     => $user_name,
 564          'orig_username' => $orig_username,
 565          'user_email'    => $user_email,
 566          'errors'        => $errors,
 567      );
 568  
 569      /**
 570       * Filters the validated user registration details.
 571       *
 572       * This does not allow you to override the username or email of the user during
 573       * registration. The values are solely used for validation and error handling.
 574       *
 575       * @since MU (3.0.0)
 576       *
 577       * @param array $result {
 578       *     The array of user name, email, and the error messages.
 579       *
 580       *     @type string   $user_name     Sanitized and unique username.
 581       *     @type string   $orig_username Original username.
 582       *     @type string   $user_email    User email address.
 583       *     @type WP_Error $errors        WP_Error object containing any errors found.
 584       * }
 585       */
 586      return apply_filters( 'wpmu_validate_user_signup', $result );
 587  }
 588  
 589  /**
 590   * Processes new site registrations.
 591   *
 592   * Checks the data provided by the user during blog signup. Verifies
 593   * the validity and uniqueness of blog paths and domains.
 594   *
 595   * This function prevents the current user from registering a new site
 596   * with a blogname equivalent to another user's login name. Passing the
 597   * $user parameter to the function, where $user is the other user, is
 598   * effectively an override of this limitation.
 599   *
 600   * Filter {@see 'wpmu_validate_blog_signup'} if you want to modify
 601   * the way that WordPress validates new site signups.
 602   *
 603   * @since MU (3.0.0)
 604   *
 605   * @global wpdb   $wpdb   WordPress database abstraction object.
 606   * @global string $domain
 607   *
 608   * @param string         $blogname   The site name provided by the user. Must be unique.
 609   * @param string         $blog_title The site title provided by the user.
 610   * @param WP_User|string $user       Optional. The user object to check against the new site name.
 611   *                                   Default empty string.
 612   * @return array {
 613   *     Array of domain, path, site name, site title, user and error messages.
 614   *
 615   *     @type string         $domain     Domain for the site.
 616   *     @type string         $path       Path for the site. Used in subdirectory installations.
 617   *     @type string         $blogname   The unique site name (slug).
 618   *     @type string         $blog_title Blog title.
 619   *     @type string|WP_User $user       By default, an empty string. A user object if provided.
 620   *     @type WP_Error       $errors     WP_Error containing any errors found.
 621   * }
 622   */
 623  function wpmu_validate_blog_signup( $blogname, $blog_title, $user = '' ) {
 624      global $wpdb, $domain;
 625  
 626      $current_network = get_network();
 627      $base            = $current_network->path;
 628  
 629      $blog_title = strip_tags( $blog_title );
 630  
 631      $errors        = new WP_Error();
 632      $illegal_names = get_site_option( 'illegal_names' );
 633      if ( false == $illegal_names ) {
 634          $illegal_names = array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
 635          add_site_option( 'illegal_names', $illegal_names );
 636      }
 637  
 638      /*
 639       * On sub dir installations, some names are so illegal, only a filter can
 640       * spring them from jail.
 641       */
 642      if ( ! is_subdomain_install() ) {
 643          $illegal_names = array_merge( $illegal_names, get_subdirectory_reserved_names() );
 644      }
 645  
 646      if ( empty( $blogname ) ) {
 647          $errors->add( 'blogname', __( 'Please enter a site name.' ) );
 648      }
 649  
 650      if ( preg_match( '/[^a-z0-9]+/', $blogname ) ) {
 651          $errors->add( 'blogname', __( 'Site names can only contain lowercase letters (a-z) and numbers.' ) );
 652      }
 653  
 654      if ( in_array( $blogname, $illegal_names, true ) ) {
 655          $errors->add( 'blogname', __( 'That name is not allowed.' ) );
 656      }
 657  
 658      /**
 659       * Filters the minimum site name length required when validating a site signup.
 660       *
 661       * @since 4.8.0
 662       *
 663       * @param int $length The minimum site name length. Default 4.
 664       */
 665      $minimum_site_name_length = apply_filters( 'minimum_site_name_length', 4 );
 666  
 667      if ( strlen( $blogname ) < $minimum_site_name_length ) {
 668          /* translators: %s: Minimum site name length. */
 669          $errors->add( 'blogname', sprintf( _n( 'Site name must be at least %s character.', 'Site name must be at least %s characters.', $minimum_site_name_length ), number_format_i18n( $minimum_site_name_length ) ) );
 670      }
 671  
 672      // Do not allow users to create a site that conflicts with a page on the main blog.
 673      if ( ! is_subdomain_install() && $wpdb->get_var( $wpdb->prepare( 'SELECT post_name FROM ' . $wpdb->get_blog_prefix( $current_network->site_id ) . "posts WHERE post_type = 'page' AND post_name = %s", $blogname ) ) ) {
 674          $errors->add( 'blogname', __( 'Sorry, you may not use that site name.' ) );
 675      }
 676  
 677      // All numeric?
 678      if ( preg_match( '/^[0-9]*$/', $blogname ) ) {
 679          $errors->add( 'blogname', __( 'Sorry, site names must have letters too!' ) );
 680      }
 681  
 682      /**
 683       * Filters the new site name during registration.
 684       *
 685       * The name is the site's subdomain or the site's subdirectory
 686       * path depending on the network settings.
 687       *
 688       * @since MU (3.0.0)
 689       *
 690       * @param string $blogname Site name.
 691       */
 692      $blogname = apply_filters( 'newblogname', $blogname );
 693  
 694      $blog_title = wp_unslash( $blog_title );
 695  
 696      if ( empty( $blog_title ) ) {
 697          $errors->add( 'blog_title', __( 'Please enter a site title.' ) );
 698      }
 699  
 700      // Check if the domain/path has been used already.
 701      if ( is_subdomain_install() ) {
 702          $mydomain = $blogname . '.' . preg_replace( '|^www\.|', '', $domain );
 703          $path     = $base;
 704      } else {
 705          $mydomain = $domain;
 706          $path     = $base . $blogname . '/';
 707      }
 708      if ( domain_exists( $mydomain, $path, $current_network->id ) ) {
 709          $errors->add( 'blogname', __( 'Sorry, that site already exists!' ) );
 710      }
 711  
 712      /*
 713       * Do not allow users to create a site that matches an existing user's login name,
 714       * unless it's the user's own username.
 715       */
 716      if ( username_exists( $blogname ) ) {
 717          if ( ! is_object( $user ) || ( is_object( $user ) && ( $user->user_login != $blogname ) ) ) {
 718              $errors->add( 'blogname', __( 'Sorry, that site is reserved!' ) );
 719          }
 720      }
 721  
 722      /*
 723       * Has someone already signed up for this domain?
 724       * TODO: Check email too?
 725       */
 726      $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE domain = %s AND path = %s", $mydomain, $path ) );
 727      if ( $signup instanceof stdClass ) {
 728          $diff = time() - mysql2date( 'U', $signup->registered );
 729          // If registered more than two days ago, cancel registration and let this signup go through.
 730          if ( $diff > 2 * DAY_IN_SECONDS ) {
 731              $wpdb->delete(
 732                  $wpdb->signups,
 733                  array(
 734                      'domain' => $mydomain,
 735                      'path'   => $path,
 736                  )
 737              );
 738          } else {
 739              $errors->add( 'blogname', __( 'That site is currently reserved but may be available in a couple days.' ) );
 740          }
 741      }
 742  
 743      $result = array(
 744          'domain'     => $mydomain,
 745          'path'       => $path,
 746          'blogname'   => $blogname,
 747          'blog_title' => $blog_title,
 748          'user'       => $user,
 749          'errors'     => $errors,
 750      );
 751  
 752      /**
 753       * Filters site details and error messages following registration.
 754       *
 755       * @since MU (3.0.0)
 756       *
 757       * @param array $result {
 758       *     Array of domain, path, site name, site title, user and error messages.
 759       *
 760       *     @type string         $domain     Domain for the site.
 761       *     @type string         $path       Path for the site. Used in subdirectory installations.
 762       *     @type string         $blogname   The unique site name (slug).
 763       *     @type string         $blog_title Site title.
 764       *     @type string|WP_User $user       By default, an empty string. A user object if provided.
 765       *     @type WP_Error       $errors     WP_Error containing any errors found.
 766       * }
 767       */
 768      return apply_filters( 'wpmu_validate_blog_signup', $result );
 769  }
 770  
 771  /**
 772   * Records site signup information for future activation.
 773   *
 774   * @since MU (3.0.0)
 775   *
 776   * @global wpdb $wpdb WordPress database abstraction object.
 777   *
 778   * @param string $domain     The requested domain.
 779   * @param string $path       The requested path.
 780   * @param string $title      The requested site title.
 781   * @param string $user       The user's requested login name.
 782   * @param string $user_email The user's email address.
 783   * @param array  $meta       Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
 784   */
 785  function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = array() ) {
 786      global $wpdb;
 787  
 788      $key = substr( md5( time() . wp_rand() . $domain ), 0, 16 );
 789  
 790      /**
 791       * Filters the metadata for a site signup.
 792       *
 793       * The metadata will be serialized prior to storing it in the database.
 794       *
 795       * @since 4.8.0
 796       *
 797       * @param array  $meta       Signup meta data. Default empty array.
 798       * @param string $domain     The requested domain.
 799       * @param string $path       The requested path.
 800       * @param string $title      The requested site title.
 801       * @param string $user       The user's requested login name.
 802       * @param string $user_email The user's email address.
 803       * @param string $key        The user's activation key.
 804       */
 805      $meta = apply_filters( 'signup_site_meta', $meta, $domain, $path, $title, $user, $user_email, $key );
 806  
 807      $wpdb->insert(
 808          $wpdb->signups,
 809          array(
 810              'domain'         => $domain,
 811              'path'           => $path,
 812              'title'          => $title,
 813              'user_login'     => $user,
 814              'user_email'     => $user_email,
 815              'registered'     => current_time( 'mysql', true ),
 816              'activation_key' => $key,
 817              'meta'           => serialize( $meta ),
 818          )
 819      );
 820  
 821      /**
 822       * Fires after site signup information has been written to the database.
 823       *
 824       * @since 4.4.0
 825       *
 826       * @param string $domain     The requested domain.
 827       * @param string $path       The requested path.
 828       * @param string $title      The requested site title.
 829       * @param string $user       The user's requested login name.
 830       * @param string $user_email The user's email address.
 831       * @param string $key        The user's activation key.
 832       * @param array  $meta       Signup meta data. By default, contains the requested privacy setting and lang_id.
 833       */
 834      do_action( 'after_signup_site', $domain, $path, $title, $user, $user_email, $key, $meta );
 835  }
 836  
 837  /**
 838   * Records user signup information for future activation.
 839   *
 840   * This function is used when user registration is open but
 841   * new site registration is not.
 842   *
 843   * @since MU (3.0.0)
 844   *
 845   * @global wpdb $wpdb WordPress database abstraction object.
 846   *
 847   * @param string $user       The user's requested login name.
 848   * @param string $user_email The user's email address.
 849   * @param array  $meta       Optional. Signup meta data. Default empty array.
 850   */
 851  function wpmu_signup_user( $user, $user_email, $meta = array() ) {
 852      global $wpdb;
 853  
 854      // Format data.
 855      $user       = preg_replace( '/\s+/', '', sanitize_user( $user, true ) );
 856      $user_email = sanitize_email( $user_email );
 857      $key        = substr( md5( time() . wp_rand() . $user_email ), 0, 16 );
 858  
 859      /**
 860       * Filters the metadata for a user signup.
 861       *
 862       * The metadata will be serialized prior to storing it in the database.
 863       *
 864       * @since 4.8.0
 865       *
 866       * @param array  $meta       Signup meta data. Default empty array.
 867       * @param string $user       The user's requested login name.
 868       * @param string $user_email The user's email address.
 869       * @param string $key        The user's activation key.
 870       */
 871      $meta = apply_filters( 'signup_user_meta', $meta, $user, $user_email, $key );
 872  
 873      $wpdb->insert(
 874          $wpdb->signups,
 875          array(
 876              'domain'         => '',
 877              'path'           => '',
 878              'title'          => '',
 879              'user_login'     => $user,
 880              'user_email'     => $user_email,
 881              'registered'     => current_time( 'mysql', true ),
 882              'activation_key' => $key,
 883              'meta'           => serialize( $meta ),
 884          )
 885      );
 886  
 887      /**
 888       * Fires after a user's signup information has been written to the database.
 889       *
 890       * @since 4.4.0
 891       *
 892       * @param string $user       The user's requested login name.
 893       * @param string $user_email The user's email address.
 894       * @param string $key        The user's activation key.
 895       * @param array  $meta       Signup meta data. Default empty array.
 896       */
 897      do_action( 'after_signup_user', $user, $user_email, $key, $meta );
 898  }
 899  
 900  /**
 901   * Sends a confirmation request email to a user when they sign up for a new site. The new site will not become active
 902   * until the confirmation link is clicked.
 903   *
 904   * This is the notification function used when site registration
 905   * is enabled.
 906   *
 907   * Filter {@see 'wpmu_signup_blog_notification'} to bypass this function or
 908   * replace it with your own notification behavior.
 909   *
 910   * Filter {@see 'wpmu_signup_blog_notification_email'} and
 911   * {@see 'wpmu_signup_blog_notification_subject'} to change the content
 912   * and subject line of the email sent to newly registered users.
 913   *
 914   * @since MU (3.0.0)
 915   *
 916   * @param string $domain     The new blog domain.
 917   * @param string $path       The new blog path.
 918   * @param string $title      The site title.
 919   * @param string $user_login The user's login name.
 920   * @param string $user_email The user's email address.
 921   * @param string $key        The activation key created in wpmu_signup_blog().
 922   * @param array  $meta       Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
 923   * @return bool
 924   */
 925  function wpmu_signup_blog_notification( $domain, $path, $title, $user_login, $user_email, $key, $meta = array() ) {
 926      /**
 927       * Filters whether to bypass the new site email notification.
 928       *
 929       * @since MU (3.0.0)
 930       *
 931       * @param string|false $domain     Site domain, or false to prevent the email from sending.
 932       * @param string       $path       Site path.
 933       * @param string       $title      Site title.
 934       * @param string       $user_login User login name.
 935       * @param string       $user_email User email address.
 936       * @param string       $key        Activation key created in wpmu_signup_blog().
 937       * @param array        $meta       Signup meta data. By default, contains the requested privacy setting and lang_id.
 938       */
 939      if ( ! apply_filters( 'wpmu_signup_blog_notification', $domain, $path, $title, $user_login, $user_email, $key, $meta ) ) {
 940          return false;
 941      }
 942  
 943      // Send email with activation link.
 944      if ( ! is_subdomain_install() || get_current_network_id() != 1 ) {
 945          $activate_url = network_site_url( "wp-activate.php?key=$key" );
 946      } else {
 947          $activate_url = "http://{$domain}{$path}wp-activate.php?key=$key"; // @todo Use *_url() API.
 948      }
 949  
 950      $activate_url = esc_url( $activate_url );
 951  
 952      $admin_email = get_site_option( 'admin_email' );
 953  
 954      if ( '' === $admin_email ) {
 955          $admin_email = 'support@' . wp_parse_url( network_home_url(), PHP_URL_HOST );
 956      }
 957  
 958      $from_name       = ( '' !== get_site_option( 'site_name' ) ) ? esc_html( get_site_option( 'site_name' ) ) : 'WordPress';
 959      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
 960  
 961      $user            = get_user_by( 'login', $user_login );
 962      $switched_locale = $user && switch_to_user_locale( $user->ID );
 963  
 964      $message = sprintf(
 965          /**
 966           * Filters the message content of the new blog notification email.
 967           *
 968           * Content should be formatted for transmission via wp_mail().
 969           *
 970           * @since MU (3.0.0)
 971           *
 972           * @param string $content    Content of the notification email.
 973           * @param string $domain     Site domain.
 974           * @param string $path       Site path.
 975           * @param string $title      Site title.
 976           * @param string $user_login User login name.
 977           * @param string $user_email User email address.
 978           * @param string $key        Activation key created in wpmu_signup_blog().
 979           * @param array  $meta       Signup meta data. By default, contains the requested privacy setting and lang_id.
 980           */
 981          apply_filters(
 982              'wpmu_signup_blog_notification_email',
 983              /* translators: New site notification email. 1: Activation URL, 2: New site URL. */
 984              __( "To activate your site, please click the following link:\n\n%1\$s\n\nAfter you activate, you will receive *another email* with your login.\n\nAfter you activate, you can visit your site here:\n\n%2\$s" ),
 985              $domain,
 986              $path,
 987              $title,
 988              $user_login,
 989              $user_email,
 990              $key,
 991              $meta
 992          ),
 993          $activate_url,
 994          esc_url( "http://{$domain}{$path}" ),
 995          $key
 996      );
 997  
 998      $subject = sprintf(
 999          /**
1000           * Filters the subject of the new blog notification email.
1001           *
1002           * @since MU (3.0.0)
1003           *
1004           * @param string $subject    Subject of the notification email.
1005           * @param string $domain     Site domain.
1006           * @param string $path       Site path.
1007           * @param string $title      Site title.
1008           * @param string $user_login User login name.
1009           * @param string $user_email User email address.
1010           * @param string $key        Activation key created in wpmu_signup_blog().
1011           * @param array  $meta       Signup meta data. By default, contains the requested privacy setting and lang_id.
1012           */
1013          apply_filters(
1014              'wpmu_signup_blog_notification_subject',
1015              /* translators: New site notification email subject. 1: Network title, 2: New site URL. */
1016              _x( '[%1$s] Activate %2$s', 'New site notification email subject' ),
1017              $domain,
1018              $path,
1019              $title,
1020              $user_login,
1021              $user_email,
1022              $key,
1023              $meta
1024          ),
1025          $from_name,
1026          esc_url( 'http://' . $domain . $path )
1027      );
1028  
1029      wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1030  
1031      if ( $switched_locale ) {
1032          restore_previous_locale();
1033      }
1034  
1035      return true;
1036  }
1037  
1038  /**
1039   * Sends a confirmation request email to a user when they sign up for a new user account (without signing up for a site
1040   * at the same time). The user account will not become active until the confirmation link is clicked.
1041   *
1042   * This is the notification function used when no new site has
1043   * been requested.
1044   *
1045   * Filter {@see 'wpmu_signup_user_notification'} to bypass this function or
1046   * replace it with your own notification behavior.
1047   *
1048   * Filter {@see 'wpmu_signup_user_notification_email'} and
1049   * {@see 'wpmu_signup_user_notification_subject'} to change the content
1050   * and subject line of the email sent to newly registered users.
1051   *
1052   * @since MU (3.0.0)
1053   *
1054   * @param string $user_login The user's login name.
1055   * @param string $user_email The user's email address.
1056   * @param string $key        The activation key created in wpmu_signup_user()
1057   * @param array  $meta       Optional. Signup meta data. Default empty array.
1058   * @return bool
1059   */
1060  function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta = array() ) {
1061      /**
1062       * Filters whether to bypass the email notification for new user sign-up.
1063       *
1064       * @since MU (3.0.0)
1065       *
1066       * @param string $user_login User login name.
1067       * @param string $user_email User email address.
1068       * @param string $key        Activation key created in wpmu_signup_user().
1069       * @param array  $meta       Signup meta data. Default empty array.
1070       */
1071      if ( ! apply_filters( 'wpmu_signup_user_notification', $user_login, $user_email, $key, $meta ) ) {
1072          return false;
1073      }
1074  
1075      $user            = get_user_by( 'login', $user_login );
1076      $switched_locale = $user && switch_to_user_locale( $user->ID );
1077  
1078      // Send email with activation link.
1079      $admin_email = get_site_option( 'admin_email' );
1080  
1081      if ( '' === $admin_email ) {
1082          $admin_email = 'support@' . wp_parse_url( network_home_url(), PHP_URL_HOST );
1083      }
1084  
1085      $from_name       = ( '' !== get_site_option( 'site_name' ) ) ? esc_html( get_site_option( 'site_name' ) ) : 'WordPress';
1086      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
1087      $message         = sprintf(
1088          /**
1089           * Filters the content of the notification email for new user sign-up.
1090           *
1091           * Content should be formatted for transmission via wp_mail().
1092           *
1093           * @since MU (3.0.0)
1094           *
1095           * @param string $content    Content of the notification email.
1096           * @param string $user_login User login name.
1097           * @param string $user_email User email address.
1098           * @param string $key        Activation key created in wpmu_signup_user().
1099           * @param array  $meta       Signup meta data. Default empty array.
1100           */
1101          apply_filters(
1102              'wpmu_signup_user_notification_email',
1103              /* translators: New user notification email. %s: Activation URL. */
1104              __( "To activate your user, please click the following link:\n\n%s\n\nAfter you activate, you will receive *another email* with your login." ),
1105              $user_login,
1106              $user_email,
1107              $key,
1108              $meta
1109          ),
1110          site_url( "wp-activate.php?key=$key" )
1111      );
1112  
1113      $subject = sprintf(
1114          /**
1115           * Filters the subject of the notification email of new user signup.
1116           *
1117           * @since MU (3.0.0)
1118           *
1119           * @param string $subject    Subject of the notification email.
1120           * @param string $user_login User login name.
1121           * @param string $user_email User email address.
1122           * @param string $key        Activation key created in wpmu_signup_user().
1123           * @param array  $meta       Signup meta data. Default empty array.
1124           */
1125          apply_filters(
1126              'wpmu_signup_user_notification_subject',
1127              /* translators: New user notification email subject. 1: Network title, 2: New user login. */
1128              _x( '[%1$s] Activate %2$s', 'New user notification email subject' ),
1129              $user_login,
1130              $user_email,
1131              $key,
1132              $meta
1133          ),
1134          $from_name,
1135          $user_login
1136      );
1137  
1138      wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1139  
1140      if ( $switched_locale ) {
1141          restore_previous_locale();
1142      }
1143  
1144      return true;
1145  }
1146  
1147  /**
1148   * Activates a signup.
1149   *
1150   * Hook to {@see 'wpmu_activate_user'} or {@see 'wpmu_activate_blog'} for events
1151   * that should happen only when users or sites are self-created (since
1152   * those actions are not called when users and sites are created
1153   * by a Super Admin).
1154   *
1155   * @since MU (3.0.0)
1156   *
1157   * @global wpdb $wpdb WordPress database abstraction object.
1158   *
1159   * @param string $key The activation key provided to the user.
1160   * @return array|WP_Error An array containing information about the activated user and/or blog.
1161   */
1162  function wpmu_activate_signup( $key ) {
1163      global $wpdb;
1164  
1165      $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s", $key ) );
1166  
1167      if ( empty( $signup ) ) {
1168          return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
1169      }
1170  
1171      if ( $signup->active ) {
1172          if ( empty( $signup->domain ) ) {
1173              return new WP_Error( 'already_active', __( 'The user is already active.' ), $signup );
1174          } else {
1175              return new WP_Error( 'already_active', __( 'The site is already active.' ), $signup );
1176          }
1177      }
1178  
1179      $meta     = maybe_unserialize( $signup->meta );
1180      $password = wp_generate_password( 12, false );
1181  
1182      $user_id = username_exists( $signup->user_login );
1183  
1184      if ( ! $user_id ) {
1185          $user_id = wpmu_create_user( $signup->user_login, $password, $signup->user_email );
1186      } else {
1187          $user_already_exists = true;
1188      }
1189  
1190      if ( ! $user_id ) {
1191          return new WP_Error( 'create_user', __( 'Could not create user' ), $signup );
1192      }
1193  
1194      $now = current_time( 'mysql', true );
1195  
1196      if ( empty( $signup->domain ) ) {
1197          $wpdb->update(
1198              $wpdb->signups,
1199              array(
1200                  'active'    => 1,
1201                  'activated' => $now,
1202              ),
1203              array( 'activation_key' => $key )
1204          );
1205  
1206          if ( isset( $user_already_exists ) ) {
1207              return new WP_Error( 'user_already_exists', __( 'That username is already activated.' ), $signup );
1208          }
1209  
1210          /**
1211           * Fires immediately after a new user is activated.
1212           *
1213           * @since MU (3.0.0)
1214           *
1215           * @param int    $user_id  User ID.
1216           * @param string $password User password.
1217           * @param array  $meta     Signup meta data.
1218           */
1219          do_action( 'wpmu_activate_user', $user_id, $password, $meta );
1220  
1221          return array(
1222              'user_id'  => $user_id,
1223              'password' => $password,
1224              'meta'     => $meta,
1225          );
1226      }
1227  
1228      $blog_id = wpmu_create_blog( $signup->domain, $signup->path, $signup->title, $user_id, $meta, get_current_network_id() );
1229  
1230      // TODO: What to do if we create a user but cannot create a blog?
1231      if ( is_wp_error( $blog_id ) ) {
1232          /*
1233           * If blog is taken, that means a previous attempt to activate this blog
1234           * failed in between creating the blog and setting the activation flag.
1235           * Let's just set the active flag and instruct the user to reset their password.
1236           */
1237          if ( 'blog_taken' === $blog_id->get_error_code() ) {
1238              $blog_id->add_data( $signup );
1239              $wpdb->update(
1240                  $wpdb->signups,
1241                  array(
1242                      'active'    => 1,
1243                      'activated' => $now,
1244                  ),
1245                  array( 'activation_key' => $key )
1246              );
1247          }
1248          return $blog_id;
1249      }
1250  
1251      $wpdb->update(
1252          $wpdb->signups,
1253          array(
1254              'active'    => 1,
1255              'activated' => $now,
1256          ),
1257          array( 'activation_key' => $key )
1258      );
1259  
1260      /**
1261       * Fires immediately after a site is activated.
1262       *
1263       * @since MU (3.0.0)
1264       *
1265       * @param int    $blog_id       Blog ID.
1266       * @param int    $user_id       User ID.
1267       * @param string $password      User password.
1268       * @param string $signup_title  Site title.
1269       * @param array  $meta          Signup meta data. By default, contains the requested privacy setting and lang_id.
1270       */
1271      do_action( 'wpmu_activate_blog', $blog_id, $user_id, $password, $signup->title, $meta );
1272  
1273      return array(
1274          'blog_id'  => $blog_id,
1275          'user_id'  => $user_id,
1276          'password' => $password,
1277          'title'    => $signup->title,
1278          'meta'     => $meta,
1279      );
1280  }
1281  
1282  /**
1283   * Deletes an associated signup entry when a user is deleted from the database.
1284   *
1285   * @since 5.5.0
1286   *
1287   * @global wpdb $wpdb WordPress database abstraction object.
1288   *
1289   * @param int      $id       ID of the user to delete.
1290   * @param int|null $reassign ID of the user to reassign posts and links to.
1291   * @param WP_User  $user     User object.
1292   */
1293  function wp_delete_signup_on_user_delete( $id, $reassign, $user ) {
1294      global $wpdb;
1295  
1296      $wpdb->delete( $wpdb->signups, array( 'user_login' => $user->user_login ) );
1297  }
1298  
1299  /**
1300   * Creates a user.
1301   *
1302   * This function runs when a user self-registers as well as when
1303   * a Super Admin creates a new user. Hook to {@see 'wpmu_new_user'} for events
1304   * that should affect all new users, but only on Multisite (otherwise
1305   * use {@see 'user_register'}).
1306   *
1307   * @since MU (3.0.0)
1308   *
1309   * @param string $user_name The new user's login name.
1310   * @param string $password  The new user's password.
1311   * @param string $email     The new user's email address.
1312   * @return int|false Returns false on failure, or int $user_id on success.
1313   */
1314  function wpmu_create_user( $user_name, $password, $email ) {
1315      $user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
1316  
1317      $user_id = wp_create_user( $user_name, $password, $email );
1318      if ( is_wp_error( $user_id ) ) {
1319          return false;
1320      }
1321  
1322      // Newly created users have no roles or caps until they are added to a blog.
1323      delete_user_option( $user_id, 'capabilities' );
1324      delete_user_option( $user_id, 'user_level' );
1325  
1326      /**
1327       * Fires immediately after a new user is created.
1328       *
1329       * @since MU (3.0.0)
1330       *
1331       * @param int $user_id User ID.
1332       */
1333      do_action( 'wpmu_new_user', $user_id );
1334  
1335      return $user_id;
1336  }
1337  
1338  /**
1339   * Creates a site.
1340   *
1341   * This function runs when a user self-registers a new site as well
1342   * as when a Super Admin creates a new site. Hook to {@see 'wpmu_new_blog'}
1343   * for events that should affect all new sites.
1344   *
1345   * On subdirectory installations, $domain is the same as the main site's
1346   * domain, and the path is the subdirectory name (eg 'example.com'
1347   * and '/blog1/'). On subdomain installations, $domain is the new subdomain +
1348   * root domain (eg 'blog1.example.com'), and $path is '/'.
1349   *
1350   * @since MU (3.0.0)
1351   *
1352   * @param string $domain     The new site's domain.
1353   * @param string $path       The new site's path.
1354   * @param string $title      The new site's title.
1355   * @param int    $user_id    The user ID of the new site's admin.
1356   * @param array  $options    Optional. Array of key=>value pairs used to set initial site options.
1357   *                           If valid status keys are included ('public', 'archived', 'mature',
1358   *                           'spam', 'deleted', or 'lang_id') the given site status(es) will be
1359   *                           updated. Otherwise, keys and values will be used to set options for
1360   *                           the new site. Default empty array.
1361   * @param int    $network_id Optional. Network ID. Only relevant on multi-network installations.
1362   *                           Default 1.
1363   * @return int|WP_Error Returns WP_Error object on failure, the new site ID on success.
1364   */
1365  function wpmu_create_blog( $domain, $path, $title, $user_id, $options = array(), $network_id = 1 ) {
1366      $defaults = array(
1367          'public' => 0,
1368      );
1369      $options  = wp_parse_args( $options, $defaults );
1370  
1371      $title   = strip_tags( $title );
1372      $user_id = (int) $user_id;
1373  
1374      // Check if the domain has been used already. We should return an error message.
1375      if ( domain_exists( $domain, $path, $network_id ) ) {
1376          return new WP_Error( 'blog_taken', __( 'Sorry, that site already exists!' ) );
1377      }
1378  
1379      if ( ! wp_installing() ) {
1380          wp_installing( true );
1381      }
1382  
1383      $allowed_data_fields = array( 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
1384  
1385      $site_data = array_merge(
1386          array(
1387              'domain'     => $domain,
1388              'path'       => $path,
1389              'network_id' => $network_id,
1390          ),
1391          array_intersect_key( $options, array_flip( $allowed_data_fields ) )
1392      );
1393  
1394      // Data to pass to wp_initialize_site().
1395      $site_initialization_data = array(
1396          'title'   => $title,
1397          'user_id' => $user_id,
1398          'options' => array_diff_key( $options, array_flip( $allowed_data_fields ) ),
1399      );
1400  
1401      $blog_id = wp_insert_site( array_merge( $site_data, $site_initialization_data ) );
1402  
1403      if ( is_wp_error( $blog_id ) ) {
1404          return $blog_id;
1405      }
1406  
1407      wp_cache_set_sites_last_changed();
1408  
1409      return $blog_id;
1410  }
1411  
1412  /**
1413   * Notifies the network admin that a new site has been activated.
1414   *
1415   * Filter {@see 'newblog_notify_siteadmin'} to change the content of
1416   * the notification email.
1417   *
1418   * @since MU (3.0.0)
1419   * @since 5.1.0 $blog_id now supports input from the {@see 'wp_initialize_site'} action.
1420   *
1421   * @param WP_Site|int $blog_id    The new site's object or ID.
1422   * @param string      $deprecated Not used.
1423   * @return bool
1424   */
1425  function newblog_notify_siteadmin( $blog_id, $deprecated = '' ) {
1426      if ( is_object( $blog_id ) ) {
1427          $blog_id = $blog_id->blog_id;
1428      }
1429  
1430      if ( 'yes' !== get_site_option( 'registrationnotification' ) ) {
1431          return false;
1432      }
1433  
1434      $email = get_site_option( 'admin_email' );
1435  
1436      if ( is_email( $email ) == false ) {
1437          return false;
1438      }
1439  
1440      $options_site_url = esc_url( network_admin_url( 'settings.php' ) );
1441  
1442      switch_to_blog( $blog_id );
1443      $blogname = get_option( 'blogname' );
1444      $siteurl  = site_url();
1445      restore_current_blog();
1446  
1447      $msg = sprintf(
1448          /* translators: New site notification email. 1: Site URL, 2: User IP address, 3: URL to Network Settings screen. */
1449          __(
1450              'New Site: %1$s
1451  URL: %2$s
1452  Remote IP address: %3$s
1453  
1454  Disable these notifications: %4$s'
1455          ),
1456          $blogname,
1457          $siteurl,
1458          wp_unslash( $_SERVER['REMOTE_ADDR'] ),
1459          $options_site_url
1460      );
1461      /**
1462       * Filters the message body of the new site activation email sent
1463       * to the network administrator.
1464       *
1465       * @since MU (3.0.0)
1466       * @since 5.4.0 The `$blog_id` parameter was added.
1467       *
1468       * @param string     $msg     Email body.
1469       * @param int|string $blog_id The new site's ID as an integer or numeric string.
1470       */
1471      $msg = apply_filters( 'newblog_notify_siteadmin', $msg, $blog_id );
1472  
1473      /* translators: New site notification email subject. %s: New site URL. */
1474      wp_mail( $email, sprintf( __( 'New Site Registration: %s' ), $siteurl ), $msg );
1475  
1476      return true;
1477  }
1478  
1479  /**
1480   * Notifies the network admin that a new user has been activated.
1481   *
1482   * Filter {@see 'newuser_notify_siteadmin'} to change the content of
1483   * the notification email.
1484   *
1485   * @since MU (3.0.0)
1486   *
1487   * @param int $user_id The new user's ID.
1488   * @return bool
1489   */
1490  function newuser_notify_siteadmin( $user_id ) {
1491      if ( 'yes' !== get_site_option( 'registrationnotification' ) ) {
1492          return false;
1493      }
1494  
1495      $email = get_site_option( 'admin_email' );
1496  
1497      if ( is_email( $email ) == false ) {
1498          return false;
1499      }
1500  
1501      $user = get_userdata( $user_id );
1502  
1503      $options_site_url = esc_url( network_admin_url( 'settings.php' ) );
1504  
1505      $msg = sprintf(
1506          /* translators: New user notification email. 1: User login, 2: User IP address, 3: URL to Network Settings screen. */
1507          __(
1508              'New User: %1$s
1509  Remote IP address: %2$s
1510  
1511  Disable these notifications: %3$s'
1512          ),
1513          $user->user_login,
1514          wp_unslash( $_SERVER['REMOTE_ADDR'] ),
1515          $options_site_url
1516      );
1517  
1518      /**
1519       * Filters the message body of the new user activation email sent
1520       * to the network administrator.
1521       *
1522       * @since MU (3.0.0)
1523       *
1524       * @param string  $msg  Email body.
1525       * @param WP_User $user WP_User instance of the new user.
1526       */
1527      $msg = apply_filters( 'newuser_notify_siteadmin', $msg, $user );
1528  
1529      /* translators: New user notification email subject. %s: User login. */
1530      wp_mail( $email, sprintf( __( 'New User Registration: %s' ), $user->user_login ), $msg );
1531  
1532      return true;
1533  }
1534  
1535  /**
1536   * Checks whether a site name is already taken.
1537   *
1538   * The name is the site's subdomain or the site's subdirectory
1539   * path depending on the network settings.
1540   *
1541   * Used during the new site registration process to ensure
1542   * that each site name is unique.
1543   *
1544   * @since MU (3.0.0)
1545   *
1546   * @param string $domain     The domain to be checked.
1547   * @param string $path       The path to be checked.
1548   * @param int    $network_id Optional. Network ID. Only relevant on multi-network installations.
1549   *                           Default 1.
1550   * @return int|null The site ID if the site name exists, null otherwise.
1551   */
1552  function domain_exists( $domain, $path, $network_id = 1 ) {
1553      $path   = trailingslashit( $path );
1554      $args   = array(
1555          'network_id'             => $network_id,
1556          'domain'                 => $domain,
1557          'path'                   => $path,
1558          'fields'                 => 'ids',
1559          'number'                 => 1,
1560          'update_site_meta_cache' => false,
1561      );
1562      $result = get_sites( $args );
1563      $result = array_shift( $result );
1564  
1565      /**
1566       * Filters whether a site name is taken.
1567       *
1568       * The name is the site's subdomain or the site's subdirectory
1569       * path depending on the network settings.
1570       *
1571       * @since 3.5.0
1572       *
1573       * @param int|null $result     The site ID if the site name exists, null otherwise.
1574       * @param string   $domain     Domain to be checked.
1575       * @param string   $path       Path to be checked.
1576       * @param int      $network_id Network ID. Only relevant on multi-network installations.
1577       */
1578      return apply_filters( 'domain_exists', $result, $domain, $path, $network_id );
1579  }
1580  
1581  /**
1582   * Notifies the site administrator that their site activation was successful.
1583   *
1584   * Filter {@see 'wpmu_welcome_notification'} to disable or bypass.
1585   *
1586   * Filter {@see 'update_welcome_email'} and {@see 'update_welcome_subject'} to
1587   * modify the content and subject line of the notification email.
1588   *
1589   * @since MU (3.0.0)
1590   *
1591   * @param int    $blog_id  Site ID.
1592   * @param int    $user_id  User ID.
1593   * @param string $password User password, or "N/A" if the user account is not new.
1594   * @param string $title    Site title.
1595   * @param array  $meta     Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
1596   * @return bool Whether the email notification was sent.
1597   */
1598  function wpmu_welcome_notification( $blog_id, $user_id, $password, $title, $meta = array() ) {
1599      $current_network = get_network();
1600  
1601      /**
1602       * Filters whether to bypass the welcome email sent to the site administrator after site activation.
1603       *
1604       * Returning false disables the welcome email.
1605       *
1606       * @since MU (3.0.0)
1607       *
1608       * @param int|false $blog_id  Site ID, or false to prevent the email from sending.
1609       * @param int       $user_id  User ID of the site administrator.
1610       * @param string    $password User password, or "N/A" if the user account is not new.
1611       * @param string    $title    Site title.
1612       * @param array     $meta     Signup meta data. By default, contains the requested privacy setting and lang_id.
1613       */
1614      if ( ! apply_filters( 'wpmu_welcome_notification', $blog_id, $user_id, $password, $title, $meta ) ) {
1615          return false;
1616      }
1617  
1618      $user = get_userdata( $user_id );
1619  
1620      $switched_locale = switch_to_user_locale( $user_id );
1621  
1622      $welcome_email = get_site_option( 'welcome_email' );
1623      if ( false == $welcome_email ) {
1624          /* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */
1625          $welcome_email = __(
1626              'Howdy USERNAME,
1627  
1628  Your new SITE_NAME site has been successfully set up at:
1629  BLOG_URL
1630  
1631  You can log in to the administrator account with the following information:
1632  
1633  Username: USERNAME
1634  Password: PASSWORD
1635  Log in here: BLOG_URLwp-login.php
1636  
1637  We hope you enjoy your new site. Thanks!
1638  
1639  --The Team @ SITE_NAME'
1640          );
1641      }
1642  
1643      $url = get_blogaddress_by_id( $blog_id );
1644  
1645      $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
1646      $welcome_email = str_replace( 'BLOG_TITLE', $title, $welcome_email );
1647      $welcome_email = str_replace( 'BLOG_URL', $url, $welcome_email );
1648      $welcome_email = str_replace( 'USERNAME', $user->user_login, $welcome_email );
1649      $welcome_email = str_replace( 'PASSWORD', $password, $welcome_email );
1650  
1651      /**
1652       * Filters the content of the welcome email sent to the site administrator after site activation.
1653       *
1654       * Content should be formatted for transmission via wp_mail().
1655       *
1656       * @since MU (3.0.0)
1657       *
1658       * @param string $welcome_email Message body of the email.
1659       * @param int    $blog_id       Site ID.
1660       * @param int    $user_id       User ID of the site administrator.
1661       * @param string $password      User password, or "N/A" if the user account is not new.
1662       * @param string $title         Site title.
1663       * @param array  $meta          Signup meta data. By default, contains the requested privacy setting and lang_id.
1664       */
1665      $welcome_email = apply_filters( 'update_welcome_email', $welcome_email, $blog_id, $user_id, $password, $title, $meta );
1666  
1667      $admin_email = get_site_option( 'admin_email' );
1668  
1669      if ( '' === $admin_email ) {
1670          $admin_email = 'support@' . wp_parse_url( network_home_url(), PHP_URL_HOST );
1671      }
1672  
1673      $from_name       = ( '' !== get_site_option( 'site_name' ) ) ? esc_html( get_site_option( 'site_name' ) ) : 'WordPress';
1674      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
1675      $message         = $welcome_email;
1676  
1677      if ( empty( $current_network->site_name ) ) {
1678          $current_network->site_name = 'WordPress';
1679      }
1680  
1681      /* translators: New site notification email subject. 1: Network title, 2: New site title. */
1682      $subject = __( 'New %1$s Site: %2$s' );
1683  
1684      /**
1685       * Filters the subject of the welcome email sent to the site administrator after site activation.
1686       *
1687       * @since MU (3.0.0)
1688       *
1689       * @param string $subject Subject of the email.
1690       */
1691      $subject = apply_filters( 'update_welcome_subject', sprintf( $subject, $current_network->site_name, wp_unslash( $title ) ) );
1692  
1693      wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1694  
1695      if ( $switched_locale ) {
1696          restore_previous_locale();
1697      }
1698  
1699      return true;
1700  }
1701  
1702  /**
1703   * Notifies the Multisite network administrator that a new site was created.
1704   *
1705   * Filter {@see 'send_new_site_email'} to disable or bypass.
1706   *
1707   * Filter {@see 'new_site_email'} to filter the contents.
1708   *
1709   * @since 5.6.0
1710   *
1711   * @param int $site_id Site ID of the new site.
1712   * @param int $user_id User ID of the administrator of the new site.
1713   * @return bool Whether the email notification was sent.
1714   */
1715  function wpmu_new_site_admin_notification( $site_id, $user_id ) {
1716      $site  = get_site( $site_id );
1717      $user  = get_userdata( $user_id );
1718      $email = get_site_option( 'admin_email' );
1719  
1720      if ( ! $site || ! $user || ! $email ) {
1721          return false;
1722      }
1723  
1724      /**
1725       * Filters whether to send an email to the Multisite network administrator when a new site is created.
1726       *
1727       * Return false to disable sending the email.
1728       *
1729       * @since 5.6.0
1730       *
1731       * @param bool    $send Whether to send the email.
1732       * @param WP_Site $site Site object of the new site.
1733       * @param WP_User $user User object of the administrator of the new site.
1734       */
1735      if ( ! apply_filters( 'send_new_site_email', true, $site, $user ) ) {
1736          return false;
1737      }
1738  
1739      $switched_locale = false;
1740      $network_admin   = get_user_by( 'email', $email );
1741  
1742      if ( $network_admin ) {
1743          // If the network admin email address corresponds to a user, switch to their locale.
1744          $switched_locale = switch_to_user_locale( $network_admin->ID );
1745      } else {
1746          // Otherwise switch to the locale of the current site.
1747          $switched_locale = switch_to_locale( get_locale() );
1748      }
1749  
1750      $subject = sprintf(
1751          /* translators: New site notification email subject. %s: Network title. */
1752          __( '[%s] New Site Created' ),
1753          get_network()->site_name
1754      );
1755  
1756      $message = sprintf(
1757          /* translators: New site notification email. 1: User login, 2: Site URL, 3: Site title. */
1758          __(
1759              'New site created by %1$s
1760  
1761  Address: %2$s
1762  Name: %3$s'
1763          ),
1764          $user->user_login,
1765          get_site_url( $site->id ),
1766          get_blog_option( $site->id, 'blogname' )
1767      );
1768  
1769      $header = sprintf(
1770          'From: "%1$s" <%2$s>',
1771          _x( 'Site Admin', 'email "From" field' ),
1772          $email
1773      );
1774  
1775      $new_site_email = array(
1776          'to'      => $email,
1777          'subject' => $subject,
1778          'message' => $message,
1779          'headers' => $header,
1780      );
1781  
1782      /**
1783       * Filters the content of the email sent to the Multisite network administrator when a new site is created.
1784       *
1785       * Content should be formatted for transmission via wp_mail().
1786       *
1787       * @since 5.6.0
1788       *
1789       * @param array $new_site_email {
1790       *     Used to build wp_mail().
1791       *
1792       *     @type string $to      The email address of the recipient.
1793       *     @type string $subject The subject of the email.
1794       *     @type string $message The content of the email.
1795       *     @type string $headers Headers.
1796       * }
1797       * @param WP_Site $site         Site object of the new site.
1798       * @param WP_User $user         User object of the administrator of the new site.
1799       */
1800      $new_site_email = apply_filters( 'new_site_email', $new_site_email, $site, $user );
1801  
1802      wp_mail(
1803          $new_site_email['to'],
1804          wp_specialchars_decode( $new_site_email['subject'] ),
1805          $new_site_email['message'],
1806          $new_site_email['headers']
1807      );
1808  
1809      if ( $switched_locale ) {
1810          restore_previous_locale();
1811      }
1812  
1813      return true;
1814  }
1815  
1816  /**
1817   * Notifies a user that their account activation has been successful.
1818   *
1819   * Filter {@see 'wpmu_welcome_user_notification'} to disable or bypass.
1820   *
1821   * Filter {@see 'update_welcome_user_email'} and {@see 'update_welcome_user_subject'} to
1822   * modify the content and subject line of the notification email.
1823   *
1824   * @since MU (3.0.0)
1825   *
1826   * @param int    $user_id  User ID.
1827   * @param string $password User password.
1828   * @param array  $meta     Optional. Signup meta data. Default empty array.
1829   * @return bool
1830   */
1831  function wpmu_welcome_user_notification( $user_id, $password, $meta = array() ) {
1832      $current_network = get_network();
1833  
1834      /**
1835       * Filters whether to bypass the welcome email after user activation.
1836       *
1837       * Returning false disables the welcome email.
1838       *
1839       * @since MU (3.0.0)
1840       *
1841       * @param int    $user_id  User ID.
1842       * @param string $password User password.
1843       * @param array  $meta     Signup meta data. Default empty array.
1844       */
1845      if ( ! apply_filters( 'wpmu_welcome_user_notification', $user_id, $password, $meta ) ) {
1846          return false;
1847      }
1848  
1849      $welcome_email = get_site_option( 'welcome_user_email' );
1850  
1851      $user = get_userdata( $user_id );
1852  
1853      $switched_locale = switch_to_user_locale( $user_id );
1854  
1855      /**
1856       * Filters the content of the welcome email after user activation.
1857       *
1858       * Content should be formatted for transmission via wp_mail().
1859       *
1860       * @since MU (3.0.0)
1861       *
1862       * @param string $welcome_email The message body of the account activation success email.
1863       * @param int    $user_id       User ID.
1864       * @param string $password      User password.
1865       * @param array  $meta          Signup meta data. Default empty array.
1866       */
1867      $welcome_email = apply_filters( 'update_welcome_user_email', $welcome_email, $user_id, $password, $meta );
1868      $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
1869      $welcome_email = str_replace( 'USERNAME', $user->user_login, $welcome_email );
1870      $welcome_email = str_replace( 'PASSWORD', $password, $welcome_email );
1871      $welcome_email = str_replace( 'LOGINLINK', wp_login_url(), $welcome_email );
1872  
1873      $admin_email = get_site_option( 'admin_email' );
1874  
1875      if ( '' === $admin_email ) {
1876          $admin_email = 'support@' . wp_parse_url( network_home_url(), PHP_URL_HOST );
1877      }
1878  
1879      $from_name       = ( '' !== get_site_option( 'site_name' ) ) ? esc_html( get_site_option( 'site_name' ) ) : 'WordPress';
1880      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
1881      $message         = $welcome_email;
1882  
1883      if ( empty( $current_network->site_name ) ) {
1884          $current_network->site_name = 'WordPress';
1885      }
1886  
1887      /* translators: New user notification email subject. 1: Network title, 2: New user login. */
1888      $subject = __( 'New %1$s User: %2$s' );
1889  
1890      /**
1891       * Filters the subject of the welcome email after user activation.
1892       *
1893       * @since MU (3.0.0)
1894       *
1895       * @param string $subject Subject of the email.
1896       */
1897      $subject = apply_filters( 'update_welcome_user_subject', sprintf( $subject, $current_network->site_name, $user->user_login ) );
1898  
1899      wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1900  
1901      if ( $switched_locale ) {
1902          restore_previous_locale();
1903      }
1904  
1905      return true;
1906  }
1907  
1908  /**
1909   * Gets the current network.
1910   *
1911   * Returns an object containing the 'id', 'domain', 'path', and 'site_name'
1912   * properties of the network being viewed.
1913   *
1914   * @see wpmu_current_site()
1915   *
1916   * @since MU (3.0.0)
1917   *
1918   * @global WP_Network $current_site The current network.
1919   *
1920   * @return WP_Network The current network.
1921   */
1922  function get_current_site() {
1923      global $current_site;
1924      return $current_site;
1925  }
1926  
1927  /**
1928   * Gets a user's most recent post.
1929   *
1930   * Walks through each of a user's blogs to find the post with
1931   * the most recent post_date_gmt.
1932   *
1933   * @since MU (3.0.0)
1934   *
1935   * @global wpdb $wpdb WordPress database abstraction object.
1936   *
1937   * @param int $user_id User ID.
1938   * @return array Contains the blog_id, post_id, post_date_gmt, and post_gmt_ts.
1939   */
1940  function get_most_recent_post_of_user( $user_id ) {
1941      global $wpdb;
1942  
1943      $user_blogs       = get_blogs_of_user( (int) $user_id );
1944      $most_recent_post = array();
1945  
1946      /*
1947       * Walk through each blog and get the most recent post
1948       * published by $user_id.
1949       */
1950      foreach ( (array) $user_blogs as $blog ) {
1951          $prefix      = $wpdb->get_blog_prefix( $blog->userblog_id );
1952          $recent_post = $wpdb->get_row( $wpdb->prepare( "SELECT ID, post_date_gmt FROM {$prefix}posts WHERE post_author = %d AND post_type = 'post' AND post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1", $user_id ), ARRAY_A );
1953  
1954          // Make sure we found a post.
1955          if ( isset( $recent_post['ID'] ) ) {
1956              $post_gmt_ts = strtotime( $recent_post['post_date_gmt'] );
1957  
1958              /*
1959               * If this is the first post checked
1960               * or if this post is newer than the current recent post,
1961               * make it the new most recent post.
1962               */
1963              if ( ! isset( $most_recent_post['post_gmt_ts'] ) || ( $post_gmt_ts > $most_recent_post['post_gmt_ts'] ) ) {
1964                  $most_recent_post = array(
1965                      'blog_id'       => $blog->userblog_id,
1966                      'post_id'       => $recent_post['ID'],
1967                      'post_date_gmt' => $recent_post['post_date_gmt'],
1968                      'post_gmt_ts'   => $post_gmt_ts,
1969                  );
1970              }
1971          }
1972      }
1973  
1974      return $most_recent_post;
1975  }
1976  
1977  //
1978  // Misc functions.
1979  //
1980  
1981  /**
1982   * Checks an array of MIME types against a list of allowed types.
1983   *
1984   * WordPress ships with a set of allowed upload filetypes,
1985   * which is defined in wp-includes/functions.php in
1986   * get_allowed_mime_types(). This function is used to filter
1987   * that list against the filetypes allowed provided by Multisite
1988   * Super Admins at wp-admin/network/settings.php.
1989   *
1990   * @since MU (3.0.0)
1991   *
1992   * @param array $mimes
1993   * @return array
1994   */
1995  function check_upload_mimes( $mimes ) {
1996      $site_exts  = explode( ' ', get_site_option( 'upload_filetypes', 'jpg jpeg png gif' ) );
1997      $site_mimes = array();
1998      foreach ( $site_exts as $ext ) {
1999          foreach ( $mimes as $ext_pattern => $mime ) {
2000              if ( '' !== $ext && str_contains( $ext_pattern, $ext ) ) {
2001                  $site_mimes[ $ext_pattern ] = $mime;
2002              }
2003          }
2004      }
2005      return $site_mimes;
2006  }
2007  
2008  /**
2009   * Updates a blog's post count.
2010   *
2011   * WordPress MS stores a blog's post count as an option so as
2012   * to avoid extraneous COUNTs when a blog's details are fetched
2013   * with get_site(). This function is called when posts are published
2014   * or unpublished to make sure the count stays current.
2015   *
2016   * @since MU (3.0.0)
2017   *
2018   * @global wpdb $wpdb WordPress database abstraction object.
2019   *
2020   * @param string $deprecated Not used.
2021   */
2022  function update_posts_count( $deprecated = '' ) {
2023      global $wpdb;
2024      update_option( 'post_count', (int) $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish' and post_type = 'post'" ) );
2025  }
2026  
2027  /**
2028   * Logs the user email, IP, and registration date of a new site.
2029   *
2030   * @since MU (3.0.0)
2031   * @since 5.1.0 Parameters now support input from the {@see 'wp_initialize_site'} action.
2032   *
2033   * @global wpdb $wpdb WordPress database abstraction object.
2034   *
2035   * @param WP_Site|int $blog_id The new site's object or ID.
2036   * @param int|array   $user_id User ID, or array of arguments including 'user_id'.
2037   */
2038  function wpmu_log_new_registrations( $blog_id, $user_id ) {
2039      global $wpdb;
2040  
2041      if ( is_object( $blog_id ) ) {
2042          $blog_id = $blog_id->blog_id;
2043      }
2044  
2045      if ( is_array( $user_id ) ) {
2046          $user_id = ! empty( $user_id['user_id'] ) ? $user_id['user_id'] : 0;
2047      }
2048  
2049      $user = get_userdata( (int) $user_id );
2050      if ( $user ) {
2051          $wpdb->insert(
2052              $wpdb->registration_log,
2053              array(
2054                  'email'           => $user->user_email,
2055                  'IP'              => preg_replace( '/[^0-9., ]/', '', wp_unslash( $_SERVER['REMOTE_ADDR'] ) ),
2056                  'blog_id'         => $blog_id,
2057                  'date_registered' => current_time( 'mysql' ),
2058              )
2059          );
2060      }
2061  }
2062  
2063  /**
2064   * Ensures that the current site's domain is listed in the allowed redirect host list.
2065   *
2066   * @see wp_validate_redirect()
2067   * @since MU (3.0.0)
2068   *
2069   * @param array|string $deprecated Not used.
2070   * @return string[] {
2071   *     An array containing the current site's domain.
2072   *
2073   *     @type string $0 The current site's domain.
2074   * }
2075   */
2076  function redirect_this_site( $deprecated = '' ) {
2077      return array( get_network()->domain );
2078  }
2079  
2080  /**
2081   * Checks whether an upload is too big.
2082   *
2083   * @since MU (3.0.0)
2084   *
2085   * @param array $upload An array of information about the newly-uploaded file.
2086   * @return string|array If the upload is under the size limit, $upload is returned. Otherwise returns an error message.
2087   */
2088  function upload_is_file_too_big( $upload ) {
2089      if ( ! is_array( $upload ) || defined( 'WP_IMPORTING' ) || get_site_option( 'upload_space_check_disabled' ) ) {
2090          return $upload;
2091      }
2092  
2093      if ( strlen( $upload['bits'] ) > ( KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 ) ) ) {
2094          /* translators: %s: Maximum allowed file size in kilobytes. */
2095          return sprintf( __( 'This file is too big. Files must be less than %s KB in size.' ) . '<br />', get_site_option( 'fileupload_maxk', 1500 ) );
2096      }
2097  
2098      return $upload;
2099  }
2100  
2101  /**
2102   * Adds a nonce field to the signup page.
2103   *
2104   * @since MU (3.0.0)
2105   */
2106  function signup_nonce_fields() {
2107      $id = mt_rand();
2108      echo "<input type='hidden' name='signup_form_id' value='{$id}' />";
2109      wp_nonce_field( 'signup_form_' . $id, '_signup_form', false );
2110  }
2111  
2112  /**
2113   * Processes the signup nonce created in signup_nonce_fields().
2114   *
2115   * @since MU (3.0.0)
2116   *
2117   * @param array $result
2118   * @return array
2119   */
2120  function signup_nonce_check( $result ) {
2121      if ( ! strpos( $_SERVER['PHP_SELF'], 'wp-signup.php' ) ) {
2122          return $result;
2123      }
2124  
2125      if ( ! wp_verify_nonce( $_POST['_signup_form'], 'signup_form_' . $_POST['signup_form_id'] ) ) {
2126          $result['errors']->add( 'invalid_nonce', __( 'Unable to submit this form, please try again.' ) );
2127      }
2128  
2129      return $result;
2130  }
2131  
2132  /**
2133   * Corrects 404 redirects when NOBLOGREDIRECT is defined.
2134   *
2135   * @since MU (3.0.0)
2136   */
2137  function maybe_redirect_404() {
2138      if ( is_main_site() && is_404() && defined( 'NOBLOGREDIRECT' ) ) {
2139          /**
2140           * Filters the redirect URL for 404s on the main site.
2141           *
2142           * The filter is only evaluated if the NOBLOGREDIRECT constant is defined.
2143           *
2144           * @since 3.0.0
2145           *
2146           * @param string $no_blog_redirect The redirect URL defined in NOBLOGREDIRECT.
2147           */
2148          $destination = apply_filters( 'blog_redirect_404', NOBLOGREDIRECT );
2149  
2150          if ( $destination ) {
2151              if ( '%siteurl%' === $destination ) {
2152                  $destination = network_home_url();
2153              }
2154  
2155              wp_redirect( $destination );
2156              exit;
2157          }
2158      }
2159  }
2160  
2161  /**
2162   * Adds a new user to a blog by visiting /newbloguser/{key}/.
2163   *
2164   * This will only work when the user's details are saved as an option
2165   * keyed as 'new_user_{key}', where '{key}' is a hash generated for the user to be
2166   * added, as when a user is invited through the regular WP Add User interface.
2167   *
2168   * @since MU (3.0.0)
2169   */
2170  function maybe_add_existing_user_to_blog() {
2171      if ( ! str_contains( $_SERVER['REQUEST_URI'], '/newbloguser/' ) ) {
2172          return;
2173      }
2174  
2175      $parts = explode( '/', $_SERVER['REQUEST_URI'] );
2176      $key   = array_pop( $parts );
2177  
2178      if ( '' === $key ) {
2179          $key = array_pop( $parts );
2180      }
2181  
2182      $details = get_option( 'new_user_' . $key );
2183      if ( ! empty( $details ) ) {
2184          delete_option( 'new_user_' . $key );
2185      }
2186  
2187      if ( empty( $details ) || is_wp_error( add_existing_user_to_blog( $details ) ) ) {
2188          wp_die(
2189              sprintf(
2190                  /* translators: %s: Home URL. */
2191                  __( 'An error occurred adding you to this site. Go to the <a href="%s">homepage</a>.' ),
2192                  home_url()
2193              )
2194          );
2195      }
2196  
2197      wp_die(
2198          sprintf(
2199              /* translators: 1: Home URL, 2: Admin URL. */
2200              __( 'You have been added to this site. Please visit the <a href="%1$s">homepage</a> or <a href="%2$s">log in</a> using your username and password.' ),
2201              home_url(),
2202              admin_url()
2203          ),
2204          __( 'WordPress &rsaquo; Success' ),
2205          array( 'response' => 200 )
2206      );
2207  }
2208  
2209  /**
2210   * Adds a user to a blog based on details from maybe_add_existing_user_to_blog().
2211   *
2212   * @since MU (3.0.0)
2213   *
2214   * @param array|false $details {
2215   *     User details. Must at least contain values for the keys listed below.
2216   *
2217   *     @type int    $user_id The ID of the user being added to the current blog.
2218   *     @type string $role    The role to be assigned to the user.
2219   * }
2220   * @return true|WP_Error|void True on success or a WP_Error object if the user doesn't exist
2221   *                            or could not be added. Void if $details array was not provided.
2222   */
2223  function add_existing_user_to_blog( $details = false ) {
2224      if ( is_array( $details ) ) {
2225          $blog_id = get_current_blog_id();
2226          $result  = add_user_to_blog( $blog_id, $details['user_id'], $details['role'] );
2227  
2228          /**
2229           * Fires immediately after an existing user is added to a site.
2230           *
2231           * @since MU (3.0.0)
2232           *
2233           * @param int           $user_id User ID.
2234           * @param true|WP_Error $result  True on success or a WP_Error object if the user doesn't exist
2235           *                               or could not be added.
2236           */
2237          do_action( 'added_existing_user', $details['user_id'], $result );
2238  
2239          return $result;
2240      }
2241  }
2242  
2243  /**
2244   * Adds a newly created user to the appropriate blog
2245   *
2246   * To add a user in general, use add_user_to_blog(). This function
2247   * is specifically hooked into the {@see 'wpmu_activate_user'} action.
2248   *
2249   * @since MU (3.0.0)
2250   *
2251   * @see add_user_to_blog()
2252   *
2253   * @param int    $user_id  User ID.
2254   * @param string $password User password. Ignored.
2255   * @param array  $meta     Signup meta data.
2256   */
2257  function add_new_user_to_blog( $user_id, $password, $meta ) {
2258      if ( ! empty( $meta['add_to_blog'] ) ) {
2259          $blog_id = $meta['add_to_blog'];
2260          $role    = $meta['new_role'];
2261          remove_user_from_blog( $user_id, get_network()->site_id ); // Remove user from main blog.
2262  
2263          $result = add_user_to_blog( $blog_id, $user_id, $role );
2264  
2265          if ( ! is_wp_error( $result ) ) {
2266              update_user_meta( $user_id, 'primary_blog', $blog_id );
2267          }
2268      }
2269  }
2270  
2271  /**
2272   * Corrects From host on outgoing mail to match the site domain.
2273   *
2274   * @since MU (3.0.0)
2275   *
2276   * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
2277   */
2278  function fix_phpmailer_messageid( $phpmailer ) {
2279      $phpmailer->Hostname = get_network()->domain;
2280  }
2281  
2282  /**
2283   * Determines whether a user is marked as a spammer, based on user login.
2284   *
2285   * @since MU (3.0.0)
2286   *
2287   * @param string|WP_User $user Optional. Defaults to current user. WP_User object,
2288   *                             or user login name as a string.
2289   * @return bool
2290   */
2291  function is_user_spammy( $user = null ) {
2292      if ( ! ( $user instanceof WP_User ) ) {
2293          if ( $user ) {
2294              $user = get_user_by( 'login', $user );
2295          } else {
2296              $user = wp_get_current_user();
2297          }
2298      }
2299  
2300      return $user && isset( $user->spam ) && 1 == $user->spam;
2301  }
2302  
2303  /**
2304   * Updates this blog's 'public' setting in the global blogs table.
2305   *
2306   * Public blogs have a setting of 1, private blogs are 0.
2307   *
2308   * @since MU (3.0.0)
2309   *
2310   * @param int $old_value The old public value.
2311   * @param int $value     The new public value.
2312   */
2313  function update_blog_public( $old_value, $value ) {
2314      update_blog_status( get_current_blog_id(), 'public', (int) $value );
2315  }
2316  
2317  /**
2318   * Determines whether users can self-register, based on Network settings.
2319   *
2320   * @since MU (3.0.0)
2321   *
2322   * @return bool
2323   */
2324  function users_can_register_signup_filter() {
2325      $registration = get_site_option( 'registration' );
2326      return ( 'all' === $registration || 'user' === $registration );
2327  }
2328  
2329  /**
2330   * Ensures that the welcome message is not empty. Currently unused.
2331   *
2332   * @since MU (3.0.0)
2333   *
2334   * @param string $text
2335   * @return string
2336   */
2337  function welcome_user_msg_filter( $text ) {
2338      if ( ! $text ) {
2339          remove_filter( 'site_option_welcome_user_email', 'welcome_user_msg_filter' );
2340  
2341          /* translators: Do not translate USERNAME, PASSWORD, LOGINLINK, SITE_NAME: those are placeholders. */
2342          $text = __(
2343              'Howdy USERNAME,
2344  
2345  Your new account is set up.
2346  
2347  You can log in with the following information:
2348  Username: USERNAME
2349  Password: PASSWORD
2350  LOGINLINK
2351  
2352  Thanks!
2353  
2354  --The Team @ SITE_NAME'
2355          );
2356          update_site_option( 'welcome_user_email', $text );
2357      }
2358      return $text;
2359  }
2360  
2361  /**
2362   * Determines whether to force SSL on content.
2363   *
2364   * @since 2.8.5
2365   *
2366   * @param bool $force
2367   * @return bool True if forced, false if not forced.
2368   */
2369  function force_ssl_content( $force = '' ) {
2370      static $forced_content = false;
2371  
2372      if ( ! $force ) {
2373          $old_forced     = $forced_content;
2374          $forced_content = $force;
2375          return $old_forced;
2376      }
2377  
2378      return $forced_content;
2379  }
2380  
2381  /**
2382   * Formats a URL to use https.
2383   *
2384   * Useful as a filter.
2385   *
2386   * @since 2.8.5
2387   *
2388   * @param string $url URL.
2389   * @return string URL with https as the scheme.
2390   */
2391  function filter_SSL( $url ) {  // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
2392      if ( ! is_string( $url ) ) {
2393          return get_bloginfo( 'url' ); // Return home site URL with proper scheme.
2394      }
2395  
2396      if ( force_ssl_content() && is_ssl() ) {
2397          $url = set_url_scheme( $url, 'https' );
2398      }
2399  
2400      return $url;
2401  }
2402  
2403  /**
2404   * Schedules update of the network-wide counts for the current network.
2405   *
2406   * @since 3.1.0
2407   */
2408  function wp_schedule_update_network_counts() {
2409      if ( ! is_main_site() ) {
2410          return;
2411      }
2412  
2413      if ( ! wp_next_scheduled( 'update_network_counts' ) && ! wp_installing() ) {
2414          wp_schedule_event( time(), 'twicedaily', 'update_network_counts' );
2415      }
2416  }
2417  
2418  /**
2419   * Updates the network-wide counts for the current network.
2420   *
2421   * @since 3.1.0
2422   * @since 4.8.0 The `$network_id` parameter has been added.
2423   *
2424   * @param int|null $network_id ID of the network. Default is the current network.
2425   */
2426  function wp_update_network_counts( $network_id = null ) {
2427      wp_update_network_user_counts( $network_id );
2428      wp_update_network_site_counts( $network_id );
2429  }
2430  
2431  /**
2432   * Updates the count of sites for the current network.
2433   *
2434   * If enabled through the {@see 'enable_live_network_counts'} filter, update the sites count
2435   * on a network when a site is created or its status is updated.
2436   *
2437   * @since 3.7.0
2438   * @since 4.8.0 The `$network_id` parameter has been added.
2439   *
2440   * @param int|null $network_id ID of the network. Default is the current network.
2441   */
2442  function wp_maybe_update_network_site_counts( $network_id = null ) {
2443      $is_small_network = ! wp_is_large_network( 'sites', $network_id );
2444  
2445      /**
2446       * Filters whether to update network site or user counts when a new site is created.
2447       *
2448       * @since 3.7.0
2449       *
2450       * @see wp_is_large_network()
2451       *
2452       * @param bool   $small_network Whether the network is considered small.
2453       * @param string $context       Context. Either 'users' or 'sites'.
2454       */
2455      if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'sites' ) ) {
2456          return;
2457      }
2458  
2459      wp_update_network_site_counts( $network_id );
2460  }
2461  
2462  /**
2463   * Updates the network-wide users count.
2464   *
2465   * If enabled through the {@see 'enable_live_network_counts'} filter, update the users count
2466   * on a network when a user is created or its status is updated.
2467   *
2468   * @since 3.7.0
2469   * @since 4.8.0 The `$network_id` parameter has been added.
2470   *
2471   * @param int|null $network_id ID of the network. Default is the current network.
2472   */
2473  function wp_maybe_update_network_user_counts( $network_id = null ) {
2474      $is_small_network = ! wp_is_large_network( 'users', $network_id );
2475  
2476      /** This filter is documented in wp-includes/ms-functions.php */
2477      if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'users' ) ) {
2478          return;
2479      }
2480  
2481      wp_update_network_user_counts( $network_id );
2482  }
2483  
2484  /**
2485   * Updates the network-wide site count.
2486   *
2487   * @since 3.7.0
2488   * @since 4.8.0 The `$network_id` parameter has been added.
2489   *
2490   * @param int|null $network_id ID of the network. Default is the current network.
2491   */
2492  function wp_update_network_site_counts( $network_id = null ) {
2493      $network_id = (int) $network_id;
2494      if ( ! $network_id ) {
2495          $network_id = get_current_network_id();
2496      }
2497  
2498      $count = get_sites(
2499          array(
2500              'network_id'             => $network_id,
2501              'spam'                   => 0,
2502              'deleted'                => 0,
2503              'archived'               => 0,
2504              'count'                  => true,
2505              'update_site_meta_cache' => false,
2506          )
2507      );
2508  
2509      update_network_option( $network_id, 'blog_count', $count );
2510  }
2511  
2512  /**
2513   * Updates the network-wide user count.
2514   *
2515   * @since 3.7.0
2516   * @since 4.8.0 The `$network_id` parameter has been added.
2517   * @since 6.0.0 This function is now a wrapper for wp_update_user_counts().
2518   *
2519   * @param int|null $network_id ID of the network. Default is the current network.
2520   */
2521  function wp_update_network_user_counts( $network_id = null ) {
2522      wp_update_user_counts( $network_id );
2523  }
2524  
2525  /**
2526   * Returns the space used by the current site.
2527   *
2528   * @since 3.5.0
2529   *
2530   * @return int Used space in megabytes.
2531   */
2532  function get_space_used() {
2533      /**
2534       * Filters the amount of storage space used by the current site, in megabytes.
2535       *
2536       * @since 3.5.0
2537       *
2538       * @param int|false $space_used The amount of used space, in megabytes. Default false.
2539       */
2540      $space_used = apply_filters( 'pre_get_space_used', false );
2541  
2542      if ( false === $space_used ) {
2543          $upload_dir = wp_upload_dir();
2544          $space_used = get_dirsize( $upload_dir['basedir'] ) / MB_IN_BYTES;
2545      }
2546  
2547      return $space_used;
2548  }
2549  
2550  /**
2551   * Returns the upload quota for the current blog.
2552   *
2553   * @since MU (3.0.0)
2554   *
2555   * @return int Quota in megabytes.
2556   */
2557  function get_space_allowed() {
2558      $space_allowed = get_option( 'blog_upload_space' );
2559  
2560      if ( ! is_numeric( $space_allowed ) ) {
2561          $space_allowed = get_site_option( 'blog_upload_space' );
2562      }
2563  
2564      if ( ! is_numeric( $space_allowed ) ) {
2565          $space_allowed = 100;
2566      }
2567  
2568      /**
2569       * Filters the upload quota for the current site.
2570       *
2571       * @since 3.7.0
2572       *
2573       * @param int $space_allowed Upload quota in megabytes for the current blog.
2574       */
2575      return apply_filters( 'get_space_allowed', $space_allowed );
2576  }
2577  
2578  /**
2579   * Determines if there is any upload space left in the current blog's quota.
2580   *
2581   * @since 3.0.0
2582   *
2583   * @return int of upload space available in bytes.
2584   */
2585  function get_upload_space_available() {
2586      $allowed = get_space_allowed();
2587      if ( $allowed < 0 ) {
2588          $allowed = 0;
2589      }
2590      $space_allowed = $allowed * MB_IN_BYTES;
2591      if ( get_site_option( 'upload_space_check_disabled' ) ) {
2592          return $space_allowed;
2593      }
2594  
2595      $space_used = get_space_used() * MB_IN_BYTES;
2596  
2597      if ( ( $space_allowed - $space_used ) <= 0 ) {
2598          return 0;
2599      }
2600  
2601      return $space_allowed - $space_used;
2602  }
2603  
2604  /**
2605   * Determines if there is any upload space left in the current blog's quota.
2606   *
2607   * @since 3.0.0
2608   * @return bool True if space is available, false otherwise.
2609   */
2610  function is_upload_space_available() {
2611      if ( get_site_option( 'upload_space_check_disabled' ) ) {
2612          return true;
2613      }
2614  
2615      return (bool) get_upload_space_available();
2616  }
2617  
2618  /**
2619   * Filters the maximum upload file size allowed, in bytes.
2620   *
2621   * @since 3.0.0
2622   *
2623   * @param int $size Upload size limit in bytes.
2624   * @return int Upload size limit in bytes.
2625   */
2626  function upload_size_limit_filter( $size ) {
2627      $fileupload_maxk         = (int) get_site_option( 'fileupload_maxk', 1500 );
2628      $max_fileupload_in_bytes = KB_IN_BYTES * $fileupload_maxk;
2629  
2630      if ( get_site_option( 'upload_space_check_disabled' ) ) {
2631          return min( $size, $max_fileupload_in_bytes );
2632      }
2633  
2634      return min( $size, $max_fileupload_in_bytes, get_upload_space_available() );
2635  }
2636  
2637  /**
2638   * Determines whether or not we have a large network.
2639   *
2640   * The default criteria for a large network is either more than 10,000 users or more than 10,000 sites.
2641   * Plugins can alter this criteria using the {@see 'wp_is_large_network'} filter.
2642   *
2643   * @since 3.3.0
2644   * @since 4.8.0 The `$network_id` parameter has been added.
2645   *
2646   * @param string   $using      'sites' or 'users'. Default is 'sites'.
2647   * @param int|null $network_id ID of the network. Default is the current network.
2648   * @return bool True if the network meets the criteria for large. False otherwise.
2649   */
2650  function wp_is_large_network( $using = 'sites', $network_id = null ) {
2651      $network_id = (int) $network_id;
2652      if ( ! $network_id ) {
2653          $network_id = get_current_network_id();
2654      }
2655  
2656      if ( 'users' === $using ) {
2657          $count = get_user_count( $network_id );
2658  
2659          $is_large_network = wp_is_large_user_count( $network_id );
2660  
2661          /**
2662           * Filters whether the network is considered large.
2663           *
2664           * @since 3.3.0
2665           * @since 4.8.0 The `$network_id` parameter has been added.
2666           *
2667           * @param bool   $is_large_network Whether the network has more than 10000 users or sites.
2668           * @param string $component        The component to count. Accepts 'users', or 'sites'.
2669           * @param int    $count            The count of items for the component.
2670           * @param int    $network_id       The ID of the network being checked.
2671           */
2672          return apply_filters( 'wp_is_large_network', $is_large_network, 'users', $count, $network_id );
2673      }
2674  
2675      $count = get_blog_count( $network_id );
2676  
2677      /** This filter is documented in wp-includes/ms-functions.php */
2678      return apply_filters( 'wp_is_large_network', $count > 10000, 'sites', $count, $network_id );
2679  }
2680  
2681  /**
2682   * Retrieves a list of reserved site on a sub-directory Multisite installation.
2683   *
2684   * @since 4.4.0
2685   *
2686   * @return string[] Array of reserved names.
2687   */
2688  function get_subdirectory_reserved_names() {
2689      $names = array(
2690          'page',
2691          'comments',
2692          'blog',
2693          'files',
2694          'feed',
2695          'wp-admin',
2696          'wp-content',
2697          'wp-includes',
2698          'wp-json',
2699          'embed',
2700      );
2701  
2702      /**
2703       * Filters reserved site names on a sub-directory Multisite installation.
2704       *
2705       * @since 3.0.0
2706       * @since 4.4.0 'wp-admin', 'wp-content', 'wp-includes', 'wp-json', and 'embed' were added
2707       *              to the reserved names list.
2708       *
2709       * @param string[] $subdirectory_reserved_names Array of reserved names.
2710       */
2711      return apply_filters( 'subdirectory_reserved_names', $names );
2712  }
2713  
2714  /**
2715   * Sends a confirmation request email when a change of network admin email address is attempted.
2716   *
2717   * The new network admin address will not become active until confirmed.
2718   *
2719   * @since 4.9.0
2720   *
2721   * @param string $old_value The old network admin email address.
2722   * @param string $value     The proposed new network admin email address.
2723   */
2724  function update_network_option_new_admin_email( $old_value, $value ) {
2725      if ( get_site_option( 'admin_email' ) === $value || ! is_email( $value ) ) {
2726          return;
2727      }
2728  
2729      $hash            = md5( $value . time() . mt_rand() );
2730      $new_admin_email = array(
2731          'hash'     => $hash,
2732          'newemail' => $value,
2733      );
2734      update_site_option( 'network_admin_hash', $new_admin_email );
2735  
2736      $switched_locale = switch_to_user_locale( get_current_user_id() );
2737  
2738      /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
2739      $email_text = __(
2740          'Howdy ###USERNAME###,
2741  
2742  You recently requested to have the network admin email address on
2743  your network changed.
2744  
2745  If this is correct, please click on the following link to change it:
2746  ###ADMIN_URL###
2747  
2748  You can safely ignore and delete this email if you do not want to
2749  take this action.
2750  
2751  This email has been sent to ###EMAIL###
2752  
2753  Regards,
2754  All at ###SITENAME###
2755  ###SITEURL###'
2756      );
2757  
2758      /**
2759       * Filters the text of the email sent when a change of network admin email address is attempted.
2760       *
2761       * The following strings have a special meaning and will get replaced dynamically:
2762       * ###USERNAME###  The current user's username.
2763       * ###ADMIN_URL### The link to click on to confirm the email change.
2764       * ###EMAIL###     The proposed new network admin email address.
2765       * ###SITENAME###  The name of the network.
2766       * ###SITEURL###   The URL to the network.
2767       *
2768       * @since 4.9.0
2769       *
2770       * @param string $email_text      Text in the email.
2771       * @param array  $new_admin_email {
2772       *     Data relating to the new network admin email address.
2773       *
2774       *     @type string $hash     The secure hash used in the confirmation link URL.
2775       *     @type string $newemail The proposed new network admin email address.
2776       * }
2777       */
2778      $content = apply_filters( 'new_network_admin_email_content', $email_text, $new_admin_email );
2779  
2780      $current_user = wp_get_current_user();
2781      $content      = str_replace( '###USERNAME###', $current_user->user_login, $content );
2782      $content      = str_replace( '###ADMIN_URL###', esc_url( network_admin_url( 'settings.php?network_admin_hash=' . $hash ) ), $content );
2783      $content      = str_replace( '###EMAIL###', $value, $content );
2784      $content      = str_replace( '###SITENAME###', wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES ), $content );
2785      $content      = str_replace( '###SITEURL###', network_home_url(), $content );
2786  
2787      wp_mail(
2788          $value,
2789          sprintf(
2790              /* translators: Email change notification email subject. %s: Network title. */
2791              __( '[%s] Network Admin Email Change Request' ),
2792              wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES )
2793          ),
2794          $content
2795      );
2796  
2797      if ( $switched_locale ) {
2798          restore_previous_locale();
2799      }
2800  }
2801  
2802  /**
2803   * Sends an email to the old network admin email address when the network admin email address changes.
2804   *
2805   * @since 4.9.0
2806   *
2807   * @param string $option_name The relevant database option name.
2808   * @param string $new_email   The new network admin email address.
2809   * @param string $old_email   The old network admin email address.
2810   * @param int    $network_id  ID of the network.
2811   */
2812  function wp_network_admin_email_change_notification( $option_name, $new_email, $old_email, $network_id ) {
2813      $send = true;
2814  
2815      // Don't send the notification to the default 'admin_email' value.
2816      if ( 'you@example.com' === $old_email ) {
2817          $send = false;
2818      }
2819  
2820      /**
2821       * Filters whether to send the network admin email change notification email.
2822       *
2823       * @since 4.9.0
2824       *
2825       * @param bool   $send       Whether to send the email notification.
2826       * @param string $old_email  The old network admin email address.
2827       * @param string $new_email  The new network admin email address.
2828       * @param int    $network_id ID of the network.
2829       */
2830      $send = apply_filters( 'send_network_admin_email_change_email', $send, $old_email, $new_email, $network_id );
2831  
2832      if ( ! $send ) {
2833          return;
2834      }
2835  
2836      /* translators: Do not translate OLD_EMAIL, NEW_EMAIL, SITENAME, SITEURL: those are placeholders. */
2837      $email_change_text = __(
2838          'Hi,
2839  
2840  This notice confirms that the network admin email address was changed on ###SITENAME###.
2841  
2842  The new network admin email address is ###NEW_EMAIL###.
2843  
2844  This email has been sent to ###OLD_EMAIL###
2845  
2846  Regards,
2847  All at ###SITENAME###
2848  ###SITEURL###'
2849      );
2850  
2851      $email_change_email = array(
2852          'to'      => $old_email,
2853          /* translators: Network admin email change notification email subject. %s: Network title. */
2854          'subject' => __( '[%s] Network Admin Email Changed' ),
2855          'message' => $email_change_text,
2856          'headers' => '',
2857      );
2858      // Get network name.
2859      $network_name = wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES );
2860  
2861      /**
2862       * Filters the contents of the email notification sent when the network admin email address is changed.
2863       *
2864       * @since 4.9.0
2865       *
2866       * @param array $email_change_email {
2867       *     Used to build wp_mail().
2868       *
2869       *     @type string $to      The intended recipient.
2870       *     @type string $subject The subject of the email.
2871       *     @type string $message The content of the email.
2872       *         The following strings have a special meaning and will get replaced dynamically:
2873       *         - ###OLD_EMAIL### The old network admin email address.
2874       *         - ###NEW_EMAIL### The new network admin email address.
2875       *         - ###SITENAME###  The name of the network.
2876       *         - ###SITEURL###   The URL to the site.
2877       *     @type string $headers Headers.
2878       * }
2879       * @param string $old_email  The old network admin email address.
2880       * @param string $new_email  The new network admin email address.
2881       * @param int    $network_id ID of the network.
2882       */
2883      $email_change_email = apply_filters( 'network_admin_email_change_email', $email_change_email, $old_email, $new_email, $network_id );
2884  
2885      $email_change_email['message'] = str_replace( '###OLD_EMAIL###', $old_email, $email_change_email['message'] );
2886      $email_change_email['message'] = str_replace( '###NEW_EMAIL###', $new_email, $email_change_email['message'] );
2887      $email_change_email['message'] = str_replace( '###SITENAME###', $network_name, $email_change_email['message'] );
2888      $email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] );
2889  
2890      wp_mail(
2891          $email_change_email['to'],
2892          sprintf(
2893              $email_change_email['subject'],
2894              $network_name
2895          ),
2896          $email_change_email['message'],
2897          $email_change_email['headers']
2898      );
2899  }


Generated : Tue Mar 19 08:20:01 2024 Cross-referenced by PHPXref