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


Generated: Mon Jun 17 08:20:02 2019 Cross-referenced by PHPXref 0.7