WordPress 3.8
[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) /1024 ) );
33         if ( $file_size > ( 1024 * get_site_option( 'fileupload_maxk', 1500 ) ) )
34                 $file['error'] = sprintf(__('This file is too big. Files must be less than %1$s KB in size.'), get_site_option( 'fileupload_maxk', 1500 ) );
35         if ( upload_is_user_over_quota( false ) ) {
36                 $file['error'] = __( 'You have used your space quota. Please delete files before uploading.' );
37         }
38         if ( $file['error'] != '0' && !isset($_POST['html-upload']) )
39                 wp_die( $file['error'] . ' <a href="javascript:history.go(-1)">' . __( 'Back' ) . '</a>' );
40
41         return $file;
42 }
43 add_filter( 'wp_handle_upload_prefilter', 'check_upload_size' );
44
45 /**
46  * Delete a blog
47  *
48  * @since 3.0.0
49  *
50  * @param int $blog_id Blog ID
51  * @param bool $drop True if blog's table should be dropped. Default is false.
52  * @return void
53  */
54 function wpmu_delete_blog( $blog_id, $drop = false ) {
55         global $wpdb;
56
57         $switch = false;
58         if ( get_current_blog_id() != $blog_id ) {
59                 $switch = true;
60                 switch_to_blog( $blog_id );
61         }
62
63         $blog = get_blog_details( $blog_id );
64         /**
65          * Fires before a blog is deleted.
66          *
67          * @since MU
68          *
69          * @param int  $blog_id The blog ID.
70          * @param bool $drop    True if blog's table should be dropped. Default is false.
71          */
72         do_action( 'delete_blog', $blog_id, $drop );
73
74         $users = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ids' ) );
75
76         // Remove users from this blog.
77         if ( ! empty( $users ) ) {
78                 foreach ( $users as $user_id ) {
79                         remove_user_from_blog( $user_id, $blog_id );
80                 }
81         }
82
83         update_blog_status( $blog_id, 'deleted', 1 );
84
85         $current_site = get_current_site();
86
87         // Don't destroy the initial, main, or root blog.
88         if ( $drop && ( 1 == $blog_id || is_main_site( $blog_id ) || ( $blog->path == $current_site->path && $blog->domain == $current_site->domain ) ) )
89                 $drop = false;
90
91         if ( $drop ) {
92                 $tables = $wpdb->tables( 'blog' );
93                 /**
94                  * Filter the tables to drop when the blog is deleted.
95                  *
96                  * @since MU
97                  *
98                  * @param array $tables  The blog tables to be dropped.
99                  * @param int   $blog_id The ID of the blog to drop tables for.
100                  */
101                 $drop_tables = apply_filters( 'wpmu_drop_tables', $tables, $blog_id );
102
103                 foreach ( (array) $drop_tables as $table ) {
104                         $wpdb->query( "DROP TABLE IF EXISTS `$table`" );
105                 }
106
107                 $wpdb->delete( $wpdb->blogs, array( 'blog_id' => $blog_id ) );
108
109                 $uploads = wp_upload_dir();
110                 /**
111                  * Filter the upload base directory to delete when the blog is deleted.
112                  *
113                  * @since MU
114                  *
115                  * @param string $uploads['basedir'] Uploads path without subdirectory. @see wp_upload_dir()
116                  * @param int    $blog_id            The blog ID.
117                  */
118                 $dir = apply_filters( 'wpmu_delete_blog_upload_dir', $uploads['basedir'], $blog_id );
119                 $dir = rtrim( $dir, DIRECTORY_SEPARATOR );
120                 $top_dir = $dir;
121                 $stack = array($dir);
122                 $index = 0;
123
124                 while ( $index < count( $stack ) ) {
125                         # Get indexed directory from stack
126                         $dir = $stack[$index];
127
128                         $dh = @opendir( $dir );
129                         if ( $dh ) {
130                                 while ( ( $file = @readdir( $dh ) ) !== false ) {
131                                         if ( $file == '.' || $file == '..' )
132                                                 continue;
133
134                                         if ( @is_dir( $dir . DIRECTORY_SEPARATOR . $file ) )
135                                                 $stack[] = $dir . DIRECTORY_SEPARATOR . $file;
136                                         else if ( @is_file( $dir . DIRECTORY_SEPARATOR . $file ) )
137                                                 @unlink( $dir . DIRECTORY_SEPARATOR . $file );
138                                 }
139                                 @closedir( $dh );
140                         }
141                         $index++;
142                 }
143
144                 $stack = array_reverse( $stack ); // Last added dirs are deepest
145                 foreach( (array) $stack as $dir ) {
146                         if ( $dir != $top_dir)
147                         @rmdir( $dir );
148                 }
149
150                 clean_blog_cache( $blog );
151         }
152
153         if ( $switch )
154                 restore_current_blog();
155 }
156
157 // @todo Merge with wp_delete_user() ?
158 function wpmu_delete_user( $id ) {
159         global $wpdb;
160
161         $id = (int) $id;
162         $user = new WP_User( $id );
163
164         if ( !$user->exists() )
165                 return false;
166         /**
167          * Fires before a user is deleted from the network.
168          *
169          * @since MU
170          *
171          * @param int $id ID of the user about to be deleted from the network.
172          */
173         do_action( 'wpmu_delete_user', $id );
174
175         $blogs = get_blogs_of_user( $id );
176
177         if ( ! empty( $blogs ) ) {
178                 foreach ( $blogs as $blog ) {
179                         switch_to_blog( $blog->userblog_id );
180                         remove_user_from_blog( $id, $blog->userblog_id );
181
182                         $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
183                         foreach ( (array) $post_ids as $post_id ) {
184                                 wp_delete_post( $post_id );
185                         }
186
187                         // Clean links
188                         $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) );
189
190                         if ( $link_ids ) {
191                                 foreach ( $link_ids as $link_id )
192                                         wp_delete_link( $link_id );
193                         }
194
195                         restore_current_blog();
196                 }
197         }
198
199         $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
200         foreach ( $meta as $mid )
201                 delete_metadata_by_mid( 'user', $mid );
202
203         $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
204
205         clean_user_cache( $user );
206
207         /** This action is documented in wp-admin/includes/user.php */
208         do_action( 'deleted_user', $id );
209
210         return true;
211 }
212
213 function update_option_new_admin_email( $old_value, $value ) {
214         $email = get_option( 'admin_email' );
215         if ( $value == get_option( 'admin_email' ) || !is_email( $value ) )
216                 return;
217
218         $hash = md5( $value. time() .mt_rand() );
219         $new_admin_email = array(
220                 'hash' => $hash,
221                 'newemail' => $value
222         );
223         update_option( 'adminhash', $new_admin_email );
224
225         $email_text = __( 'Dear user,
226
227 You recently requested to have the administration email address on
228 your site changed.
229 If this is correct, please click on the following link to change it:
230 ###ADMIN_URL###
231
232 You can safely ignore and delete this email if you do not want to
233 take this action.
234
235 This email has been sent to ###EMAIL###
236
237 Regards,
238 All at ###SITENAME###
239 ###SITEURL###' );
240
241         /**
242          * Filter the email text sent when the site admin email is changed.
243          *
244          * The following strings have a special meaning and will get replaced dynamically:
245          * ###ADMIN_URL### The link to click on to confirm the email change. Required otherwise this functunalty is will break.
246          * ###EMAIL###     The new email.
247          * ###SITENAME###  The name of the site.
248          * ###SITEURL###   The URL to the site.
249          *
250          * @since MU
251          *
252          * @param string $email_text      Text in the email.
253          * @param string $new_admin_email New admin email that the current administration email was changed to.
254          */
255         $content = apply_filters( 'new_admin_email_content', $email_text, $new_admin_email );
256
257         $content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'options.php?adminhash='.$hash ) ), $content );
258         $content = str_replace( '###EMAIL###', $value, $content );
259         $content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
260         $content = str_replace( '###SITEURL###', network_home_url(), $content );
261
262         wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), get_option( 'blogname' ) ), $content );
263 }
264 add_action( 'update_option_new_admin_email', 'update_option_new_admin_email', 10, 2 );
265 add_action( 'add_option_new_admin_email', 'update_option_new_admin_email', 10, 2 );
266
267 function send_confirmation_on_profile_email() {
268         global $errors, $wpdb;
269         $current_user = wp_get_current_user();
270         if ( ! is_object($errors) )
271                 $errors = new WP_Error();
272
273         if ( $current_user->ID != $_POST['user_id'] )
274                 return false;
275
276         if ( $current_user->user_email != $_POST['email'] ) {
277                 if ( !is_email( $_POST['email'] ) ) {
278                         $errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address isn&#8217;t correct." ), array( 'form-field' => 'email' ) );
279                         return;
280                 }
281
282                 if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_email FROM {$wpdb->users} WHERE user_email=%s", $_POST['email'] ) ) ) {
283                         $errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address is already used." ), array( 'form-field' => 'email' ) );
284                         delete_option( $current_user->ID . '_new_email' );
285                         return;
286                 }
287
288                 $hash = md5( $_POST['email'] . time() . mt_rand() );
289                 $new_user_email = array(
290                                 'hash' => $hash,
291                                 'newemail' => $_POST['email']
292                                 );
293                 update_option( $current_user->ID . '_new_email', $new_user_email );
294
295                 $email_text = __( 'Dear user,
296
297 You recently requested to have the email address on your account changed.
298 If this is correct, please click on the following link to change it:
299 ###ADMIN_URL###
300
301 You can safely ignore and delete this email if you do not want to
302 take this action.
303
304 This email has been sent to ###EMAIL###
305
306 Regards,
307 All at ###SITENAME###
308 ###SITEURL###' );
309
310                 /**
311                  * Filter the email text sent when a user changes emails.
312                  *
313                  * The following strings have a special meaning and will get replaced dynamically:
314                  * ###ADMIN_URL### The link to click on to confirm the email change. Required otherwise this functunalty is will break.
315                  * ###EMAIL### The new email.
316                  * ###SITENAME### The name of the site.
317                  * ###SITEURL### The URL to the site.
318                  *
319                  * @since MU
320                  *
321                  * @param string $email_text     Text in the email.
322                  * @param string $new_user_email New user email that the current user has changed to.
323                  */
324                 $content = apply_filters( 'new_user_email_content', $email_text, $new_user_email );
325
326                 $content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail='.$hash ) ), $content );
327                 $content = str_replace( '###EMAIL###', $_POST['email'], $content);
328                 $content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
329                 $content = str_replace( '###SITEURL###', network_home_url(), $content );
330
331                 wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), get_option( 'blogname' ) ), $content );
332                 $_POST['email'] = $current_user->user_email;
333         }
334 }
335 add_action( 'personal_options_update', 'send_confirmation_on_profile_email' );
336
337 function new_user_email_admin_notice() {
338         if ( strpos( $_SERVER['PHP_SELF'], 'profile.php' ) && isset( $_GET['updated'] ) && $email = get_option( get_current_user_id() . '_new_email' ) )
339                 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>";
340 }
341 add_action( 'admin_notices', 'new_user_email_admin_notice' );
342
343 /**
344  * Check whether a blog has used its allotted upload space.
345  *
346  * @since MU
347  *
348  * @param bool $echo Optional. If $echo is set and the quota is exceeded, a warning message is echoed. Default is true.
349  * @return int
350  */
351 function upload_is_user_over_quota( $echo = true ) {
352         if ( get_site_option( 'upload_space_check_disabled' ) )
353                 return false;
354
355         $space_allowed = get_space_allowed();
356         if ( empty( $space_allowed ) || !is_numeric( $space_allowed ) )
357                 $space_allowed = 10; // Default space allowed is 10 MB
358
359         $space_used = get_space_used();
360
361         if ( ( $space_allowed - $space_used ) < 0 ) {
362                 if ( $echo )
363                         _e( 'Sorry, you have used your space allocation. Please delete some files to upload more files.' );
364                 return true;
365         } else {
366                 return false;
367         }
368 }
369
370 /**
371  * Displays the amount of disk space used by the current blog. Not used in core.
372  *
373  * @since MU
374  */
375 function display_space_usage() {
376         $space_allowed = get_space_allowed();
377         $space_used = get_space_used();
378
379         $percent_used = ( $space_used / $space_allowed ) * 100;
380
381         if ( $space_allowed > 1000 ) {
382                 $space = number_format( $space_allowed / 1024 );
383                 /* translators: Gigabytes */
384                 $space .= __( 'GB' );
385         } else {
386                 $space = number_format( $space_allowed );
387                 /* translators: Megabytes */
388                 $space .= __( 'MB' );
389         }
390         ?>
391         <strong><?php printf( __( 'Used: %1$s%% of %2$s' ), number_format( $percent_used ), $space ); ?></strong>
392         <?php
393 }
394
395 /**
396  * Get the remaining upload space for this blog.
397  *
398  * @since MU
399  * @uses upload_is_user_over_quota()
400  * @uses get_space_allowed()
401  * @uses get_upload_space_available()
402  *
403  * @param int $size Current max size in bytes
404  * @return int Max size in bytes
405  */
406 function fix_import_form_size( $size ) {
407         if ( upload_is_user_over_quota( false ) == true )
408                 return 0;
409
410         $available = get_upload_space_available();
411         return min( $size, $available );
412 }
413
414 // Edit blog upload space setting on Edit Blog page
415 function upload_space_setting( $id ) {
416         switch_to_blog( $id );
417         $quota = get_option( 'blog_upload_space' );
418         restore_current_blog();
419
420         if ( !$quota )
421                 $quota = '';
422
423         ?>
424         <tr>
425                 <th><?php _e( 'Site Upload Space Quota '); ?></th>
426                 <td><input type="number" step="1" min="0" style="width: 100px" name="option[blog_upload_space]" value="<?php echo $quota; ?>" /> <?php _e( 'MB (Leave blank for network default)' ); ?></td>
427         </tr>
428         <?php
429 }
430 add_action( 'wpmueditblogaction', 'upload_space_setting' );
431
432 function update_user_status( $id, $pref, $value, $deprecated = null ) {
433         global $wpdb;
434
435         if ( null !== $deprecated )
436                 _deprecated_argument( __FUNCTION__, '3.1' );
437
438         $wpdb->update( $wpdb->users, array( sanitize_key( $pref ) => $value ), array( 'ID' => $id ) );
439
440         $user = new WP_User( $id );
441         clean_user_cache( $user );
442
443         if ( $pref == 'spam' ) {
444                 if ( $value == 1 ) {
445                         /**
446                          * Fires after the user is marked as a SPAM user.
447                          *
448                          * @since 3.0.0
449                          *
450                          * @param int $id ID of the user marked as SPAM.
451                          */
452                         do_action( 'make_spam_user', $id );
453                 } else {
454                         /**
455                          * Fires after the user is marked as a HAM user. Opposite of SPAM.
456                          *
457                          * @since 3.0.0
458                          *
459                          * @param int $id ID of the user marked as HAM.
460                          */
461                         do_action( 'make_ham_user', $id );
462                 }
463         }
464
465         return $value;
466 }
467
468 function refresh_user_details( $id ) {
469         $id = (int) $id;
470
471         if ( !$user = get_userdata( $id ) )
472                 return false;
473
474         clean_user_cache( $user );
475
476         return $id;
477 }
478
479 function format_code_lang( $code = '' ) {
480         $code = strtolower( substr( $code, 0, 2 ) );
481         $lang_codes = array(
482                 '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',
483                 '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',
484                 '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',
485                 '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',
486                 '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',
487                 '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',
488                 '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',
489                 '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',
490                 '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',
491                 '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',
492                 've' => 'Venda', 'vi' => 'Vietnamese', 'vo' => 'Volapük', 'cy' => 'Welsh','wa' => 'Walloon','wo' => 'Wolof', 'xh' => 'Xhosa', 'yi' => 'Yiddish', 'yo' => 'Yoruba', 'za' => 'Zhuang; Chuang', 'zu' => 'Zulu' );
493
494         /**
495          * Filter the language codes.
496          *
497          * @since MU
498          *
499          * @param array  $lang_codes Key/value pair of language codes where key is the short version.
500          * @param string $code       A two-letter designation of the language.
501          */
502         $lang_codes = apply_filters( 'lang_codes', $lang_codes, $code );
503         return strtr( $code, $lang_codes );
504 }
505
506 function sync_category_tag_slugs( $term, $taxonomy ) {
507         if ( global_terms_enabled() && ( $taxonomy == 'category' || $taxonomy == 'post_tag' ) ) {
508                 if ( is_object( $term ) ) {
509                         $term->slug = sanitize_title( $term->name );
510                 } else {
511                         $term['slug'] = sanitize_title( $term['name'] );
512                 }
513         }
514         return $term;
515 }
516 add_filter( 'get_term', 'sync_category_tag_slugs', 10, 2 );
517
518 function _access_denied_splash() {
519         if ( ! is_user_logged_in() || is_network_admin() )
520                 return;
521
522         $blogs = get_blogs_of_user( get_current_user_id() );
523
524         if ( wp_list_filter( $blogs, array( 'userblog_id' => get_current_blog_id() ) ) )
525                 return;
526
527         $blog_name = get_bloginfo( 'name' );
528
529         if ( empty( $blogs ) )
530                 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 ) );
531
532         $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>';
533         $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>';
534
535         $output .= '<h3>' . __('Your Sites') . '</h3>';
536         $output .= '<table>';
537
538         foreach ( $blogs as $blog ) {
539                 $output .= "<tr>";
540                 $output .= "<td valign='top'>";
541                 $output .= "{$blog->blogname}";
542                 $output .= "</td>";
543                 $output .= "<td valign='top'>";
544                 $output .= "<a href='" . esc_url( get_admin_url( $blog->userblog_id ) ) . "'>" . __( 'Visit Dashboard' ) . "</a> | <a href='" . esc_url( get_home_url( $blog->userblog_id ) ). "'>" . __( 'View Site' ) . "</a>" ;
545                 $output .= "</td>";
546                 $output .= "</tr>";
547         }
548         $output .= '</table>';
549
550         wp_die( $output );
551 }
552 add_action( 'admin_page_access_denied', '_access_denied_splash', 99 );
553
554 function check_import_new_users( $permission ) {
555         if ( !is_super_admin() )
556                 return false;
557         return true;
558 }
559 add_filter( 'import_allow_create_users', 'check_import_new_users' );
560 // See "import_allow_fetch_attachments" and "import_attachment_size_limit" filters too.
561
562 function mu_dropdown_languages( $lang_files = array(), $current = '' ) {
563         $flag = false;
564         $output = array();
565
566         foreach ( (array) $lang_files as $val ) {
567                 $code_lang = basename( $val, '.mo' );
568
569                 if ( $code_lang == 'en_US' ) { // American English
570                         $flag = true;
571                         $ae = __( 'American English' );
572                         $output[$ae] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . $ae . '</option>';
573                 } elseif ( $code_lang == 'en_GB' ) { // British English
574                         $flag = true;
575                         $be = __( 'British English' );
576                         $output[$be] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . $be . '</option>';
577                 } else {
578                         $translated = format_code_lang( $code_lang );
579                         $output[$translated] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . esc_html ( $translated ) . '</option>';
580                 }
581
582         }
583
584         if ( $flag === false ) // WordPress english
585                 $output[] = '<option value=""' . selected( $current, '', false ) . '>' . __( 'English' ) . "</option>";
586
587         // Order by name
588         uksort( $output, 'strnatcasecmp' );
589         /**
590          * Filter the languages available in the dropdown.
591          *
592          * @since MU
593          *
594          * @param array $output     HTML output of the dropdown.
595          * @param array $lang_files Available language files.
596          * @param string $current   The current language code.
597          */
598         $output = apply_filters( 'mu_dropdown_languages', $output, $lang_files, $current );
599         echo implode( "\n\t", $output );
600 }
601
602 function site_admin_notice() {
603         global $wp_db_version;
604         if ( !is_super_admin() )
605                 return false;
606         if ( get_site_option( 'wpmu_upgrade_site' ) != $wp_db_version )
607                 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>";
608 }
609 add_action( 'admin_notices', 'site_admin_notice' );
610 add_action( 'network_admin_notices', 'site_admin_notice' );
611
612 function avoid_blog_page_permalink_collision( $data, $postarr ) {
613         if ( is_subdomain_install() )
614                 return $data;
615         if ( $data['post_type'] != 'page' )
616                 return $data;
617         if ( !isset( $data['post_name'] ) || $data['post_name'] == '' )
618                 return $data;
619         if ( !is_main_site() )
620                 return $data;
621
622         $post_name = $data['post_name'];
623         $c = 0;
624         while( $c < 10 && get_id_from_blogname( $post_name ) ) {
625                 $post_name .= mt_rand( 1, 10 );
626                 $c ++;
627         }
628         if ( $post_name != $data['post_name'] ) {
629                 $data['post_name'] = $post_name;
630         }
631         return $data;
632 }
633 add_filter( 'wp_insert_post_data', 'avoid_blog_page_permalink_collision', 10, 2 );
634
635 function choose_primary_blog() {
636         ?>
637         <table class="form-table">
638         <tr>
639         <?php /* translators: My sites label */ ?>
640                 <th scope="row"><?php _e( 'Primary Site' ); ?></th>
641                 <td>
642                 <?php
643                 $all_blogs = get_blogs_of_user( get_current_user_id() );
644                 $primary_blog = get_user_meta( get_current_user_id(), 'primary_blog', true );
645                 if ( count( $all_blogs ) > 1 ) {
646                         $found = false;
647                         ?>
648                         <select name="primary_blog">
649                                 <?php foreach( (array) $all_blogs as $blog ) {
650                                         if ( $primary_blog == $blog->userblog_id )
651                                                 $found = true;
652                                         ?><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
653                                 } ?>
654                         </select>
655                         <?php
656                         if ( !$found ) {
657                                 $blog = array_shift( $all_blogs );
658                                 update_user_meta( get_current_user_id(), 'primary_blog', $blog->userblog_id );
659                         }
660                 } elseif ( count( $all_blogs ) == 1 ) {
661                         $blog = array_shift( $all_blogs );
662                         echo $blog->domain;
663                         if ( $primary_blog != $blog->userblog_id ) // Set the primary blog again if it's out of sync with blog list.
664                                 update_user_meta( get_current_user_id(), 'primary_blog', $blog->userblog_id );
665                 } else {
666                         echo "N/A";
667                 }
668                 ?>
669                 </td>
670         </tr>
671         <?php if ( in_array( get_site_option( 'registration' ), array( 'all', 'blog' ) ) ) : ?>
672                 <tr>
673                         <th scope="row" colspan="2" class="th-full">
674                                 <?php
675                                 $signup_url = network_site_url( 'wp-signup.php' );
676                                 /** This filter is documented in wp-login.php */
677                                 ?>
678                                 <a href="<?php echo apply_filters( 'wp_signup_location', $signup_url ); ?>"><?php _e( 'Create a New Site' ); ?></a>
679                         </th>
680                 </tr>
681         <?php endif; ?>
682         </table>
683         <?php
684 }
685
686 /**
687  * Grants Super Admin privileges.
688  *
689  * @since 3.0.0
690  * @param int $user_id ID of the user to be granted Super Admin privileges.
691  */
692 function grant_super_admin( $user_id ) {
693         global $super_admins;
694
695         // If global super_admins override is defined, there is nothing to do here.
696         if ( isset( $super_admins ) )
697                 return false;
698
699         /**
700          * Fires before the user is granted Super Admin privileges.
701          *
702          * @since 3.0.0
703          *
704          * @param int $user_id ID of the user that is about to be granted Super Admin privileges.
705          */
706         do_action( 'grant_super_admin', $user_id );
707
708         // Directly fetch site_admins instead of using get_super_admins()
709         $super_admins = get_site_option( 'site_admins', array( 'admin' ) );
710
711         $user = get_userdata( $user_id );
712         if ( $user && ! in_array( $user->user_login, $super_admins ) ) {
713                 $super_admins[] = $user->user_login;
714                 update_site_option( 'site_admins' , $super_admins );
715
716                 /**
717                  * Fires after the user is granted Super Admin privileges.
718                  *
719                  * @since 3.0.0
720                  *
721                  * @param int $user_id ID of the user that was granted Super Admin privileges.
722                  */
723                 do_action( 'granted_super_admin', $user_id );
724                 return true;
725         }
726         return false;
727 }
728
729 /**
730  * Revokes Super Admin privileges.
731  *
732  * @since 3.0.0
733  * @param int $user_id ID of the user Super Admin privileges to be revoked from.
734  */
735 function revoke_super_admin( $user_id ) {
736         global $super_admins;
737
738         // If global super_admins override is defined, there is nothing to do here.
739         if ( isset( $super_admins ) )
740                 return false;
741
742         /**
743          * Fires before the user's Super Admin privileges are revoked.
744          *
745          * @since 3.0.0
746          *
747          * @param int $user_id ID of the user Super Admin privileges are being revoked from.
748          */
749         do_action( 'revoke_super_admin', $user_id );
750
751         // Directly fetch site_admins instead of using get_super_admins()
752         $super_admins = get_site_option( 'site_admins', array( 'admin' ) );
753
754         $user = get_userdata( $user_id );
755         if ( $user && 0 !== strcasecmp( $user->user_email, get_site_option( 'admin_email' ) ) ) {
756                 if ( false !== ( $key = array_search( $user->user_login, $super_admins ) ) ) {
757                         unset( $super_admins[$key] );
758                         update_site_option( 'site_admins', $super_admins );
759
760                         /**
761                          * Fires after the user's Super Admin privileges are revoked.
762                          *
763                          * @since 3.0.0
764                          *
765                          * @param int $user_id ID of the user Super Admin privileges were revoked from.
766                          */
767                         do_action( 'revoked_super_admin', $user_id );
768                         return true;
769                 }
770         }
771         return false;
772 }
773
774 /**
775  * Whether or not we can edit this network from this page
776  *
777  * By default editing of network is restricted to the Network Admin for that site_id this allows for this to be overridden
778  *
779  * @since 3.1.0
780  * @param integer $site_id The network/site ID to check.
781  */
782 function can_edit_network( $site_id ) {
783         global $wpdb;
784
785         if ( $site_id == $wpdb->siteid )
786                 $result = true;
787         else
788                 $result = false;
789
790         /**
791          * Filter whether this network can be edited from this page.
792          *
793          * @since 3.1.0
794          *
795          * @param bool $result  Whether the network can be edited from this page.
796          * @param int  $site_id The network/site ID to check.
797          */
798         return apply_filters( 'can_edit_network', $result, $site_id );
799 }
800
801 /**
802  * Thickbox image paths for Network Admin.
803  *
804  * @since 3.1.0
805  * @access private
806  */
807 function _thickbox_path_admin_subfolder() {
808 ?>
809 <script type="text/javascript">
810 //<![CDATA[
811 var tb_pathToImage = "../../wp-includes/js/thickbox/loadingAnimation.gif";
812 //]]>
813 </script>
814 <?php
815 }