home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / ms-functions.php < prev    next >
Encoding:
PHP Script  |  2018-01-23  |  89.0 KB  |  2,745 lines

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