PageRenderTime 86ms CodeModel.GetById 11ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-includes/ms-functions.php

https://bitbucket.org/skyarch-iijima/wordpress
PHP | 2744 lines | 1117 code | 329 blank | 1298 comment | 260 complexity | 347598ec1d6512d32f1916404c32653a MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 */
  17function 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 */
  40function 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 */
 105function 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 */
 121function 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 */
 134function 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 */
 154function 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 */
 229function 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 */
 307function 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 */
 331function 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 */
 375function 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 */
 436function 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 */
 572function 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 */
 706function 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 */
 769function 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 */
 840function 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 */
 954function 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 */
1042function 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 */
1136function 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 */
1185function 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 */
1264function 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
1281URL: %2$s
1282Remote IP address: %3$s
1283
1284Disable 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 */
1310function 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
1324Remote IP address: %2$s
1325
1326Disable 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 */
1358function 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 */
1401function 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 */
1434function install_blog( $blog_id, $bl…

Large files files are truncated, but you can click here to view the full file