[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

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


Generated: Sat Nov 23 20:47:33 2019 Cross-referenced by PHPXref 0.7