[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Sun Jan 16 01:00:03 2022 Cross-referenced by PHPXref 0.7.1