]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-admin/includes/ms.php
WordPress 4.4
[autoinstalls/wordpress.git] / wp-admin / includes / ms.php
1 <?php
2 /**
3  * Multisite administration functions.
4  *
5  * @package WordPress
6  * @subpackage Multisite
7  * @since 3.0.0
8  */
9
10 /**
11  * Determine if uploaded file exceeds space quota.
12  *
13  * @since 3.0.0
14  *
15  * @param array $file $_FILES array for a given file.
16  * @return array $_FILES array with 'error' key set if file exceeds quota. 'error' is empty otherwise.
17  */
18 function check_upload_size( $file ) {
19         if ( get_site_option( 'upload_space_check_disabled' ) )
20                 return $file;
21
22         if ( $file['error'] != '0' ) // there's already an error
23                 return $file;
24
25         if ( defined( 'WP_IMPORTING' ) )
26                 return $file;
27
28         $space_left = get_upload_space_available();
29
30         $file_size = filesize( $file['tmp_name'] );
31         if ( $space_left < $file_size ) {
32                 $file['error'] = sprintf( __( 'Not enough space to upload. %1$s KB needed.' ), number_format( ( $file_size - $space_left ) / KB_IN_BYTES ) );
33         }
34
35         if ( $file_size > ( KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 ) ) ) {
36                 $file['error'] = sprintf( __( 'This file is too big. Files must be less than %1$s KB in size.' ), get_site_option( 'fileupload_maxk', 1500 ) );
37         }
38
39         if ( upload_is_user_over_quota( false ) ) {
40                 $file['error'] = __( 'You have used your space quota. Please delete files before uploading.' );
41         }
42
43         if ( $file['error'] != '0' && ! isset( $_POST['html-upload'] ) && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
44                 wp_die( $file['error'] . ' <a href="javascript:history.go(-1)">' . __( 'Back' ) . '</a>' );
45         }
46
47         return $file;
48 }
49
50 /**
51  * Delete a blog.
52  *
53  * @since 3.0.0
54  *
55  * @global wpdb $wpdb WordPress database abstraction object.
56  *
57  * @param int  $blog_id Blog ID.
58  * @param bool $drop    True if blog's table should be dropped. Default is false.
59  */
60 function wpmu_delete_blog( $blog_id, $drop = false ) {
61         global $wpdb;
62
63         $switch = false;
64         if ( get_current_blog_id() != $blog_id ) {
65                 $switch = true;
66                 switch_to_blog( $blog_id );
67         }
68
69         $blog = get_blog_details( $blog_id );
70         /**
71          * Fires before a blog is deleted.
72          *
73          * @since MU
74          *
75          * @param int  $blog_id The blog ID.
76          * @param bool $drop    True if blog's table should be dropped. Default is false.
77          */
78         do_action( 'delete_blog', $blog_id, $drop );
79
80         $users = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ids' ) );
81
82         // Remove users from this blog.
83         if ( ! empty( $users ) ) {
84                 foreach ( $users as $user_id ) {
85                         remove_user_from_blog( $user_id, $blog_id );
86                 }
87         }
88
89         update_blog_status( $blog_id, 'deleted', 1 );
90
91         $current_site = get_current_site();
92
93         // If a full blog object is not available, do not destroy anything.
94         if ( $drop && ! $blog ) {
95                 $drop = false;
96         }
97
98         // Don't destroy the initial, main, or root blog.
99         if ( $drop && ( 1 == $blog_id || is_main_site( $blog_id ) || ( $blog->path == $current_site->path && $blog->domain == $current_site->domain ) ) ) {
100                 $drop = false;
101         }
102
103         $upload_path = trim( get_option( 'upload_path' ) );
104
105         // If ms_files_rewriting is enabled and upload_path is empty, wp_upload_dir is not reliable.
106         if ( $drop && get_site_option( 'ms_files_rewriting' ) && empty( $upload_path ) ) {
107                 $drop = false;
108         }
109
110         if ( $drop ) {
111                 $uploads = wp_upload_dir();
112
113                 $tables = $wpdb->tables( 'blog' );
114                 /**
115                  * Filter the tables to drop when the blog is deleted.
116                  *
117                  * @since MU
118                  *
119                  * @param array $tables  The blog tables to be dropped.
120                  * @param int   $blog_id The ID of the blog to drop tables for.
121                  */
122                 $drop_tables = apply_filters( 'wpmu_drop_tables', $tables, $blog_id );
123
124                 foreach ( (array) $drop_tables as $table ) {
125                         $wpdb->query( "DROP TABLE IF EXISTS `$table`" );
126                 }
127
128                 $wpdb->delete( $wpdb->blogs, array( 'blog_id' => $blog_id ) );
129
130                 /**
131                  * Filter the upload base directory to delete when the blog is deleted.
132                  *
133                  * @since MU
134                  *
135                  * @param string $uploads['basedir'] Uploads path without subdirectory. @see wp_upload_dir()
136                  * @param int    $blog_id            The blog ID.
137                  */
138                 $dir = apply_filters( 'wpmu_delete_blog_upload_dir', $uploads['basedir'], $blog_id );
139                 $dir = rtrim( $dir, DIRECTORY_SEPARATOR );
140                 $top_dir = $dir;
141                 $stack = array($dir);
142                 $index = 0;
143
144                 while ( $index < count( $stack ) ) {
145                         // Get indexed directory from stack
146                         $dir = $stack[$index];
147
148                         $dh = @opendir( $dir );
149                         if ( $dh ) {
150                                 while ( ( $file = @readdir( $dh ) ) !== false ) {
151                                         if ( $file == '.' || $file == '..' )
152                                                 continue;
153
154                                         if ( @is_dir( $dir . DIRECTORY_SEPARATOR . $file ) ) {
155                                                 $stack[] = $dir . DIRECTORY_SEPARATOR . $file;
156                                         } elseif ( @is_file( $dir . DIRECTORY_SEPARATOR . $file ) ) {
157                                                 @unlink( $dir . DIRECTORY_SEPARATOR . $file );
158                                         }
159                                 }
160                                 @closedir( $dh );
161                         }
162                         $index++;
163                 }
164
165                 $stack = array_reverse( $stack ); // Last added dirs are deepest
166                 foreach ( (array) $stack as $dir ) {
167                         if ( $dir != $top_dir)
168                         @rmdir( $dir );
169                 }
170
171                 clean_blog_cache( $blog );
172         }
173
174         if ( $switch )
175                 restore_current_blog();
176 }
177
178 /**
179  * Delete a user from the network and remove from all sites.
180  *
181  * @since 3.0.0
182  *
183  * @todo Merge with wp_delete_user() ?
184  *
185  * @global wpdb $wpdb WordPress database abstraction object.
186  *
187  * @param int $id The user ID.
188  * @return bool True if the user was deleted, otherwise false.
189  */
190 function wpmu_delete_user( $id ) {
191         global $wpdb;
192
193         if ( ! is_numeric( $id ) ) {
194                 return false;
195         }
196
197         $id = (int) $id;
198         $user = new WP_User( $id );
199
200         if ( !$user->exists() )
201                 return false;
202
203         // Global super-administrators are protected, and cannot be deleted.
204         $_super_admins = get_super_admins();
205         if ( in_array( $user->user_login, $_super_admins, true ) ) {
206                 return false;
207         }
208
209         /**
210          * Fires before a user is deleted from the network.
211          *
212          * @since MU
213          *
214          * @param int $id ID of the user about to be deleted from the network.
215          */
216         do_action( 'wpmu_delete_user', $id );
217
218         $blogs = get_blogs_of_user( $id );
219
220         if ( ! empty( $blogs ) ) {
221                 foreach ( $blogs as $blog ) {
222                         switch_to_blog( $blog->userblog_id );
223                         remove_user_from_blog( $id, $blog->userblog_id );
224
225                         $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
226                         foreach ( (array) $post_ids as $post_id ) {
227                                 wp_delete_post( $post_id );
228                         }
229
230                         // Clean links
231                         $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) );
232
233                         if ( $link_ids ) {
234                                 foreach ( $link_ids as $link_id )
235                                         wp_delete_link( $link_id );
236                         }
237
238                         restore_current_blog();
239                 }
240         }
241
242         $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
243         foreach ( $meta as $mid )
244                 delete_metadata_by_mid( 'user', $mid );
245
246         $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
247
248         clean_user_cache( $user );
249
250         /** This action is documented in wp-admin/includes/user.php */
251         do_action( 'deleted_user', $id );
252
253         return true;
254 }
255
256 /**
257  * Sends an email when a site administrator email address is changed.
258  *
259  * @since 3.0.0
260  *
261  * @param string $old_value The old email address. Not currently used.
262  * @param string $value     The new email address.
263  */
264 function update_option_new_admin_email( $old_value, $value ) {
265         if ( $value == get_option( 'admin_email' ) || !is_email( $value ) )
266                 return;
267
268         $hash = md5( $value. time() .mt_rand() );
269         $new_admin_email = array(
270                 'hash' => $hash,
271                 'newemail' => $value
272         );
273         update_option( 'adminhash', $new_admin_email );
274
275         /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
276         $email_text = __( 'Howdy ###USERNAME###,
277
278 You recently requested to have the administration email address on
279 your site changed.
280
281 If this is correct, please click on the following link to change it:
282 ###ADMIN_URL###
283
284 You can safely ignore and delete this email if you do not want to
285 take this action.
286
287 This email has been sent to ###EMAIL###
288
289 Regards,
290 All at ###SITENAME###
291 ###SITEURL###' );
292
293         /**
294          * Filter the email text sent when the site admin email is changed.
295          *
296          * The following strings have a special meaning and will get replaced dynamically:
297          * ###USERNAME###  The current user's username.
298          * ###ADMIN_URL### The link to click on to confirm the email change.
299          * ###EMAIL###     The new email.
300          * ###SITENAME###  The name of the site.
301          * ###SITEURL###   The URL to the site.
302          *
303          * @since MU
304          *
305          * @param string $email_text      Text in the email.
306          * @param string $new_admin_email New admin email that the current administration email was changed to.
307          */
308         $content = apply_filters( 'new_admin_email_content', $email_text, $new_admin_email );
309
310         $current_user = wp_get_current_user();
311         $content = str_replace( '###USERNAME###', $current_user->user_login, $content );
312         $content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'options.php?adminhash='.$hash ) ), $content );
313         $content = str_replace( '###EMAIL###', $value, $content );
314         $content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
315         $content = str_replace( '###SITEURL###', network_home_url(), $content );
316
317         wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
318 }
319
320 /**
321  * Sends an email when an email address change is requested.
322  *
323  * @since 3.0.0
324  *
325  * @global WP_Error $errors WP_Error object.
326  * @global wpdb     $wpdb   WordPress database object.
327  */
328 function send_confirmation_on_profile_email() {
329         global $errors, $wpdb;
330         $current_user = wp_get_current_user();
331         if ( ! is_object($errors) )
332                 $errors = new WP_Error();
333
334         if ( $current_user->ID != $_POST['user_id'] )
335                 return false;
336
337         if ( $current_user->user_email != $_POST['email'] ) {
338                 if ( !is_email( $_POST['email'] ) ) {
339                         $errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address isn&#8217;t correct." ), array( 'form-field' => 'email' ) );
340                         return;
341                 }
342
343                 if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_email FROM {$wpdb->users} WHERE user_email=%s", $_POST['email'] ) ) ) {
344                         $errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address is already used." ), array( 'form-field' => 'email' ) );
345                         delete_option( $current_user->ID . '_new_email' );
346                         return;
347                 }
348
349                 $hash = md5( $_POST['email'] . time() . mt_rand() );
350                 $new_user_email = array(
351                                 'hash' => $hash,
352                                 'newemail' => $_POST['email']
353                                 );
354                 update_option( $current_user->ID . '_new_email', $new_user_email );
355
356                 /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
357                 $email_text = __( 'Howdy ###USERNAME###,
358
359 You recently requested to have the email address on your account changed.
360
361 If this is correct, please click on the following link to change it:
362 ###ADMIN_URL###
363
364 You can safely ignore and delete this email if you do not want to
365 take this action.
366
367 This email has been sent to ###EMAIL###
368
369 Regards,
370 All at ###SITENAME###
371 ###SITEURL###' );
372
373                 /**
374                  * Filter the email text sent when a user changes emails.
375                  *
376                  * The following strings have a special meaning and will get replaced dynamically:
377                  * ###USERNAME###  The current user's username.
378                  * ###ADMIN_URL### The link to click on to confirm the email change.
379                  * ###EMAIL###     The new email.
380                  * ###SITENAME###  The name of the site.
381                  * ###SITEURL###   The URL to the site.
382                  *
383                  * @since MU
384                  *
385                  * @param string $email_text     Text in the email.
386                  * @param string $new_user_email New user email that the current user has changed to.
387                  */
388                 $content = apply_filters( 'new_user_email_content', $email_text, $new_user_email );
389
390                 $content = str_replace( '###USERNAME###', $current_user->user_login, $content );
391                 $content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail='.$hash ) ), $content );
392                 $content = str_replace( '###EMAIL###', $_POST['email'], $content);
393                 $content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
394                 $content = str_replace( '###SITEURL###', network_home_url(), $content );
395
396                 wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
397                 $_POST['email'] = $current_user->user_email;
398         }
399 }
400
401 /**
402  * Adds an admin notice alerting the user to check for confirmation email
403  * after email address change.
404  *
405  * @since 3.0.0
406  */
407 function new_user_email_admin_notice() {
408         if ( strpos( $_SERVER['PHP_SELF'], 'profile.php' ) && isset( $_GET['updated'] ) && $email = get_option( get_current_user_id() . '_new_email' ) )
409                 echo "<div class='update-nag'>" . sprintf( __( "Your email address has not been updated yet. Please check your inbox at %s for a confirmation email." ), $email['newemail'] ) . "</div>";
410 }
411
412 /**
413  * Check whether a blog has used its allotted upload space.
414  *
415  * @since MU
416  *
417  * @param bool $echo Optional. If $echo is set and the quota is exceeded, a warning message is echoed. Default is true.
418  * @return bool True if user is over upload space quota, otherwise false.
419  */
420 function upload_is_user_over_quota( $echo = true ) {
421         if ( get_site_option( 'upload_space_check_disabled' ) )
422                 return false;
423
424         $space_allowed = get_space_allowed();
425         if ( ! is_numeric( $space_allowed ) ) {
426                 $space_allowed = 10; // Default space allowed is 10 MB
427         }
428         $space_used = get_space_used();
429
430         if ( ( $space_allowed - $space_used ) < 0 ) {
431                 if ( $echo )
432                         _e( 'Sorry, you have used your space allocation. Please delete some files to upload more files.' );
433                 return true;
434         } else {
435                 return false;
436         }
437 }
438
439 /**
440  * Displays the amount of disk space used by the current blog. Not used in core.
441  *
442  * @since MU
443  */
444 function display_space_usage() {
445         $space_allowed = get_space_allowed();
446         $space_used = get_space_used();
447
448         $percent_used = ( $space_used / $space_allowed ) * 100;
449
450         if ( $space_allowed > 1000 ) {
451                 $space = number_format( $space_allowed / KB_IN_BYTES );
452                 /* translators: Gigabytes */
453                 $space .= __( 'GB' );
454         } else {
455                 $space = number_format( $space_allowed );
456                 /* translators: Megabytes */
457                 $space .= __( 'MB' );
458         }
459         ?>
460         <strong><?php printf( __( 'Used: %1$s%% of %2$s' ), number_format( $percent_used ), $space ); ?></strong>
461         <?php
462 }
463
464 /**
465  * Get the remaining upload space for this blog.
466  *
467  * @since MU
468  *
469  * @param int $size Current max size in bytes
470  * @return int Max size in bytes
471  */
472 function fix_import_form_size( $size ) {
473         if ( upload_is_user_over_quota( false ) ) {
474                 return 0;
475         }
476         $available = get_upload_space_available();
477         return min( $size, $available );
478 }
479
480 /**
481  * Displays the edit blog upload space setting form on the Edit Blog screen.
482  *
483  * @since 3.0.0
484  *
485  * @param int $id The ID of the blog to display the setting for.
486  */
487 function upload_space_setting( $id ) {
488         switch_to_blog( $id );
489         $quota = get_option( 'blog_upload_space' );
490         restore_current_blog();
491
492         if ( !$quota )
493                 $quota = '';
494
495         ?>
496         <tr>
497                 <th><label for="blog-upload-space-number"><?php _e( 'Site Upload Space Quota' ); ?></label></th>
498                 <td>
499                         <input type="number" step="1" min="0" style="width: 100px" name="option[blog_upload_space]" id="blog-upload-space-number" aria-describedby="blog-upload-space-desc" value="<?php echo $quota; ?>" />
500                         <span id="blog-upload-space-desc"><span class="screen-reader-text"><?php _e( 'Size in megabytes' ); ?></span> <?php _e( 'MB (Leave blank for network default)' ); ?></span>
501                 </td>
502         </tr>
503         <?php
504 }
505
506 /**
507  * Update the status of a user in the database.
508  *
509  * Used in core to mark a user as spam or "ham" (not spam) in Multisite.
510  *
511  * @since 3.0.0
512  *
513  * @global wpdb $wpdb WordPress database abstraction object.
514  *
515  * @param int    $id         The user ID.
516  * @param string $pref       The column in the wp_users table to update the user's status
517  *                           in (presumably user_status, spam, or deleted).
518  * @param int    $value      The new status for the user.
519  * @param null   $deprecated Deprecated as of 3.0.2 and should not be used.
520  * @return int   The initially passed $value.
521  */
522 function update_user_status( $id, $pref, $value, $deprecated = null ) {
523         global $wpdb;
524
525         if ( null !== $deprecated )
526                 _deprecated_argument( __FUNCTION__, '3.1' );
527
528         $wpdb->update( $wpdb->users, array( sanitize_key( $pref ) => $value ), array( 'ID' => $id ) );
529
530         $user = new WP_User( $id );
531         clean_user_cache( $user );
532
533         if ( $pref == 'spam' ) {
534                 if ( $value == 1 ) {
535                         /**
536                          * Fires after the user is marked as a SPAM user.
537                          *
538                          * @since 3.0.0
539                          *
540                          * @param int $id ID of the user marked as SPAM.
541                          */
542                         do_action( 'make_spam_user', $id );
543                 } else {
544                         /**
545                          * Fires after the user is marked as a HAM user. Opposite of SPAM.
546                          *
547                          * @since 3.0.0
548                          *
549                          * @param int $id ID of the user marked as HAM.
550                          */
551                         do_action( 'make_ham_user', $id );
552                 }
553         }
554
555         return $value;
556 }
557
558 /**
559  * Cleans the user cache for a specific user.
560  *
561  * @since 3.0.0
562  *
563  * @param int $id The user ID.
564  * @return bool|int The ID of the refreshed user or false if the user does not exist.
565  */
566 function refresh_user_details( $id ) {
567         $id = (int) $id;
568
569         if ( !$user = get_userdata( $id ) )
570                 return false;
571
572         clean_user_cache( $user );
573
574         return $id;
575 }
576
577 /**
578  * Returns the language for a language code.
579  *
580  * @since 3.0.0
581  *
582  * @param string $code Optional. The two-letter language code. Default empty.
583  * @return string The language corresponding to $code if it exists. If it does not exist,
584  *                then the first two letters of $code is returned.
585  */
586 function format_code_lang( $code = '' ) {
587         $code = strtolower( substr( $code, 0, 2 ) );
588         $lang_codes = array(
589                 'aa' => 'Afar', 'ab' => 'Abkhazian', 'af' => 'Afrikaans', 'ak' => 'Akan', 'sq' => 'Albanian', 'am' => 'Amharic', 'ar' => 'Arabic', 'an' => 'Aragonese', 'hy' => 'Armenian', 'as' => 'Assamese', 'av' => 'Avaric', 'ae' => 'Avestan', 'ay' => 'Aymara', 'az' => 'Azerbaijani', 'ba' => 'Bashkir', 'bm' => 'Bambara', 'eu' => 'Basque', 'be' => 'Belarusian', 'bn' => 'Bengali',
590                 'bh' => 'Bihari', 'bi' => 'Bislama', 'bs' => 'Bosnian', 'br' => 'Breton', 'bg' => 'Bulgarian', 'my' => 'Burmese', 'ca' => 'Catalan; Valencian', 'ch' => 'Chamorro', 'ce' => 'Chechen', 'zh' => 'Chinese', 'cu' => 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', 'cv' => 'Chuvash', 'kw' => 'Cornish', 'co' => 'Corsican', 'cr' => 'Cree',
591                 'cs' => 'Czech', 'da' => 'Danish', 'dv' => 'Divehi; Dhivehi; Maldivian', 'nl' => 'Dutch; Flemish', 'dz' => 'Dzongkha', 'en' => 'English', 'eo' => 'Esperanto', 'et' => 'Estonian', 'ee' => 'Ewe', 'fo' => 'Faroese', 'fj' => 'Fijjian', 'fi' => 'Finnish', 'fr' => 'French', 'fy' => 'Western Frisian', 'ff' => 'Fulah', 'ka' => 'Georgian', 'de' => 'German', 'gd' => 'Gaelic; Scottish Gaelic',
592                 'ga' => 'Irish', 'gl' => 'Galician', 'gv' => 'Manx', 'el' => 'Greek, Modern', 'gn' => 'Guarani', 'gu' => 'Gujarati', 'ht' => 'Haitian; Haitian Creole', 'ha' => 'Hausa', 'he' => 'Hebrew', 'hz' => 'Herero', 'hi' => 'Hindi', 'ho' => 'Hiri Motu', 'hu' => 'Hungarian', 'ig' => 'Igbo', 'is' => 'Icelandic', 'io' => 'Ido', 'ii' => 'Sichuan Yi', 'iu' => 'Inuktitut', 'ie' => 'Interlingue',
593                 'ia' => 'Interlingua (International Auxiliary Language Association)', 'id' => 'Indonesian', 'ik' => 'Inupiaq', 'it' => 'Italian', 'jv' => 'Javanese', 'ja' => 'Japanese', 'kl' => 'Kalaallisut; Greenlandic', 'kn' => 'Kannada', 'ks' => 'Kashmiri', 'kr' => 'Kanuri', 'kk' => 'Kazakh', 'km' => 'Central Khmer', 'ki' => 'Kikuyu; Gikuyu', 'rw' => 'Kinyarwanda', 'ky' => 'Kirghiz; Kyrgyz',
594                 'kv' => 'Komi', 'kg' => 'Kongo', 'ko' => 'Korean', 'kj' => 'Kuanyama; Kwanyama', 'ku' => 'Kurdish', 'lo' => 'Lao', 'la' => 'Latin', 'lv' => 'Latvian', 'li' => 'Limburgan; Limburger; Limburgish', 'ln' => 'Lingala', 'lt' => 'Lithuanian', 'lb' => 'Luxembourgish; Letzeburgesch', 'lu' => 'Luba-Katanga', 'lg' => 'Ganda', 'mk' => 'Macedonian', 'mh' => 'Marshallese', 'ml' => 'Malayalam',
595                 'mi' => 'Maori', 'mr' => 'Marathi', 'ms' => 'Malay', 'mg' => 'Malagasy', 'mt' => 'Maltese', 'mo' => 'Moldavian', 'mn' => 'Mongolian', 'na' => 'Nauru', 'nv' => 'Navajo; Navaho', 'nr' => 'Ndebele, South; South Ndebele', 'nd' => 'Ndebele, North; North Ndebele', 'ng' => 'Ndonga', 'ne' => 'Nepali', 'nn' => 'Norwegian Nynorsk; Nynorsk, Norwegian', 'nb' => 'BokmÃ¥l, Norwegian, Norwegian BokmÃ¥l',
596                 'no' => 'Norwegian', 'ny' => 'Chichewa; Chewa; Nyanja', 'oc' => 'Occitan, Provençal', 'oj' => 'Ojibwa', 'or' => 'Oriya', 'om' => 'Oromo', 'os' => 'Ossetian; Ossetic', 'pa' => 'Panjabi; Punjabi', 'fa' => 'Persian', 'pi' => 'Pali', 'pl' => 'Polish', 'pt' => 'Portuguese', 'ps' => 'Pushto', 'qu' => 'Quechua', 'rm' => 'Romansh', 'ro' => 'Romanian', 'rn' => 'Rundi', 'ru' => 'Russian',
597                 'sg' => 'Sango', 'sa' => 'Sanskrit', 'sr' => 'Serbian', 'hr' => 'Croatian', 'si' => 'Sinhala; Sinhalese', 'sk' => 'Slovak', 'sl' => 'Slovenian', 'se' => 'Northern Sami', 'sm' => 'Samoan', 'sn' => 'Shona', 'sd' => 'Sindhi', 'so' => 'Somali', 'st' => 'Sotho, Southern', 'es' => 'Spanish; Castilian', 'sc' => 'Sardinian', 'ss' => 'Swati', 'su' => 'Sundanese', 'sw' => 'Swahili',
598                 'sv' => 'Swedish', 'ty' => 'Tahitian', 'ta' => 'Tamil', 'tt' => 'Tatar', 'te' => 'Telugu', 'tg' => 'Tajik', 'tl' => 'Tagalog', 'th' => 'Thai', 'bo' => 'Tibetan', 'ti' => 'Tigrinya', 'to' => 'Tonga (Tonga Islands)', 'tn' => 'Tswana', 'ts' => 'Tsonga', 'tk' => 'Turkmen', 'tr' => 'Turkish', 'tw' => 'Twi', 'ug' => 'Uighur; Uyghur', 'uk' => 'Ukrainian', 'ur' => 'Urdu', 'uz' => 'Uzbek',
599                 've' => 'Venda', 'vi' => 'Vietnamese', 'vo' => 'Volapük', 'cy' => 'Welsh','wa' => 'Walloon','wo' => 'Wolof', 'xh' => 'Xhosa', 'yi' => 'Yiddish', 'yo' => 'Yoruba', 'za' => 'Zhuang; Chuang', 'zu' => 'Zulu' );
600
601         /**
602          * Filter the language codes.
603          *
604          * @since MU
605          *
606          * @param array  $lang_codes Key/value pair of language codes where key is the short version.
607          * @param string $code       A two-letter designation of the language.
608          */
609         $lang_codes = apply_filters( 'lang_codes', $lang_codes, $code );
610         return strtr( $code, $lang_codes );
611 }
612
613 /**
614  * Synchronize category and post tag slugs when global terms are enabled.
615  *
616  * @since 3.0.0
617  *
618  * @param object $term     The term.
619  * @param string $taxonomy The taxonomy for $term. Should be 'category' or 'post_tag', as these are
620  *                         the only taxonomies which are processed by this function; anything else
621  *                         will be returned untouched.
622  * @return object|array Returns `$term`, after filtering the 'slug' field with {@see sanitize_title()}
623  *                      if $taxonomy is 'category' or 'post_tag'.
624  */
625 function sync_category_tag_slugs( $term, $taxonomy ) {
626         if ( global_terms_enabled() && ( $taxonomy == 'category' || $taxonomy == 'post_tag' ) ) {
627                 if ( is_object( $term ) ) {
628                         $term->slug = sanitize_title( $term->name );
629                 } else {
630                         $term['slug'] = sanitize_title( $term['name'] );
631                 }
632         }
633         return $term;
634 }
635
636 /**
637  * Displays an access denied message when a user tries to view a site's dashboard they
638  * do not have access to.
639  *
640  * @since 3.2.0
641  * @access private
642  */
643 function _access_denied_splash() {
644         if ( ! is_user_logged_in() || is_network_admin() )
645                 return;
646
647         $blogs = get_blogs_of_user( get_current_user_id() );
648
649         if ( wp_list_filter( $blogs, array( 'userblog_id' => get_current_blog_id() ) ) )
650                 return;
651
652         $blog_name = get_bloginfo( 'name' );
653
654         if ( empty( $blogs ) )
655                 wp_die( sprintf( __( 'You attempted to access the "%1$s" dashboard, but you do not currently have privileges on this site. If you believe you should be able to access the "%1$s" dashboard, please contact your network administrator.' ), $blog_name ), 403 );
656
657         $output = '<p>' . sprintf( __( 'You attempted to access the "%1$s" dashboard, but you do not currently have privileges on this site. If you believe you should be able to access the "%1$s" dashboard, please contact your network administrator.' ), $blog_name ) . '</p>';
658         $output .= '<p>' . __( 'If you reached this screen by accident and meant to visit one of your own sites, here are some shortcuts to help you find your way.' ) . '</p>';
659
660         $output .= '<h3>' . __('Your Sites') . '</h3>';
661         $output .= '<table>';
662
663         foreach ( $blogs as $blog ) {
664                 $output .= '<tr>';
665                 $output .= "<td>{$blog->blogname}</td>";
666                 $output .= '<td><a href="' . esc_url( get_admin_url( $blog->userblog_id ) ) . '">' . __( 'Visit Dashboard' ) . '</a> | ' .
667                         '<a href="' . esc_url( get_home_url( $blog->userblog_id ) ). '">' . __( 'View Site' ) . '</a></td>';
668                 $output .= '</tr>';
669         }
670
671         $output .= '</table>';
672
673         wp_die( $output, 403 );
674 }
675
676 /**
677  * Checks if the current user has permissions to import new users.
678  *
679  * @since 3.0.0
680  *
681  * @param string $permission A permission to be checked. Currently not used.
682  * @return bool True if the user has proper permissions, false if they do not.
683  */
684 function check_import_new_users( $permission ) {
685         if ( !is_super_admin() )
686                 return false;
687         return true;
688 }
689 // See "import_allow_fetch_attachments" and "import_attachment_size_limit" filters too.
690
691 /**
692  * Generates and displays a drop-down of available languages.
693  *
694  * @since 3.0.0
695  *
696  * @param array  $lang_files Optional. An array of the language files. Default empty array.
697  * @param string $current    Optional. The current language code. Default empty.
698  */
699 function mu_dropdown_languages( $lang_files = array(), $current = '' ) {
700         $flag = false;
701         $output = array();
702
703         foreach ( (array) $lang_files as $val ) {
704                 $code_lang = basename( $val, '.mo' );
705
706                 if ( $code_lang == 'en_US' ) { // American English
707                         $flag = true;
708                         $ae = __( 'American English' );
709                         $output[$ae] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . $ae . '</option>';
710                 } elseif ( $code_lang == 'en_GB' ) { // British English
711                         $flag = true;
712                         $be = __( 'British English' );
713                         $output[$be] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . $be . '</option>';
714                 } else {
715                         $translated = format_code_lang( $code_lang );
716                         $output[$translated] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . esc_html ( $translated ) . '</option>';
717                 }
718
719         }
720
721         if ( $flag === false ) // WordPress english
722                 $output[] = '<option value=""' . selected( $current, '', false ) . '>' . __( 'English' ) . "</option>";
723
724         // Order by name
725         uksort( $output, 'strnatcasecmp' );
726
727         /**
728          * Filter the languages available in the dropdown.
729          *
730          * @since MU
731          *
732          * @param array $output     HTML output of the dropdown.
733          * @param array $lang_files Available language files.
734          * @param string $current   The current language code.
735          */
736         $output = apply_filters( 'mu_dropdown_languages', $output, $lang_files, $current );
737
738         echo implode( "\n\t", $output );
739 }
740
741 /**
742  * Displays an admin notice to upgrade all sites after a core upgrade.
743  *
744  * @since 3.0.0
745  *
746  * @global int $wp_db_version The version number of the database.
747  *
748  * @return false False if the current user is not a super admin.
749  */
750 function site_admin_notice() {
751         global $wp_db_version;
752         if ( !is_super_admin() )
753                 return false;
754         if ( get_site_option( 'wpmu_upgrade_site' ) != $wp_db_version )
755                 echo "<div class='update-nag'>" . sprintf( __( 'Thank you for Updating! Please visit the <a href="%s">Upgrade Network</a> page to update all your sites.' ), esc_url( network_admin_url( 'upgrade.php' ) ) ) . "</div>";
756 }
757
758 /**
759  * Avoids a collision between a site slug and a permalink slug.
760  *
761  * In a subdirectory install this will make sure that a site and a post do not use the
762  * same subdirectory by checking for a site with the same name as a new post.
763  *
764  * @since 3.0.0
765  *
766  * @param array $data    An array of post data.
767  * @param array $postarr An array of posts. Not currently used.
768  * @return array The new array of post data after checking for collisions.
769  */
770 function avoid_blog_page_permalink_collision( $data, $postarr ) {
771         if ( is_subdomain_install() )
772                 return $data;
773         if ( $data['post_type'] != 'page' )
774                 return $data;
775         if ( !isset( $data['post_name'] ) || $data['post_name'] == '' )
776                 return $data;
777         if ( !is_main_site() )
778                 return $data;
779
780         $post_name = $data['post_name'];
781         $c = 0;
782         while( $c < 10 && get_id_from_blogname( $post_name ) ) {
783                 $post_name .= mt_rand( 1, 10 );
784                 $c ++;
785         }
786         if ( $post_name != $data['post_name'] ) {
787                 $data['post_name'] = $post_name;
788         }
789         return $data;
790 }
791
792 /**
793  * Handles the display of choosing a user's primary site.
794  *
795  * This displays the user's primary site and allows the user to choose
796  * which site is primary.
797  *
798  * @since 3.0.0
799  */
800 function choose_primary_blog() {
801         ?>
802         <table class="form-table">
803         <tr>
804         <?php /* translators: My sites label */ ?>
805                 <th scope="row"><label for="primary_blog"><?php _e( 'Primary Site' ); ?></label></th>
806                 <td>
807                 <?php
808                 $all_blogs = get_blogs_of_user( get_current_user_id() );
809                 $primary_blog = get_user_meta( get_current_user_id(), 'primary_blog', true );
810                 if ( count( $all_blogs ) > 1 ) {
811                         $found = false;
812                         ?>
813                         <select name="primary_blog" id="primary_blog">
814                                 <?php foreach ( (array) $all_blogs as $blog ) {
815                                         if ( $primary_blog == $blog->userblog_id )
816                                                 $found = true;
817                                         ?><option value="<?php echo $blog->userblog_id ?>"<?php selected( $primary_blog, $blog->userblog_id ); ?>><?php echo esc_url( get_home_url( $blog->userblog_id ) ) ?></option><?php
818                                 } ?>
819                         </select>
820                         <?php
821                         if ( !$found ) {
822                                 $blog = reset( $all_blogs );
823                                 update_user_meta( get_current_user_id(), 'primary_blog', $blog->userblog_id );
824                         }
825                 } elseif ( count( $all_blogs ) == 1 ) {
826                         $blog = reset( $all_blogs );
827                         echo esc_url( get_home_url( $blog->userblog_id ) );
828                         if ( $primary_blog != $blog->userblog_id ) // Set the primary blog again if it's out of sync with blog list.
829                                 update_user_meta( get_current_user_id(), 'primary_blog', $blog->userblog_id );
830                 } else {
831                         echo "N/A";
832                 }
833                 ?>
834                 </td>
835         </tr>
836         </table>
837         <?php
838 }
839
840 /**
841  * Grants Super Admin privileges.
842  *
843  * @since 3.0.0
844  *
845  * @global array $super_admins
846  *
847  * @param int $user_id ID of the user to be granted Super Admin privileges.
848  * @return bool True on success, false on failure. This can fail when the user is
849  *              already a super admin or when the `$super_admins` global is defined.
850  */
851 function grant_super_admin( $user_id ) {
852         // If global super_admins override is defined, there is nothing to do here.
853         if ( isset( $GLOBALS['super_admins'] ) ) {
854                 return false;
855         }
856
857         /**
858          * Fires before the user is granted Super Admin privileges.
859          *
860          * @since 3.0.0
861          *
862          * @param int $user_id ID of the user that is about to be granted Super Admin privileges.
863          */
864         do_action( 'grant_super_admin', $user_id );
865
866         // Directly fetch site_admins instead of using get_super_admins()
867         $super_admins = get_site_option( 'site_admins', array( 'admin' ) );
868
869         $user = get_userdata( $user_id );
870         if ( $user && ! in_array( $user->user_login, $super_admins ) ) {
871                 $super_admins[] = $user->user_login;
872                 update_site_option( 'site_admins' , $super_admins );
873
874                 /**
875                  * Fires after the user is granted Super Admin privileges.
876                  *
877                  * @since 3.0.0
878                  *
879                  * @param int $user_id ID of the user that was granted Super Admin privileges.
880                  */
881                 do_action( 'granted_super_admin', $user_id );
882                 return true;
883         }
884         return false;
885 }
886
887 /**
888  * Revokes Super Admin privileges.
889  *
890  * @since 3.0.0
891  *
892  * @global array $super_admins
893  *
894  * @param int $user_id ID of the user Super Admin privileges to be revoked from.
895  * @return bool True on success, false on failure. This can fail when the user's email
896  *              is the network admin email or when the `$super_admins` global is defined.
897  */
898 function revoke_super_admin( $user_id ) {
899         // If global super_admins override is defined, there is nothing to do here.
900         if ( isset( $GLOBALS['super_admins'] ) ) {
901                 return false;
902         }
903
904         /**
905          * Fires before the user's Super Admin privileges are revoked.
906          *
907          * @since 3.0.0
908          *
909          * @param int $user_id ID of the user Super Admin privileges are being revoked from.
910          */
911         do_action( 'revoke_super_admin', $user_id );
912
913         // Directly fetch site_admins instead of using get_super_admins()
914         $super_admins = get_site_option( 'site_admins', array( 'admin' ) );
915
916         $user = get_userdata( $user_id );
917         if ( $user && 0 !== strcasecmp( $user->user_email, get_site_option( 'admin_email' ) ) ) {
918                 if ( false !== ( $key = array_search( $user->user_login, $super_admins ) ) ) {
919                         unset( $super_admins[$key] );
920                         update_site_option( 'site_admins', $super_admins );
921
922                         /**
923                          * Fires after the user's Super Admin privileges are revoked.
924                          *
925                          * @since 3.0.0
926                          *
927                          * @param int $user_id ID of the user Super Admin privileges were revoked from.
928                          */
929                         do_action( 'revoked_super_admin', $user_id );
930                         return true;
931                 }
932         }
933         return false;
934 }
935
936 /**
937  * Whether or not we can edit this network from this page.
938  *
939  * By default editing of network is restricted to the Network Admin for that `$site_id`
940  * this allows for this to be overridden.
941  *
942  * @since 3.1.0
943  *
944  * @global wpdb $wpdb WordPress database abstraction object.
945  *
946  * @param int $site_id The network/site ID to check.
947  * @return bool True if network can be edited, otherwise false.
948  */
949 function can_edit_network( $site_id ) {
950         global $wpdb;
951
952         if ( $site_id == $wpdb->siteid )
953                 $result = true;
954         else
955                 $result = false;
956
957         /**
958          * Filter whether this network can be edited from this page.
959          *
960          * @since 3.1.0
961          *
962          * @param bool $result  Whether the network can be edited from this page.
963          * @param int  $site_id The network/site ID to check.
964          */
965         return apply_filters( 'can_edit_network', $result, $site_id );
966 }
967
968 /**
969  * Thickbox image paths for Network Admin.
970  *
971  * @since 3.1.0
972  *
973  * @access private
974  */
975 function _thickbox_path_admin_subfolder() {
976 ?>
977 <script type="text/javascript">
978 var tb_pathToImage = "<?php echo includes_url( 'js/thickbox/loadingAnimation.gif', 'relative' ); ?>";
979 </script>
980 <?php
981 }
982
983 /**
984  *
985  * @param array $users
986  */
987 function confirm_delete_users( $users ) {
988         $current_user = wp_get_current_user();
989         if ( ! is_array( $users ) || empty( $users ) ) {
990                 return false;
991         }
992         ?>
993         <h1><?php esc_html_e( 'Users' ); ?></h1>
994
995         <?php if ( 1 == count( $users ) ) : ?>
996                 <p><?php _e( 'You have chosen to delete the user from all networks and sites.' ); ?></p>
997         <?php else : ?>
998                 <p><?php _e( 'You have chosen to delete the following users from all networks and sites.' ); ?></p>
999         <?php endif; ?>
1000
1001         <form action="users.php?action=dodelete" method="post">
1002         <input type="hidden" name="dodelete" />
1003         <?php
1004         wp_nonce_field( 'ms-users-delete' );
1005         $site_admins = get_super_admins();
1006         $admin_out = '<option value="' . esc_attr( $current_user->ID ) . '">' . $current_user->user_login . '</option>'; ?>
1007         <table class="form-table">
1008         <?php foreach ( ( $allusers = (array) $_POST['allusers'] ) as $user_id ) {
1009                 if ( $user_id != '' && $user_id != '0' ) {
1010                         $delete_user = get_userdata( $user_id );
1011
1012                         if ( ! current_user_can( 'delete_user', $delete_user->ID ) ) {
1013                                 wp_die( sprintf( __( 'Warning! User %s cannot be deleted.' ), $delete_user->user_login ) );
1014                         }
1015
1016                         if ( in_array( $delete_user->user_login, $site_admins ) ) {
1017                                 wp_die( sprintf( __( 'Warning! User cannot be deleted. The user %s is a network administrator.' ), '<em>' . $delete_user->user_login . '</em>' ) );
1018                         }
1019                         ?>
1020                         <tr>
1021                                 <th scope="row"><?php echo $delete_user->user_login; ?>
1022                                         <?php echo '<input type="hidden" name="user[]" value="' . esc_attr( $user_id ) . '" />' . "\n"; ?>
1023                                 </th>
1024                         <?php $blogs = get_blogs_of_user( $user_id, true );
1025
1026                         if ( ! empty( $blogs ) ) {
1027                                 ?>
1028                                 <td><fieldset><p><legend><?php printf(
1029                                         /* translators: user login */
1030                                         __( 'What should be done with content owned by %s?' ),
1031                                         '<em>' . $delete_user->user_login . '</em>'
1032                                 ); ?></legend></p>
1033                                 <?php
1034                                 foreach ( (array) $blogs as $key => $details ) {
1035                                         $blog_users = get_users( array( 'blog_id' => $details->userblog_id, 'fields' => array( 'ID', 'user_login' ) ) );
1036                                         if ( is_array( $blog_users ) && !empty( $blog_users ) ) {
1037                                                 $user_site = "<a href='" . esc_url( get_home_url( $details->userblog_id ) ) . "'>{$details->blogname}</a>";
1038                                                 $user_dropdown = '<label for="reassign_user" class="screen-reader-text">' . __( 'Select a user' ) . '</label>';
1039                                                 $user_dropdown .= "<select name='blog[$user_id][$key]' id='reassign_user'>";
1040                                                 $user_list = '';
1041                                                 foreach ( $blog_users as $user ) {
1042                                                         if ( ! in_array( $user->ID, $allusers ) ) {
1043                                                                 $user_list .= "<option value='{$user->ID}'>{$user->user_login}</option>";
1044                                                         }
1045                                                 }
1046                                                 if ( '' == $user_list ) {
1047                                                         $user_list = $admin_out;
1048                                                 }
1049                                                 $user_dropdown .= $user_list;
1050                                                 $user_dropdown .= "</select>\n";
1051                                                 ?>
1052                                                 <ul style="list-style:none;">
1053                                                         <li><?php printf( __( 'Site: %s' ), $user_site ); ?></li>
1054                                                         <li><label><input type="radio" id="delete_option0" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID ?>]" value="delete" checked="checked" />
1055                                                         <?php _e( 'Delete all content.' ); ?></label></li>
1056                                                         <li><label><input type="radio" id="delete_option1" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID ?>]" value="reassign" />
1057                                                         <?php _e( 'Attribute all content to:' ); ?></label>
1058                                                         <?php echo $user_dropdown; ?></li>
1059                                                 </ul>
1060                                                 <?php
1061                                         }
1062                                 }
1063                                 echo "</fieldset></td></tr>";
1064                         } else {
1065                                 ?>
1066                                 <td><fieldset><p><legend><?php _e( 'User has no sites or content and will be deleted.' ); ?></legend></p>
1067                         <?php } ?>
1068                         </tr>
1069                 <?php
1070                 }
1071         }
1072
1073         ?>
1074         </table>
1075         <?php
1076         /** This action is documented in wp-admin/users.php */
1077         do_action( 'delete_user_form', $current_user );
1078
1079         if ( 1 == count( $users ) ) : ?>
1080                 <p><?php _e( 'Once you hit &#8220;Confirm Deletion&#8221;, the user will be permanently removed.' ); ?></p>
1081         <?php else : ?>
1082                 <p><?php _e( 'Once you hit &#8220;Confirm Deletion&#8221;, these users will be permanently removed.' ); ?></p>
1083         <?php endif;
1084
1085         submit_button( __('Confirm Deletion'), 'primary' );
1086         ?>
1087         </form>
1088         <?php
1089         return true;
1090 }
1091
1092 /**
1093  * Print JavaScript in the header on the Network Settings screen.
1094  *
1095  * @since 4.1.0
1096 */
1097 function network_settings_add_js() {
1098 ?>
1099 <script type="text/javascript">
1100 jQuery(document).ready( function($) {
1101         var languageSelect = $( '#WPLANG' );
1102         $( 'form' ).submit( function() {
1103                 // Don't show a spinner for English and installed languages,
1104                 // as there is nothing to download.
1105                 if ( ! languageSelect.find( 'option:selected' ).data( 'installed' ) ) {
1106                         $( '#submit', this ).after( '<span class="spinner language-install-spinner" />' );
1107                 }
1108         });
1109 });
1110 </script>
1111 <?php
1112 }