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