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


Generated: Thu Jun 4 01:00:04 2020 Cross-referenced by PHPXref 0.7.1