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