[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Mon Nov 11 01:00:04 2019 Cross-referenced by PHPXref 0.7.1