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