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