[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Thu Apr 25 01:00:03 2024 Cross-referenced by PHPXref 0.7.1