[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Multisite WordPress API
   4   *
   5   * @package WordPress
   6   * @subpackage Multisite
   7   * @since 3.0.0
   8   */
   9  
  10  /**
  11   * Gets the network's site and user counts.
  12   *
  13   * @since MU (3.0.0)
  14   *
  15   * @return int[] {
  16   *     Site and user count for the network.
  17   *
  18   *     @type int $blogs Number of sites on the network.
  19   *     @type int $users Number of users on the network.
  20   * }
  21   */
  22  function get_sitestats() {
  23      $stats = array(
  24          'blogs' => get_blog_count(),
  25          'users' => get_user_count(),
  26      );
  27  
  28      return $stats;
  29  }
  30  
  31  /**
  32   * 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 bool|WP_Error $retval  True if the user should be added to the site, false
 180       *                               or error 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 Returns true when the email address is banned.
 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      $admin_email  = get_site_option( 'admin_email' );
 948      if ( '' == $admin_email ) {
 949          $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
 950      }
 951      $from_name       = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
 952      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
 953  
 954      $user            = get_user_by( 'login', $user_login );
 955      $switched_locale = switch_to_locale( get_user_locale( $user ) );
 956  
 957      $message = sprintf(
 958          /**
 959           * Filters the message content of the new blog notification email.
 960           *
 961           * Content should be formatted for transmission via wp_mail().
 962           *
 963           * @since MU (3.0.0)
 964           *
 965           * @param string $content    Content of the notification email.
 966           * @param string $domain     Site domain.
 967           * @param string $path       Site path.
 968           * @param string $title      Site title.
 969           * @param string $user_login User login name.
 970           * @param string $user_email User email address.
 971           * @param string $key        Activation key created in wpmu_signup_blog().
 972           * @param array  $meta       Signup meta data. By default, contains the requested privacy setting and lang_id.
 973           */
 974          apply_filters(
 975              'wpmu_signup_blog_notification_email',
 976              /* translators: New site notification email. 1: Activation URL, 2: New site URL. */
 977              __( "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" ),
 978              $domain,
 979              $path,
 980              $title,
 981              $user_login,
 982              $user_email,
 983              $key,
 984              $meta
 985          ),
 986          $activate_url,
 987          esc_url( "http://{$domain}{$path}" ),
 988          $key
 989      );
 990  
 991      $subject = sprintf(
 992          /**
 993           * Filters the subject of the new blog notification email.
 994           *
 995           * @since MU (3.0.0)
 996           *
 997           * @param string $subject    Subject of the notification email.
 998           * @param string $domain     Site domain.
 999           * @param string $path       Site path.
1000           * @param string $title      Site title.
1001           * @param string $user_login User login name.
1002           * @param string $user_email User email address.
1003           * @param string $key        Activation key created in wpmu_signup_blog().
1004           * @param array  $meta       Signup meta data. By default, contains the requested privacy setting and lang_id.
1005           */
1006          apply_filters(
1007              'wpmu_signup_blog_notification_subject',
1008              /* translators: New site notification email subject. 1: Network title, 2: New site URL. */
1009              _x( '[%1$s] Activate %2$s', 'New site notification email subject' ),
1010              $domain,
1011              $path,
1012              $title,
1013              $user_login,
1014              $user_email,
1015              $key,
1016              $meta
1017          ),
1018          $from_name,
1019          esc_url( 'http://' . $domain . $path )
1020      );
1021  
1022      wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1023  
1024      if ( $switched_locale ) {
1025          restore_previous_locale();
1026      }
1027  
1028      return true;
1029  }
1030  
1031  /**
1032   * Send a confirmation request email to a user when they sign up for a new user account (without signing up for a site
1033   * at the same time). The user account will not become active until the confirmation link is clicked.
1034   *
1035   * This is the notification function used when no new site has
1036   * been requested.
1037   *
1038   * Filter {@see 'wpmu_signup_user_notification'} to bypass this function or
1039   * replace it with your own notification behavior.
1040   *
1041   * Filter {@see 'wpmu_signup_user_notification_email'} and
1042   * {@see 'wpmu_signup_user_notification_subject'} to change the content
1043   * and subject line of the email sent to newly registered users.
1044   *
1045   * @since MU (3.0.0)
1046   *
1047   * @param string $user_login The user's login name.
1048   * @param string $user_email The user's email address.
1049   * @param string $key        The activation key created in wpmu_signup_user()
1050   * @param array  $meta       Optional. Signup meta data. Default empty array.
1051   * @return bool
1052   */
1053  function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta = array() ) {
1054      /**
1055       * Filters whether to bypass the email notification for new user sign-up.
1056       *
1057       * @since MU (3.0.0)
1058       *
1059       * @param string $user_login User login name.
1060       * @param string $user_email User email address.
1061       * @param string $key        Activation key created in wpmu_signup_user().
1062       * @param array  $meta       Signup meta data. Default empty array.
1063       */
1064      if ( ! apply_filters( 'wpmu_signup_user_notification', $user_login, $user_email, $key, $meta ) ) {
1065          return false;
1066      }
1067  
1068      $user            = get_user_by( 'login', $user_login );
1069      $switched_locale = switch_to_locale( get_user_locale( $user ) );
1070  
1071      // Send email with activation link.
1072      $admin_email = get_site_option( 'admin_email' );
1073      if ( '' == $admin_email ) {
1074          $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
1075      }
1076      $from_name       = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
1077      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
1078      $message         = sprintf(
1079          /**
1080           * Filters the content of the notification email for new user sign-up.
1081           *
1082           * Content should be formatted for transmission via wp_mail().
1083           *
1084           * @since MU (3.0.0)
1085           *
1086           * @param string $content    Content of the notification email.
1087           * @param string $user_login User login name.
1088           * @param string $user_email User email address.
1089           * @param string $key        Activation key created in wpmu_signup_user().
1090           * @param array  $meta       Signup meta data. Default empty array.
1091           */
1092          apply_filters(
1093              'wpmu_signup_user_notification_email',
1094              /* translators: New user notification email. %s: Activation URL. */
1095              __( "To activate your user, please click the following link:\n\n%s\n\nAfter you activate, you will receive *another email* with your login." ),
1096              $user_login,
1097              $user_email,
1098              $key,
1099              $meta
1100          ),
1101          site_url( "wp-activate.php?key=$key" )
1102      );
1103  
1104      $subject = sprintf(
1105          /**
1106           * Filters the subject of the notification email of new user signup.
1107           *
1108           * @since MU (3.0.0)
1109           *
1110           * @param string $subject    Subject of the notification email.
1111           * @param string $user_login User login name.
1112           * @param string $user_email User email address.
1113           * @param string $key        Activation key created in wpmu_signup_user().
1114           * @param array  $meta       Signup meta data. Default empty array.
1115           */
1116          apply_filters(
1117              'wpmu_signup_user_notification_subject',
1118              /* translators: New user notification email subject. 1: Network title, 2: New user login. */
1119              _x( '[%1$s] Activate %2$s', 'New user notification email subject' ),
1120              $user_login,
1121              $user_email,
1122              $key,
1123              $meta
1124          ),
1125          $from_name,
1126          $user_login
1127      );
1128  
1129      wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1130  
1131      if ( $switched_locale ) {
1132          restore_previous_locale();
1133      }
1134  
1135      return true;
1136  }
1137  
1138  /**
1139   * Activate a signup.
1140   *
1141   * Hook to {@see 'wpmu_activate_user'} or {@see 'wpmu_activate_blog'} for events
1142   * that should happen only when users or sites are self-created (since
1143   * those actions are not called when users and sites are created
1144   * by a Super Admin).
1145   *
1146   * @since MU (3.0.0)
1147   *
1148   * @global wpdb $wpdb WordPress database abstraction object.
1149   *
1150   * @param string $key The activation key provided to the user.
1151   * @return array|WP_Error An array containing information about the activated user and/or blog
1152   */
1153  function wpmu_activate_signup( $key ) {
1154      global $wpdb;
1155  
1156      $signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s", $key ) );
1157  
1158      if ( empty( $signup ) ) {
1159          return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
1160      }
1161  
1162      if ( $signup->active ) {
1163          if ( empty( $signup->domain ) ) {
1164              return new WP_Error( 'already_active', __( 'The user is already active.' ), $signup );
1165          } else {
1166              return new WP_Error( 'already_active', __( 'The site is already active.' ), $signup );
1167          }
1168      }
1169  
1170      $meta     = maybe_unserialize( $signup->meta );
1171      $password = wp_generate_password( 12, false );
1172  
1173      $user_id = username_exists( $signup->user_login );
1174  
1175      if ( ! $user_id ) {
1176          $user_id = wpmu_create_user( $signup->user_login, $password, $signup->user_email );
1177      } else {
1178          $user_already_exists = true;
1179      }
1180  
1181      if ( ! $user_id ) {
1182          return new WP_Error( 'create_user', __( 'Could not create user' ), $signup );
1183      }
1184  
1185      $now = current_time( 'mysql', true );
1186  
1187      if ( empty( $signup->domain ) ) {
1188          $wpdb->update(
1189              $wpdb->signups,
1190              array(
1191                  'active'    => 1,
1192                  'activated' => $now,
1193              ),
1194              array( 'activation_key' => $key )
1195          );
1196  
1197          if ( isset( $user_already_exists ) ) {
1198              return new WP_Error( 'user_already_exists', __( 'That username is already activated.' ), $signup );
1199          }
1200  
1201          /**
1202           * Fires immediately after a new user is activated.
1203           *
1204           * @since MU (3.0.0)
1205           *
1206           * @param int    $user_id  User ID.
1207           * @param string $password User password.
1208           * @param array  $meta     Signup meta data.
1209           */
1210          do_action( 'wpmu_activate_user', $user_id, $password, $meta );
1211          return array(
1212              'user_id'  => $user_id,
1213              'password' => $password,
1214              'meta'     => $meta,
1215          );
1216      }
1217  
1218      $blog_id = wpmu_create_blog( $signup->domain, $signup->path, $signup->title, $user_id, $meta, get_current_network_id() );
1219  
1220      // TODO: What to do if we create a user but cannot create a blog?
1221      if ( is_wp_error( $blog_id ) ) {
1222          /*
1223           * If blog is taken, that means a previous attempt to activate this blog
1224           * failed in between creating the blog and setting the activation flag.
1225           * Let's just set the active flag and instruct the user to reset their password.
1226           */
1227          if ( 'blog_taken' == $blog_id->get_error_code() ) {
1228              $blog_id->add_data( $signup );
1229              $wpdb->update(
1230                  $wpdb->signups,
1231                  array(
1232                      'active'    => 1,
1233                      'activated' => $now,
1234                  ),
1235                  array( 'activation_key' => $key )
1236              );
1237          }
1238          return $blog_id;
1239      }
1240  
1241      $wpdb->update(
1242          $wpdb->signups,
1243          array(
1244              'active'    => 1,
1245              'activated' => $now,
1246          ),
1247          array( 'activation_key' => $key )
1248      );
1249      /**
1250       * Fires immediately after a site is activated.
1251       *
1252       * @since MU (3.0.0)
1253       *
1254       * @param int    $blog_id       Blog ID.
1255       * @param int    $user_id       User ID.
1256       * @param int    $password      User password.
1257       * @param string $signup_title  Site title.
1258       * @param array  $meta          Signup meta data. By default, contains the requested privacy setting and lang_id.
1259       */
1260      do_action( 'wpmu_activate_blog', $blog_id, $user_id, $password, $signup->title, $meta );
1261  
1262      return array(
1263          'blog_id'  => $blog_id,
1264          'user_id'  => $user_id,
1265          'password' => $password,
1266          'title'    => $signup->title,
1267          'meta'     => $meta,
1268      );
1269  }
1270  
1271  /**
1272   * Create a user.
1273   *
1274   * This function runs when a user self-registers as well as when
1275   * a Super Admin creates a new user. Hook to {@see 'wpmu_new_user'} for events
1276   * that should affect all new users, but only on Multisite (otherwise
1277   * use {@see'user_register'}).
1278   *
1279   * @since MU (3.0.0)
1280   *
1281   * @param string $user_name The new user's login name.
1282   * @param string $password  The new user's password.
1283   * @param string $email     The new user's email address.
1284   * @return int|false Returns false on failure, or int $user_id on success
1285   */
1286  function wpmu_create_user( $user_name, $password, $email ) {
1287      $user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
1288  
1289      $user_id = wp_create_user( $user_name, $password, $email );
1290      if ( is_wp_error( $user_id ) ) {
1291          return false;
1292      }
1293  
1294      // Newly created users have no roles or caps until they are added to a blog.
1295      delete_user_option( $user_id, 'capabilities' );
1296      delete_user_option( $user_id, 'user_level' );
1297  
1298      /**
1299       * Fires immediately after a new user is created.
1300       *
1301       * @since MU (3.0.0)
1302       *
1303       * @param int $user_id User ID.
1304       */
1305      do_action( 'wpmu_new_user', $user_id );
1306  
1307      return $user_id;
1308  }
1309  
1310  /**
1311   * Create a site.
1312   *
1313   * This function runs when a user self-registers a new site as well
1314   * as when a Super Admin creates a new site. Hook to {@see 'wpmu_new_blog'}
1315   * for events that should affect all new sites.
1316   *
1317   * On subdirectory installations, $domain is the same as the main site's
1318   * domain, and the path is the subdirectory name (eg 'example.com'
1319   * and '/blog1/'). On subdomain installations, $domain is the new subdomain +
1320   * root domain (eg 'blog1.example.com'), and $path is '/'.
1321   *
1322   * @since MU (3.0.0)
1323   *
1324   * @param string $domain     The new site's domain.
1325   * @param string $path       The new site's path.
1326   * @param string $title      The new site's title.
1327   * @param int    $user_id    The user ID of the new site's admin.
1328   * @param array  $options    Optional. Array of key=>value pairs used to set initial site options.
1329   *                           If valid status keys are included ('public', 'archived', 'mature',
1330   *                           'spam', 'deleted', or 'lang_id') the given site status(es) will be
1331   *                           updated. Otherwise, keys and values will be used to set options for
1332   *                           the new site. Default empty array.
1333   * @param int    $network_id Optional. Network ID. Only relevant on multi-network installations.
1334   * @return int|WP_Error Returns WP_Error object on failure, the new site ID on success.
1335   */
1336  function wpmu_create_blog( $domain, $path, $title, $user_id, $options = array(), $network_id = 1 ) {
1337      $defaults = array(
1338          'public' => 0,
1339      );
1340      $options  = wp_parse_args( $options, $defaults );
1341  
1342      $title   = strip_tags( $title );
1343      $user_id = (int) $user_id;
1344  
1345      // Check if the domain has been used already. We should return an error message.
1346      if ( domain_exists( $domain, $path, $network_id ) ) {
1347          return new WP_Error( 'blog_taken', __( 'Sorry, that site already exists!' ) );
1348      }
1349  
1350      if ( ! wp_installing() ) {
1351          wp_installing( true );
1352      }
1353  
1354      $site_data_whitelist = array( 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
1355  
1356      $site_data = array_merge(
1357          array(
1358              'domain'     => $domain,
1359              'path'       => $path,
1360              'network_id' => $network_id,
1361          ),
1362          array_intersect_key( $options, array_flip( $site_data_whitelist ) )
1363      );
1364  
1365      // Data to pass to wp_initialize_site().
1366      $site_initialization_data = array(
1367          'title'   => $title,
1368          'user_id' => $user_id,
1369          'options' => array_diff_key( $options, array_flip( $site_data_whitelist ) ),
1370      );
1371  
1372      $blog_id = wp_insert_site( array_merge( $site_data, $site_initialization_data ) );
1373  
1374      if ( is_wp_error( $blog_id ) ) {
1375          return $blog_id;
1376      }
1377  
1378      wp_cache_set( 'last_changed', microtime(), 'sites' );
1379  
1380      return $blog_id;
1381  }
1382  
1383  /**
1384   * Notifies the network admin that a new site has been activated.
1385   *
1386   * Filter {@see 'newblog_notify_siteadmin'} to change the content of
1387   * the notification email.
1388   *
1389   * @since MU (3.0.0)
1390   * @since 5.1.0 $blog_id now supports input from the {@see 'wp_initialize_site'} action.
1391   *
1392   * @param WP_Site|int $blog_id    The new site's object or ID.
1393   * @param string      $deprecated Not used.
1394   * @return bool
1395   */
1396  function newblog_notify_siteadmin( $blog_id, $deprecated = '' ) {
1397      if ( is_object( $blog_id ) ) {
1398          $blog_id = $blog_id->blog_id;
1399      }
1400  
1401      if ( get_site_option( 'registrationnotification' ) != 'yes' ) {
1402          return false;
1403      }
1404  
1405      $email = get_site_option( 'admin_email' );
1406      if ( is_email( $email ) == false ) {
1407          return false;
1408      }
1409  
1410      $options_site_url = esc_url( network_admin_url( 'settings.php' ) );
1411  
1412      switch_to_blog( $blog_id );
1413      $blogname = get_option( 'blogname' );
1414      $siteurl  = site_url();
1415      restore_current_blog();
1416  
1417      $msg = sprintf(
1418          /* translators: New site notification email. 1: Site URL, 2: User IP address, 3: URL to Network Settings screen. */
1419          __(
1420              'New Site: %1$s
1421  URL: %2$s
1422  Remote IP address: %3$s
1423  
1424  Disable these notifications: %4$s'
1425          ),
1426          $blogname,
1427          $siteurl,
1428          wp_unslash( $_SERVER['REMOTE_ADDR'] ),
1429          $options_site_url
1430      );
1431      /**
1432       * Filters the message body of the new site activation email sent
1433       * to the network administrator.
1434       *
1435       * @since MU (3.0.0)
1436       * @since 5.4.0 The `$blog_id` parameter was added.
1437       *
1438       * @param string $msg     Email body.
1439       * @param int    $blog_id The new site's ID.
1440       */
1441      $msg = apply_filters( 'newblog_notify_siteadmin', $msg, $blog_id );
1442  
1443      /* translators: New site notification email subject. %s: New site URL. */
1444      wp_mail( $email, sprintf( __( 'New Site Registration: %s' ), $siteurl ), $msg );
1445  
1446      return true;
1447  }
1448  
1449  /**
1450   * Notifies the network admin that a new user has been activated.
1451   *
1452   * Filter {@see 'newuser_notify_siteadmin'} to change the content of
1453   * the notification email.
1454   *
1455   * @since MU (3.0.0)
1456   *
1457   * @param int $user_id The new user's ID.
1458   * @return bool
1459   */
1460  function newuser_notify_siteadmin( $user_id ) {
1461      if ( get_site_option( 'registrationnotification' ) != 'yes' ) {
1462          return false;
1463      }
1464  
1465      $email = get_site_option( 'admin_email' );
1466  
1467      if ( is_email( $email ) == false ) {
1468          return false;
1469      }
1470  
1471      $user = get_userdata( $user_id );
1472  
1473      $options_site_url = esc_url( network_admin_url( 'settings.php' ) );
1474  
1475      $msg = sprintf(
1476          /* translators: New user notification email. 1: User login, 2: User IP address, 3: URL to Network Settings screen. */
1477          __(
1478              'New User: %1$s
1479  Remote IP address: %2$s
1480  
1481  Disable these notifications: %3$s'
1482          ),
1483          $user->user_login,
1484          wp_unslash( $_SERVER['REMOTE_ADDR'] ),
1485          $options_site_url
1486      );
1487  
1488      /**
1489       * Filters the message body of the new user activation email sent
1490       * to the network administrator.
1491       *
1492       * @since MU (3.0.0)
1493       *
1494       * @param string  $msg  Email body.
1495       * @param WP_User $user WP_User instance of the new user.
1496       */
1497      $msg = apply_filters( 'newuser_notify_siteadmin', $msg, $user );
1498  
1499      /* translators: New user notification email subject. %s: User login. */
1500      wp_mail( $email, sprintf( __( 'New User Registration: %s' ), $user->user_login ), $msg );
1501  
1502      return true;
1503  }
1504  
1505  /**
1506   * Checks whether a site name is already taken.
1507   *
1508   * The name is the site's subdomain or the site's subdirectory
1509   * path depending on the network settings.
1510   *
1511   * Used during the new site registration process to ensure
1512   * that each site name is unique.
1513   *
1514   * @since MU (3.0.0)
1515   *
1516   * @param string $domain     The domain to be checked.
1517   * @param string $path       The path to be checked.
1518   * @param int    $network_id Optional. Network ID. Relevant only on multi-network installations.
1519   * @return int|null The site ID if the site name exists, null otherwise.
1520   */
1521  function domain_exists( $domain, $path, $network_id = 1 ) {
1522      $path   = trailingslashit( $path );
1523      $args   = array(
1524          'network_id'             => $network_id,
1525          'domain'                 => $domain,
1526          'path'                   => $path,
1527          'fields'                 => 'ids',
1528          'number'                 => 1,
1529          'update_site_meta_cache' => false,
1530      );
1531      $result = get_sites( $args );
1532      $result = array_shift( $result );
1533  
1534      /**
1535       * Filters whether a site name is taken.
1536       *
1537       * The name is the site's subdomain or the site's subdirectory
1538       * path depending on the network settings.
1539       *
1540       * @since 3.5.0
1541       *
1542       * @param int|null $result     The site ID if the site name exists, null otherwise.
1543       * @param string   $domain     Domain to be checked.
1544       * @param string   $path       Path to be checked.
1545       * @param int      $network_id Network ID. Relevant only on multi-network installations.
1546       */
1547      return apply_filters( 'domain_exists', $result, $domain, $path, $network_id );
1548  }
1549  
1550  /**
1551   * Notify a user that their blog activation has been successful.
1552   *
1553   * Filter {@see 'wpmu_welcome_notification'} to disable or bypass.
1554   *
1555   * Filter {@see 'update_welcome_email'} and {@see 'update_welcome_subject'} to
1556   * modify the content and subject line of the notification email.
1557   *
1558   * @since MU (3.0.0)
1559   *
1560   * @param int    $blog_id  Blog ID.
1561   * @param int    $user_id  User ID.
1562   * @param string $password User password.
1563   * @param string $title    Site title.
1564   * @param array  $meta     Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
1565   * @return bool
1566   */
1567  function wpmu_welcome_notification( $blog_id, $user_id, $password, $title, $meta = array() ) {
1568      $current_network = get_network();
1569  
1570      /**
1571       * Filters whether to bypass the welcome email after site activation.
1572       *
1573       * Returning false disables the welcome email.
1574       *
1575       * @since MU (3.0.0)
1576       *
1577       * @param int|bool $blog_id  Blog ID.
1578       * @param int      $user_id  User ID.
1579       * @param string   $password User password.
1580       * @param string   $title    Site title.
1581       * @param array    $meta     Signup meta data. By default, contains the requested privacy setting and lang_id.
1582       */
1583      if ( ! apply_filters( 'wpmu_welcome_notification', $blog_id, $user_id, $password, $title, $meta ) ) {
1584          return false;
1585      }
1586  
1587      $user = get_userdata( $user_id );
1588  
1589      $switched_locale = switch_to_locale( get_user_locale( $user ) );
1590  
1591      $welcome_email = get_site_option( 'welcome_email' );
1592      if ( false == $welcome_email ) {
1593          /* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */
1594          $welcome_email = __(
1595              'Howdy USERNAME,
1596  
1597  Your new SITE_NAME site has been successfully set up at:
1598  BLOG_URL
1599  
1600  You can log in to the administrator account with the following information:
1601  
1602  Username: USERNAME
1603  Password: PASSWORD
1604  Log in here: BLOG_URLwp-login.php
1605  
1606  We hope you enjoy your new site. Thanks!
1607  
1608  --The Team @ SITE_NAME'
1609          );
1610      }
1611  
1612      $url = get_blogaddress_by_id( $blog_id );
1613  
1614      $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
1615      $welcome_email = str_replace( 'BLOG_TITLE', $title, $welcome_email );
1616      $welcome_email = str_replace( 'BLOG_URL', $url, $welcome_email );
1617      $welcome_email = str_replace( 'USERNAME', $user->user_login, $welcome_email );
1618      $welcome_email = str_replace( 'PASSWORD', $password, $welcome_email );
1619  
1620      /**
1621       * Filters the content of the welcome email after site activation.
1622       *
1623       * Content should be formatted for transmission via wp_mail().
1624       *
1625       * @since MU (3.0.0)
1626       *
1627       * @param string $welcome_email Message body of the email.
1628       * @param int    $blog_id       Blog ID.
1629       * @param int    $user_id       User ID.
1630       * @param string $password      User password.
1631       * @param string $title         Site title.
1632       * @param array  $meta          Signup meta data. By default, contains the requested privacy setting and lang_id.
1633       */
1634      $welcome_email = apply_filters( 'update_welcome_email', $welcome_email, $blog_id, $user_id, $password, $title, $meta );
1635      $admin_email   = get_site_option( 'admin_email' );
1636  
1637      if ( '' == $admin_email ) {
1638          $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
1639      }
1640  
1641      $from_name       = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
1642      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
1643      $message         = $welcome_email;
1644  
1645      if ( empty( $current_network->site_name ) ) {
1646          $current_network->site_name = 'WordPress';
1647      }
1648  
1649      /* translators: New site notification email subject. 1: Network title, 2: New site title. */
1650      $subject = __( 'New %1$s Site: %2$s' );
1651  
1652      /**
1653       * Filters the subject of the welcome email after site activation.
1654       *
1655       * @since MU (3.0.0)
1656       *
1657       * @param string $subject Subject of the email.
1658       */
1659      $subject = apply_filters( 'update_welcome_subject', sprintf( $subject, $current_network->site_name, wp_unslash( $title ) ) );
1660  
1661      wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1662  
1663      if ( $switched_locale ) {
1664          restore_previous_locale();
1665      }
1666  
1667      return true;
1668  }
1669  
1670  /**
1671   * Notify a user that their account activation has been successful.
1672   *
1673   * Filter {@see 'wpmu_welcome_user_notification'} to disable or bypass.
1674   *
1675   * Filter {@see 'update_welcome_user_email'} and {@see 'update_welcome_user_subject'} to
1676   * modify the content and subject line of the notification email.
1677   *
1678   * @since MU (3.0.0)
1679   *
1680   * @param int    $user_id  User ID.
1681   * @param string $password User password.
1682   * @param array  $meta     Optional. Signup meta data. Default empty array.
1683   * @return bool
1684   */
1685  function wpmu_welcome_user_notification( $user_id, $password, $meta = array() ) {
1686      $current_network = get_network();
1687  
1688      /**
1689       * Filters whether to bypass the welcome email after user activation.
1690       *
1691       * Returning false disables the welcome email.
1692       *
1693       * @since MU (3.0.0)
1694       *
1695       * @param int    $user_id  User ID.
1696       * @param string $password User password.
1697       * @param array  $meta     Signup meta data. Default empty array.
1698       */
1699      if ( ! apply_filters( 'wpmu_welcome_user_notification', $user_id, $password, $meta ) ) {
1700          return false;
1701      }
1702  
1703      $welcome_email = get_site_option( 'welcome_user_email' );
1704  
1705      $user = get_userdata( $user_id );
1706  
1707      $switched_locale = switch_to_locale( get_user_locale( $user ) );
1708  
1709      /**
1710       * Filters the content of the welcome email after user activation.
1711       *
1712       * Content should be formatted for transmission via wp_mail().
1713       *
1714       * @since MU (3.0.0)
1715       *
1716       * @param string $welcome_email The message body of the account activation success email.
1717       * @param int    $user_id       User ID.
1718       * @param string $password      User password.
1719       * @param array  $meta          Signup meta data. Default empty array.
1720       */
1721      $welcome_email = apply_filters( 'update_welcome_user_email', $welcome_email, $user_id, $password, $meta );
1722      $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
1723      $welcome_email = str_replace( 'USERNAME', $user->user_login, $welcome_email );
1724      $welcome_email = str_replace( 'PASSWORD', $password, $welcome_email );
1725      $welcome_email = str_replace( 'LOGINLINK', wp_login_url(), $welcome_email );
1726  
1727      $admin_email = get_site_option( 'admin_email' );
1728  
1729      if ( '' == $admin_email ) {
1730          $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
1731      }
1732  
1733      $from_name       = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
1734      $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
1735      $message         = $welcome_email;
1736  
1737      if ( empty( $current_network->site_name ) ) {
1738          $current_network->site_name = 'WordPress';
1739      }
1740  
1741      /* translators: New user notification email subject. 1: Network title, 2: New user login. */
1742      $subject = __( 'New %1$s User: %2$s' );
1743  
1744      /**
1745       * Filters the subject of the welcome email after user activation.
1746       *
1747       * @since MU (3.0.0)
1748       *
1749       * @param string $subject Subject of the email.
1750       */
1751      $subject = apply_filters( 'update_welcome_user_subject', sprintf( $subject, $current_network->site_name, $user->user_login ) );
1752  
1753      wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
1754  
1755      if ( $switched_locale ) {
1756          restore_previous_locale();
1757      }
1758  
1759      return true;
1760  }
1761  
1762  /**
1763   * Get the current network.
1764   *
1765   * Returns an object containing the 'id', 'domain', 'path', and 'site_name'
1766   * properties of the network being viewed.
1767   *
1768   * @see wpmu_current_site()
1769   *
1770   * @since MU (3.0.0)
1771   *
1772   * @global WP_Network $current_site
1773   *
1774   * @return WP_Network
1775   */
1776  function get_current_site() {
1777      global $current_site;
1778      return $current_site;
1779  }
1780  
1781  /**
1782   * Get a user's most recent post.
1783   *
1784   * Walks through each of a user's blogs to find the post with
1785   * the most recent post_date_gmt.
1786   *
1787   * @since MU (3.0.0)
1788   *
1789   * @global wpdb $wpdb WordPress database abstraction object.
1790   *
1791   * @param int $user_id
1792   * @return array Contains the blog_id, post_id, post_date_gmt, and post_gmt_ts
1793   */
1794  function get_most_recent_post_of_user( $user_id ) {
1795      global $wpdb;
1796  
1797      $user_blogs       = get_blogs_of_user( (int) $user_id );
1798      $most_recent_post = array();
1799  
1800      // Walk through each blog and get the most recent post
1801      // published by $user_id.
1802      foreach ( (array) $user_blogs as $blog ) {
1803          $prefix      = $wpdb->get_blog_prefix( $blog->userblog_id );
1804          $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 );
1805  
1806          // Make sure we found a post.
1807          if ( isset( $recent_post['ID'] ) ) {
1808              $post_gmt_ts = strtotime( $recent_post['post_date_gmt'] );
1809  
1810              /*
1811               * If this is the first post checked
1812               * or if this post is newer than the current recent post,
1813               * make it the new most recent post.
1814               */
1815              if ( ! isset( $most_recent_post['post_gmt_ts'] ) || ( $post_gmt_ts > $most_recent_post['post_gmt_ts'] ) ) {
1816                  $most_recent_post = array(
1817                      'blog_id'       => $blog->userblog_id,
1818                      'post_id'       => $recent_post['ID'],
1819                      'post_date_gmt' => $recent_post['post_date_gmt'],
1820                      'post_gmt_ts'   => $post_gmt_ts,
1821                  );
1822              }
1823          }
1824      }
1825  
1826      return $most_recent_post;
1827  }
1828  
1829  //
1830  // Misc functions.
1831  //
1832  
1833  /**
1834   * Check an array of MIME types against a whitelist.
1835   *
1836   * WordPress ships with a set of allowed upload filetypes,
1837   * which is defined in wp-includes/functions.php in
1838   * get_allowed_mime_types(). This function is used to filter
1839   * that list against the filetype whitelist provided by Multisite
1840   * Super Admins at wp-admin/network/settings.php.
1841   *
1842   * @since MU (3.0.0)
1843   *
1844   * @param array $mimes
1845   * @return array
1846   */
1847  function check_upload_mimes( $mimes ) {
1848      $site_exts  = explode( ' ', get_site_option( 'upload_filetypes', 'jpg jpeg png gif' ) );
1849      $site_mimes = array();
1850      foreach ( $site_exts as $ext ) {
1851          foreach ( $mimes as $ext_pattern => $mime ) {
1852              if ( '' != $ext && false !== strpos( $ext_pattern, $ext ) ) {
1853                  $site_mimes[ $ext_pattern ] = $mime;
1854              }
1855          }
1856      }
1857      return $site_mimes;
1858  }
1859  
1860  /**
1861   * Update a blog's post count.
1862   *
1863   * WordPress MS stores a blog's post count as an option so as
1864   * to avoid extraneous COUNTs when a blog's details are fetched
1865   * with get_site(). This function is called when posts are published
1866   * or unpublished to make sure the count stays current.
1867   *
1868   * @since MU (3.0.0)
1869   *
1870   * @global wpdb $wpdb WordPress database abstraction object.
1871   *
1872   * @param string $deprecated Not used.
1873   */
1874  function update_posts_count( $deprecated = '' ) {
1875      global $wpdb;
1876      update_option( 'post_count', (int) $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish' and post_type = 'post'" ) );
1877  }
1878  
1879  /**
1880   * Logs the user email, IP, and registration date of a new site.
1881   *
1882   * @since MU (3.0.0)
1883   * @since 5.1.0 Parameters now support input from the {@see 'wp_initialize_site'} action.
1884   *
1885   * @global wpdb $wpdb WordPress database abstraction object.
1886   *
1887   * @param WP_Site|int $blog_id The new site's object or ID.
1888   * @param int|array   $user_id User ID, or array of arguments including 'user_id'.
1889   */
1890  function wpmu_log_new_registrations( $blog_id, $user_id ) {
1891      global $wpdb;
1892  
1893      if ( is_object( $blog_id ) ) {
1894          $blog_id = $blog_id->blog_id;
1895      }
1896  
1897      if ( is_array( $user_id ) ) {
1898          $user_id = ! empty( $user_id['user_id'] ) ? $user_id['user_id'] : 0;
1899      }
1900  
1901      $user = get_userdata( (int) $user_id );
1902      if ( $user ) {
1903          $wpdb->insert(
1904              $wpdb->registration_log,
1905              array(
1906                  'email'           => $user->user_email,
1907                  'IP'              => preg_replace( '/[^0-9., ]/', '', wp_unslash( $_SERVER['REMOTE_ADDR'] ) ),
1908                  'blog_id'         => $blog_id,
1909                  'date_registered' => current_time( 'mysql' ),
1910              )
1911          );
1912      }
1913  }
1914  
1915  /**
1916   * Maintains a canonical list of terms by syncing terms created for each blog with the global terms table.
1917   *
1918   * @since 3.0.0
1919   *
1920   * @see term_id_filter
1921   *
1922   * @global wpdb $wpdb WordPress database abstraction object.
1923   * @staticvar int $global_terms_recurse
1924   *
1925   * @param int    $term_id    An ID for a term on the current blog.
1926   * @param string $deprecated Not used.
1927   * @return int An ID from the global terms table mapped from $term_id.
1928   */
1929  function global_terms( $term_id, $deprecated = '' ) {
1930      global $wpdb;
1931      static $global_terms_recurse = null;
1932  
1933      if ( ! global_terms_enabled() ) {
1934          return $term_id;
1935      }
1936  
1937      // Prevent a race condition.
1938      $recurse_start = false;
1939      if ( null === $global_terms_recurse ) {
1940          $recurse_start        = true;
1941          $global_terms_recurse = 1;
1942      } elseif ( 10 < $global_terms_recurse++ ) {
1943          return $term_id;
1944      }
1945  
1946      $term_id = intval( $term_id );
1947      $c       = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->terms WHERE term_id = %d", $term_id ) );
1948  
1949      $global_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM $wpdb->sitecategories WHERE category_nicename = %s", $c->slug ) );
1950      if ( null == $global_id ) {
1951          $used_global_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM $wpdb->sitecategories WHERE cat_ID = %d", $c->term_id ) );
1952          if ( null == $used_global_id ) {
1953              $wpdb->insert(
1954                  $wpdb->sitecategories,
1955                  array(
1956                      'cat_ID'            => $term_id,
1957                      'cat_name'          => $c->name,
1958                      'category_nicename' => $c->slug,
1959                  )
1960              );
1961              $global_id = $wpdb->insert_id;
1962              if ( empty( $global_id ) ) {
1963                  return $term_id;
1964              }
1965          } else {
1966              $max_global_id = $wpdb->get_var( "SELECT MAX(cat_ID) FROM $wpdb->sitecategories" );
1967              $max_local_id  = $wpdb->get_var( "SELECT MAX(term_id) FROM $wpdb->terms" );
1968              $new_global_id = max( $max_global_id, $max_local_id ) + mt_rand( 100, 400 );
1969              $wpdb->insert(
1970                  $wpdb->sitecategories,
1971                  array(
1972                      'cat_ID'            => $new_global_id,
1973                      'cat_name'          => $c->name,
1974                      'category_nicename' => $c->slug,
1975                  )
1976              );
1977              $global_id = $wpdb->insert_id;
1978          }
1979      } elseif ( $global_id != $term_id ) {
1980          $local_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE term_id = %d", $global_id ) );
1981          if ( null != $local_id ) {
1982              global_terms( $local_id );
1983              if ( 10 < $global_terms_recurse ) {
1984                  $global_id = $term_id;
1985              }
1986          }
1987      }
1988  
1989      if ( $global_id != $term_id ) {
1990          if ( get_option( 'default_category' ) == $term_id ) {
1991              update_option( 'default_category', $global_id );
1992          }
1993  
1994          $wpdb->update( $wpdb->terms, array( 'term_id' => $global_id ), array( 'term_id' => $term_id ) );
1995          $wpdb->update( $wpdb->term_taxonomy, array( 'term_id' => $global_id ), array( 'term_id' => $term_id ) );
1996          $wpdb->update( $wpdb->term_taxonomy, array( 'parent' => $global_id ), array( 'parent' => $term_id ) );
1997  
1998          clean_term_cache( $term_id );
1999      }
2000      if ( $recurse_start ) {
2001          $global_terms_recurse = null;
2002      }
2003  
2004      return $global_id;
2005  }
2006  
2007  /**
2008   * Ensure that the current site's domain is listed in the allowed redirect host list.
2009   *
2010   * @see wp_validate_redirect()
2011   * @since MU (3.0.0)
2012   *
2013   * @param array|string $deprecated Not used.
2014   * @return string[] {
2015   *     An array containing the current site's domain.
2016   *
2017   *     @type string $0 The current site's domain.
2018   * }
2019   */
2020  function redirect_this_site( $deprecated = '' ) {
2021      return array( get_network()->domain );
2022  }
2023  
2024  /**
2025   * Check whether an upload is too big.
2026   *
2027   * @since MU (3.0.0)
2028   *
2029   * @blessed
2030   *
2031   * @param array $upload
2032   * @return string|array If the upload is under the size limit, $upload is returned. Otherwise returns an error message.
2033   */
2034  function upload_is_file_too_big( $upload ) {
2035      if ( ! is_array( $upload ) || defined( 'WP_IMPORTING' ) || get_site_option( 'upload_space_check_disabled' ) ) {
2036          return $upload;
2037      }
2038  
2039      if ( strlen( $upload['bits'] ) > ( KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 ) ) ) {
2040          /* translators: %s: Maximum allowed file size in kilobytes. */
2041          return sprintf( __( 'This file is too big. Files must be less than %s KB in size.' ) . '<br />', get_site_option( 'fileupload_maxk', 1500 ) );
2042      }
2043  
2044      return $upload;
2045  }
2046  
2047  /**
2048   * Add a nonce field to the signup page.
2049   *
2050   * @since MU (3.0.0)
2051   */
2052  function signup_nonce_fields() {
2053      $id = mt_rand();
2054      echo "<input type='hidden' name='signup_form_id' value='{$id}' />";
2055      wp_nonce_field( 'signup_form_' . $id, '_signup_form', false );
2056  }
2057  
2058  /**
2059   * Process the signup nonce created in signup_nonce_fields().
2060   *
2061   * @since MU (3.0.0)
2062   *
2063   * @param array $result
2064   * @return array
2065   */
2066  function signup_nonce_check( $result ) {
2067      if ( ! strpos( $_SERVER['PHP_SELF'], 'wp-signup.php' ) ) {
2068          return $result;
2069      }
2070  
2071      if ( ! wp_verify_nonce( $_POST['_signup_form'], 'signup_form_' . $_POST['signup_form_id'] ) ) {
2072          $result['errors']->add( 'invalid_nonce', __( 'Unable to submit this form, please try again.' ) );
2073      }
2074  
2075      return $result;
2076  }
2077  
2078  /**
2079   * Correct 404 redirects when NOBLOGREDIRECT is defined.
2080   *
2081   * @since MU (3.0.0)
2082   */
2083  function maybe_redirect_404() {
2084      if ( is_main_site() && is_404() && defined( 'NOBLOGREDIRECT' ) ) {
2085          /**
2086           * Filters the redirect URL for 404s on the main site.
2087           *
2088           * The filter is only evaluated if the NOBLOGREDIRECT constant is defined.
2089           *
2090           * @since 3.0.0
2091           *
2092           * @param string $no_blog_redirect The redirect URL defined in NOBLOGREDIRECT.
2093           */
2094          $destination = apply_filters( 'blog_redirect_404', NOBLOGREDIRECT );
2095          if ( $destination ) {
2096              if ( '%siteurl%' === $destination ) {
2097                  $destination = network_home_url();
2098              }
2099              wp_redirect( $destination );
2100              exit();
2101          }
2102      }
2103  }
2104  
2105  /**
2106   * Add a new user to a blog by visiting /newbloguser/{key}/.
2107   *
2108   * This will only work when the user's details are saved as an option
2109   * keyed as 'new_user_{key}', where '{key}' is a hash generated for the user to be
2110   * added, as when a user is invited through the regular WP Add User interface.
2111   *
2112   * @since MU (3.0.0)
2113   */
2114  function maybe_add_existing_user_to_blog() {
2115      if ( false === strpos( $_SERVER['REQUEST_URI'], '/newbloguser/' ) ) {
2116          return;
2117      }
2118  
2119      $parts = explode( '/', $_SERVER['REQUEST_URI'] );
2120      $key   = array_pop( $parts );
2121  
2122      if ( '' == $key ) {
2123          $key = array_pop( $parts );
2124      }
2125  
2126      $details = get_option( 'new_user_' . $key );
2127      if ( ! empty( $details ) ) {
2128          delete_option( 'new_user_' . $key );
2129      }
2130  
2131      if ( empty( $details ) || is_wp_error( add_existing_user_to_blog( $details ) ) ) {
2132          wp_die(
2133              sprintf(
2134                  /* translators: %s: Home URL. */
2135                  __( 'An error occurred adding you to this site. Back to the <a href="%s">homepage</a>.' ),
2136                  home_url()
2137              )
2138          );
2139      }
2140  
2141      wp_die(
2142          sprintf(
2143              /* translators: 1: Home URL, 2: Admin URL. */
2144              __( '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.' ),
2145              home_url(),
2146              admin_url()
2147          ),
2148          __( 'WordPress &rsaquo; Success' ),
2149          array( 'response' => 200 )
2150      );
2151  }
2152  
2153  /**
2154   * Add a user to a blog based on details from maybe_add_existing_user_to_blog().
2155   *
2156   * @since MU (3.0.0)
2157   *
2158   * @param array $details User details.
2159   * @return true|WP_Error|void True on success or a WP_Error object if the user doesn't exist
2160   *                            or could not be added. Void if $details array was not provided.
2161   */
2162  function add_existing_user_to_blog( $details = false ) {
2163      if ( is_array( $details ) ) {
2164          $blog_id = get_current_blog_id();
2165          $result  = add_user_to_blog( $blog_id, $details['user_id'], $details['role'] );
2166  
2167          /**
2168           * Fires immediately after an existing user is added to a site.
2169           *
2170           * @since MU (3.0.0)
2171           *
2172           * @param int           $user_id User ID.
2173           * @param true|WP_Error $result  True on success or a WP_Error object if the user doesn't exist
2174           *                               or could not be added.
2175           */
2176          do_action( 'added_existing_user', $details['user_id'], $result );
2177  
2178          return $result;
2179      }
2180  }
2181  
2182  /**
2183   * Adds a newly created user to the appropriate blog
2184   *
2185   * To add a user in general, use add_user_to_blog(). This function
2186   * is specifically hooked into the {@see 'wpmu_activate_user'} action.
2187   *
2188   * @since MU (3.0.0)
2189   * @see add_user_to_blog()
2190   *
2191   * @param int    $user_id  User ID.
2192   * @param string $password User password. Ignored.
2193   * @param array  $meta     Signup meta data.
2194   */
2195  function add_new_user_to_blog( $user_id, $password, $meta ) {
2196      if ( ! empty( $meta['add_to_blog'] ) ) {
2197          $blog_id = $meta['add_to_blog'];
2198          $role    = $meta['new_role'];
2199          remove_user_from_blog( $user_id, get_network()->site_id ); // Remove user from main blog.
2200  
2201          $result = add_user_to_blog( $blog_id, $user_id, $role );
2202  
2203          if ( ! is_wp_error( $result ) ) {
2204              update_user_meta( $user_id, 'primary_blog', $blog_id );
2205          }
2206      }
2207  }
2208  
2209  /**
2210   * Correct From host on outgoing mail to match the site domain
2211   *
2212   * @since MU (3.0.0)
2213   *
2214   * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
2215   */
2216  function fix_phpmailer_messageid( $phpmailer ) {
2217      $phpmailer->Hostname = get_network()->domain;
2218  }
2219  
2220  /**
2221   * Check to see whether a user is marked as a spammer, based on user login.
2222   *
2223   * @since MU (3.0.0)
2224   *
2225   * @param string|WP_User $user Optional. Defaults to current user. WP_User object,
2226   *                             or user login name as a string.
2227   * @return bool
2228   */
2229  function is_user_spammy( $user = null ) {
2230      if ( ! ( $user instanceof WP_User ) ) {
2231          if ( $user ) {
2232              $user = get_user_by( 'login', $user );
2233          } else {
2234              $user = wp_get_current_user();
2235          }
2236      }
2237  
2238      return $user && isset( $user->spam ) && 1 == $user->spam;
2239  }
2240  
2241  /**
2242   * Update this blog's 'public' setting in the global blogs table.
2243   *
2244   * Public blogs have a setting of 1, private blogs are 0.
2245   *
2246   * @since MU (3.0.0)
2247   *
2248   * @param int $old_value
2249   * @param int $value     The new public value
2250   */
2251  function update_blog_public( $old_value, $value ) {
2252      update_blog_status( get_current_blog_id(), 'public', (int) $value );
2253  }
2254  
2255  /**
2256   * Check whether users can self-register, based on Network settings.
2257   *
2258   * @since MU (3.0.0)
2259   *
2260   * @return bool
2261   */
2262  function users_can_register_signup_filter() {
2263      $registration = get_site_option( 'registration' );
2264      return ( 'all' === $registration || 'user' === $registration );
2265  }
2266  
2267  /**
2268   * Ensure that the welcome message is not empty. Currently unused.
2269   *
2270   * @since MU (3.0.0)
2271   *
2272   * @param string $text
2273   * @return string
2274   */
2275  function welcome_user_msg_filter( $text ) {
2276      if ( ! $text ) {
2277          remove_filter( 'site_option_welcome_user_email', 'welcome_user_msg_filter' );
2278  
2279          /* translators: Do not translate USERNAME, PASSWORD, LOGINLINK, SITE_NAME: those are placeholders. */
2280          $text = __(
2281              'Howdy USERNAME,
2282  
2283  Your new account is set up.
2284  
2285  You can log in with the following information:
2286  Username: USERNAME
2287  Password: PASSWORD
2288  LOGINLINK
2289  
2290  Thanks!
2291  
2292  --The Team @ SITE_NAME'
2293          );
2294          update_site_option( 'welcome_user_email', $text );
2295      }
2296      return $text;
2297  }
2298  
2299  /**
2300   * Whether to force SSL on content.
2301   *
2302   * @since 2.8.5
2303   *
2304   * @staticvar bool $forced_content
2305   *
2306   * @param bool $force
2307   * @return bool True if forced, false if not forced.
2308   */
2309  function force_ssl_content( $force = '' ) {
2310      static $forced_content = false;
2311  
2312      if ( '' != $force ) {
2313          $old_forced     = $forced_content;
2314          $forced_content = $force;
2315          return $old_forced;
2316      }
2317  
2318      return $forced_content;
2319  }
2320  
2321  /**
2322   * Formats a URL to use https.
2323   *
2324   * Useful as a filter.
2325   *
2326   * @since 2.8.5
2327   *
2328   * @param string $url URL
2329   * @return string URL with https as the scheme
2330   */
2331  function filter_SSL( $url ) {  // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
2332      if ( ! is_string( $url ) ) {
2333          return get_bloginfo( 'url' ); // Return home blog URL with proper scheme.
2334      }
2335  
2336      if ( force_ssl_content() && is_ssl() ) {
2337          $url = set_url_scheme( $url, 'https' );
2338      }
2339  
2340      return $url;
2341  }
2342  
2343  /**
2344   * Schedule update of the network-wide counts for the current network.
2345   *
2346   * @since 3.1.0
2347   */
2348  function wp_schedule_update_network_counts() {
2349      if ( ! is_main_site() ) {
2350          return;
2351      }
2352  
2353      if ( ! wp_next_scheduled( 'update_network_counts' ) && ! wp_installing() ) {
2354          wp_schedule_event( time(), 'twicedaily', 'update_network_counts' );
2355      }
2356  }
2357  
2358  /**
2359   * Update the network-wide counts for the current network.
2360   *
2361   * @since 3.1.0
2362   * @since 4.8.0 The `$network_id` parameter has been added.
2363   *
2364   * @param int|null $network_id ID of the network. Default is the current network.
2365   */
2366  function wp_update_network_counts( $network_id = null ) {
2367      wp_update_network_user_counts( $network_id );
2368      wp_update_network_site_counts( $network_id );
2369  }
2370  
2371  /**
2372   * Update the count of sites for the current network.
2373   *
2374   * If enabled through the {@see 'enable_live_network_counts'} filter, update the sites count
2375   * on a network when a site is created or its status is updated.
2376   *
2377   * @since 3.7.0
2378   * @since 4.8.0 The `$network_id` parameter has been added.
2379   *
2380   * @param int|null $network_id ID of the network. Default is the current network.
2381   */
2382  function wp_maybe_update_network_site_counts( $network_id = null ) {
2383      $is_small_network = ! wp_is_large_network( 'sites', $network_id );
2384  
2385      /**
2386       * Filters whether to update network site or user counts when a new site is created.
2387       *
2388       * @since 3.7.0
2389       *
2390       * @see wp_is_large_network()
2391       *
2392       * @param bool   $small_network Whether the network is considered small.
2393       * @param string $context       Context. Either 'users' or 'sites'.
2394       */
2395      if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'sites' ) ) {
2396          return;
2397      }
2398  
2399      wp_update_network_site_counts( $network_id );
2400  }
2401  
2402  /**
2403   * Update the network-wide users count.
2404   *
2405   * If enabled through the {@see 'enable_live_network_counts'} filter, update the users count
2406   * on a network when a user is created or its status is updated.
2407   *
2408   * @since 3.7.0
2409   * @since 4.8.0 The `$network_id` parameter has been added.
2410   *
2411   * @param int|null $network_id ID of the network. Default is the current network.
2412   */
2413  function wp_maybe_update_network_user_counts( $network_id = null ) {
2414      $is_small_network = ! wp_is_large_network( 'users', $network_id );
2415  
2416      /** This filter is documented in wp-includes/ms-functions.php */
2417      if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'users' ) ) {
2418          return;
2419      }
2420  
2421      wp_update_network_user_counts( $network_id );
2422  }
2423  
2424  /**
2425   * Update the network-wide site count.
2426   *
2427   * @since 3.7.0
2428   * @since 4.8.0 The `$network_id` parameter has been added.
2429   *
2430   * @param int|null $network_id ID of the network. Default is the current network.
2431   */
2432  function wp_update_network_site_counts( $network_id = null ) {
2433      $network_id = (int) $network_id;
2434      if ( ! $network_id ) {
2435          $network_id = get_current_network_id();
2436      }
2437  
2438      $count = get_sites(
2439          array(
2440              'network_id'             => $network_id,
2441              'spam'                   => 0,
2442              'deleted'                => 0,
2443              'archived'               => 0,
2444              'count'                  => true,
2445              'update_site_meta_cache' => false,
2446          )
2447      );
2448  
2449      update_network_option( $network_id, 'blog_count', $count );
2450  }
2451  
2452  /**
2453   * Update the network-wide user count.
2454   *
2455   * @since 3.7.0
2456   * @since 4.8.0 The `$network_id` parameter has been added.
2457   *
2458   * @global wpdb $wpdb WordPress database abstraction object.
2459   *
2460   * @param int|null $network_id ID of the network. Default is the current network.
2461   */
2462  function wp_update_network_user_counts( $network_id = null ) {
2463      global $wpdb;
2464  
2465      $count = $wpdb->get_var( "SELECT COUNT(ID) as c FROM $wpdb->users WHERE spam = '0' AND deleted = '0'" );
2466      update_network_option( $network_id, 'user_count', $count );
2467  }
2468  
2469  /**
2470   * Returns the space used by the current site.
2471   *
2472   * @since 3.5.0
2473   *
2474   * @return int Used space in megabytes.
2475   */
2476  function get_space_used() {
2477      /**
2478       * Filters the amount of storage space used by the current site, in megabytes.
2479       *
2480       * @since 3.5.0
2481       *
2482       * @param int|false $space_used The amount of used space, in megabytes. Default false.
2483       */
2484      $space_used = apply_filters( 'pre_get_space_used', false );
2485      if ( false === $space_used ) {
2486          $upload_dir = wp_upload_dir();
2487          $space_used = get_dirsize( $upload_dir['basedir'] ) / MB_IN_BYTES;
2488      }
2489  
2490      return $space_used;
2491  }
2492  
2493  /**
2494   * Returns the upload quota for the current blog.
2495   *
2496   * @since MU (3.0.0)
2497   *
2498   * @return int Quota in megabytes
2499   */
2500  function get_space_allowed() {
2501      $space_allowed = get_option( 'blog_upload_space' );
2502  
2503      if ( ! is_numeric( $space_allowed ) ) {
2504          $space_allowed = get_site_option( 'blog_upload_space' );
2505      }
2506  
2507      if ( ! is_numeric( $space_allowed ) ) {
2508          $space_allowed = 100;
2509      }
2510  
2511      /**
2512       * Filters the upload quota for the current site.
2513       *
2514       * @since 3.7.0
2515       *
2516       * @param int $space_allowed Upload quota in megabytes for the current blog.
2517       */
2518      return apply_filters( 'get_space_allowed', $space_allowed );
2519  }
2520  
2521  /**
2522   * Determines if there is any upload space left in the current blog's quota.
2523   *
2524   * @since 3.0.0
2525   *
2526   * @return int of upload space available in bytes
2527   */
2528  function get_upload_space_available() {
2529      $allowed = get_space_allowed();
2530      if ( $allowed < 0 ) {
2531          $allowed = 0;
2532      }
2533      $space_allowed = $allowed * MB_IN_BYTES;
2534      if ( get_site_option( 'upload_space_check_disabled' ) ) {
2535          return $space_allowed;
2536      }
2537  
2538      $space_used = get_space_used() * MB_IN_BYTES;
2539  
2540      if ( ( $space_allowed - $space_used ) <= 0 ) {
2541          return 0;
2542      }
2543  
2544      return $space_allowed - $space_used;
2545  }
2546  
2547  /**
2548   * Determines if there is any upload space left in the current blog's quota.
2549   *
2550   * @since 3.0.0
2551   * @return bool True if space is available, false otherwise.
2552   */
2553  function is_upload_space_available() {
2554      if ( get_site_option( 'upload_space_check_disabled' ) ) {
2555          return true;
2556      }
2557  
2558      return (bool) get_upload_space_available();
2559  }
2560  
2561  /**
2562   * Filters the maximum upload file size allowed, in bytes.
2563   *
2564   * @since 3.0.0
2565   *
2566   * @param  int $size Upload size limit in bytes.
2567   * @return int       Upload size limit in bytes.
2568   */
2569  function upload_size_limit_filter( $size ) {
2570      $fileupload_maxk = KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 );
2571      if ( get_site_option( 'upload_space_check_disabled' ) ) {
2572          return min( $size, $fileupload_maxk );
2573      }
2574  
2575      return min( $size, $fileupload_maxk, get_upload_space_available() );
2576  }
2577  
2578  /**
2579   * Whether or not we have a large network.
2580   *
2581   * The default criteria for a large network is either more than 10,000 users or more than 10,000 sites.
2582   * Plugins can alter this criteria using the {@see 'wp_is_large_network'} filter.
2583   *
2584   * @since 3.3.0
2585   * @since 4.8.0 The `$network_id` parameter has been added.
2586   *
2587   * @param string   $using      'sites or 'users'. Default is 'sites'.
2588   * @param int|null $network_id ID of the network. Default is the current network.
2589   * @return bool True if the network meets the criteria for large. False otherwise.
2590   */
2591  function wp_is_large_network( $using = 'sites', $network_id = null ) {
2592      $network_id = (int) $network_id;
2593      if ( ! $network_id ) {
2594          $network_id = get_current_network_id();
2595      }
2596  
2597      if ( 'users' == $using ) {
2598          $count = get_user_count( $network_id );
2599          /**
2600           * Filters whether the network is considered large.
2601           *
2602           * @since 3.3.0
2603           * @since 4.8.0 The `$network_id` parameter has been added.
2604           *
2605           * @param bool   $is_large_network Whether the network has more than 10000 users or sites.
2606           * @param string $component        The component to count. Accepts 'users', or 'sites'.
2607           * @param int    $count            The count of items for the component.
2608           * @param int    $network_id       The ID of the network being checked.
2609           */
2610          return apply_filters( 'wp_is_large_network', $count > 10000, 'users', $count, $network_id );
2611      }
2612  
2613      $count = get_blog_count( $network_id );
2614      /** This filter is documented in wp-includes/ms-functions.php */
2615      return apply_filters( 'wp_is_large_network', $count > 10000, 'sites', $count, $network_id );
2616  }
2617  
2618  /**
2619   * Retrieves a list of reserved site on a sub-directory Multisite installation.
2620   *
2621   * @since 4.4.0
2622   *
2623   * @return string[] Array of reserved names.
2624   */
2625  function get_subdirectory_reserved_names() {
2626      $names = array(
2627          'page',
2628          'comments',
2629          'blog',
2630          'files',
2631          'feed',
2632          'wp-admin',
2633          'wp-content',
2634          'wp-includes',
2635          'wp-json',
2636          'embed',
2637      );
2638  
2639      /**
2640       * Filters reserved site names on a sub-directory Multisite installation.
2641       *
2642       * @since 3.0.0
2643       * @since 4.4.0 'wp-admin', 'wp-content', 'wp-includes', 'wp-json', and 'embed' were added
2644       *              to the reserved names list.
2645       *
2646       * @param string[] $subdirectory_reserved_names Array of reserved names.
2647       */
2648      return apply_filters( 'subdirectory_reserved_names', $names );
2649  }
2650  
2651  /**
2652   * Send a confirmation request email when a change of network admin email address is attempted.
2653   *
2654   * The new network admin address will not become active until confirmed.
2655   *
2656   * @since 4.9.0
2657   *
2658   * @param string $old_value The old network admin email address.
2659   * @param string $value     The proposed new network admin email address.
2660   */
2661  function update_network_option_new_admin_email( $old_value, $value ) {
2662      if ( get_site_option( 'admin_email' ) === $value || ! is_email( $value ) ) {
2663          return;
2664      }
2665  
2666      $hash            = md5( $value . time() . mt_rand() );
2667      $new_admin_email = array(
2668          'hash'     => $hash,
2669          'newemail' => $value,
2670      );
2671      update_site_option( 'network_admin_hash', $new_admin_email );
2672  
2673      $switched_locale = switch_to_locale( get_user_locale() );
2674  
2675      /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
2676      $email_text = __(
2677          'Howdy ###USERNAME###,
2678  
2679  You recently requested to have the network admin email address on
2680  your network changed.
2681  
2682  If this is correct, please click on the following link to change it:
2683  ###ADMIN_URL###
2684  
2685  You can safely ignore and delete this email if you do not want to
2686  take this action.
2687  
2688  This email has been sent to ###EMAIL###
2689  
2690  Regards,
2691  All at ###SITENAME###
2692  ###SITEURL###'
2693      );
2694  
2695      /**
2696       * Filters the text of the email sent when a change of network admin email address is attempted.
2697       *
2698       * The following strings have a special meaning and will get replaced dynamically:
2699       * ###USERNAME###  The current user's username.
2700       * ###ADMIN_URL### The link to click on to confirm the email change.
2701       * ###EMAIL###     The proposed new network admin email address.
2702       * ###SITENAME###  The name of the network.
2703       * ###SITEURL###   The URL to the network.
2704       *
2705       * @since 4.9.0
2706       *
2707       * @param string $email_text      Text in the email.
2708       * @param array  $new_admin_email {
2709       *     Data relating to the new network admin email address.
2710       *
2711       *     @type string $hash     The secure hash used in the confirmation link URL.
2712       *     @type string $newemail The proposed new network admin email address.
2713       * }
2714       */
2715      $content = apply_filters( 'new_network_admin_email_content', $email_text, $new_admin_email );
2716  
2717      $current_user = wp_get_current_user();
2718      $content      = str_replace( '###USERNAME###', $current_user->user_login, $content );
2719      $content      = str_replace( '###ADMIN_URL###', esc_url( network_admin_url( 'settings.php?network_admin_hash=' . $hash ) ), $content );
2720      $content      = str_replace( '###EMAIL###', $value, $content );
2721      $content      = str_replace( '###SITENAME###', wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES ), $content );
2722      $content      = str_replace( '###SITEURL###', network_home_url(), $content );
2723  
2724      wp_mail(
2725          $value,
2726          sprintf(
2727              /* translators: Email change notification email subject. %s: Network title. */
2728              __( '[%s] Network Admin Email Change Request' ),
2729              wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES )
2730          ),
2731          $content
2732      );
2733  
2734      if ( $switched_locale ) {
2735          restore_previous_locale();
2736      }
2737  }
2738  
2739  /**
2740   * Send an email to the old network admin email address when the network admin email address changes.
2741   *
2742   * @since 4.9.0
2743   *
2744   * @param string $option_name The relevant database option name.
2745   * @param string $new_email   The new network admin email address.
2746   * @param string $old_email   The old network admin email address.
2747   * @param int    $network_id  ID of the network.
2748   */
2749  function wp_network_admin_email_change_notification( $option_name, $new_email, $old_email, $network_id ) {
2750      $send = true;
2751  
2752      // Don't send the notification to the default 'admin_email' value.
2753      if ( 'you@example.com' === $old_email ) {
2754          $send = false;
2755      }
2756  
2757      /**
2758       * Filters whether to send the network admin email change notification email.
2759       *
2760       * @since 4.9.0
2761       *
2762       * @param bool   $send       Whether to send the email notification.
2763       * @param string $old_email  The old network admin email address.
2764       * @param string $new_email  The new network admin email address.
2765       * @param int    $network_id ID of the network.
2766       */
2767      $send = apply_filters( 'send_network_admin_email_change_email', $send, $old_email, $new_email, $network_id );
2768  
2769      if ( ! $send ) {
2770          return;
2771      }
2772  
2773      /* translators: Do not translate OLD_EMAIL, NEW_EMAIL, SITENAME, SITEURL: those are placeholders. */
2774      $email_change_text = __(
2775          'Hi,
2776  
2777  This notice confirms that the network admin email address was changed on ###SITENAME###.
2778  
2779  The new network admin email address is ###NEW_EMAIL###.
2780  
2781  This email has been sent to ###OLD_EMAIL###
2782  
2783  Regards,
2784  All at ###SITENAME###
2785  ###SITEURL###'
2786      );
2787  
2788      $email_change_email = array(
2789          'to'      => $old_email,
2790          /* translators: Network admin email change notification email subject. %s: Network title. */
2791          'subject' => __( '[%s] Network Admin Email Changed' ),
2792          'message' => $email_change_text,
2793          'headers' => '',
2794      );
2795      // Get network name.
2796      $network_name = wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES );
2797  
2798      /**
2799       * Filters the contents of the email notification sent when the network admin email address is changed.
2800       *
2801       * @since 4.9.0
2802       *
2803       * @param array $email_change_email {
2804       *            Used to build wp_mail().
2805       *
2806       *            @type string $to      The intended recipient.
2807       *            @type string $subject The subject of the email.
2808       *            @type string $message The content of the email.
2809       *                The following strings have a special meaning and will get replaced dynamically:
2810       *                - ###OLD_EMAIL### The old network admin email address.
2811       *                - ###NEW_EMAIL### The new network admin email address.
2812       *                - ###SITENAME###  The name of the network.
2813       *                - ###SITEURL###   The URL to the site.
2814       *            @type string $headers Headers.
2815       *        }
2816       * @param string $old_email  The old network admin email address.
2817       * @param string $new_email  The new network admin email address.
2818       * @param int    $network_id ID of the network.
2819       */
2820      $email_change_email = apply_filters( 'network_admin_email_change_email', $email_change_email, $old_email, $new_email, $network_id );
2821  
2822      $email_change_email['message'] = str_replace( '###OLD_EMAIL###', $old_email, $email_change_email['message'] );
2823      $email_change_email['message'] = str_replace( '###NEW_EMAIL###', $new_email, $email_change_email['message'] );
2824      $email_change_email['message'] = str_replace( '###SITENAME###', $network_name, $email_change_email['message'] );
2825      $email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] );
2826  
2827      wp_mail(
2828          $email_change_email['to'],
2829          sprintf(
2830              $email_change_email['subject'],
2831              $network_name
2832          ),
2833          $email_change_email['message'],
2834          $email_change_email['headers']
2835      );
2836  }


Generated : Thu Apr 9 08:20:01 2020 Cross-referenced by PHPXref