Skip to content

Commit f16b2a6

Browse files
committed
Role/Capability: Introduce capabilities dedicated to installing and updating language files.
The new meta capabilities are called `install_languages` and `update_languages`. Prior to this change, there were no proper capability checks applied. Instead only the filesystem and related constants were checked, and for actual permissions a rather vague fallback was used where a user needed to have at least one of the other updating capabilities. In addition to being generally more verbose, the new capabilities make it possible for example to allow a user to update languages, but nothing else. By default they fall back to the original way of how they were handled. Props johnbillion, flixos90. Fixes #39677. git-svn-id: https://develop.svn.wordpress.org/trunk@41268 602fd350-edb4-49c9-b593-d223f7449a82
1 parent c56dd07 commit f16b2a6

9 files changed

Lines changed: 68 additions & 21 deletions

File tree

src/wp-admin/menu.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@
3333
}
3434

3535
if ( ! is_multisite() ) {
36-
if ( current_user_can( 'update_core' ) )
36+
if ( current_user_can( 'update_core' ) ) {
3737
$cap = 'update_core';
38-
elseif ( current_user_can( 'update_plugins' ) )
38+
} elseif ( current_user_can( 'update_plugins' ) ) {
3939
$cap = 'update_plugins';
40-
else
40+
} elseif ( current_user_can( 'update_themes' ) ) {
4141
$cap = 'update_themes';
42+
} else {
43+
$cap = 'update_languages';
44+
}
4245
$submenu[ 'index.php' ][10] = array( sprintf( __('Updates %s'), "<span class='update-plugins count-{$update_data['counts']['total']}'><span class='update-count'>" . number_format_i18n($update_data['counts']['total']) . "</span></span>" ), $cap, 'update-core.php');
4346
unset( $cap );
4447
}

src/wp-admin/network/settings.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
);
6464

6565
// Handle translation install.
66-
if ( ! empty( $_POST['WPLANG'] ) && wp_can_install_language_pack() ) { // @todo: Skip if already installed
66+
if ( ! empty( $_POST['WPLANG'] ) && current_user_can( 'install_languages' ) ) {
6767
$language = wp_download_language_pack( $_POST['WPLANG'] );
6868
if ( $language ) {
6969
$_POST['WPLANG'] = $language;
@@ -342,7 +342,7 @@
342342
'selected' => $lang,
343343
'languages' => $languages,
344344
'translations' => $translations,
345-
'show_available_translations' => wp_can_install_language_pack(),
345+
'show_available_translations' => current_user_can( 'install_languages' ),
346346
) );
347347
?>
348348
</td>

src/wp-admin/network/site-new.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@
6666
if ( isset( $_POST['WPLANG'] ) ) {
6767
if ( '' === $_POST['WPLANG'] ) {
6868
$meta['WPLANG'] = ''; // en_US
69-
} elseif ( wp_can_install_language_pack() ) {
69+
} elseif ( in_array( $_POST['WPLANG'], get_available_languages() ) ) {
70+
$meta['WPLANG'] = $_POST['WPLANG'];
71+
} elseif ( current_user_can( 'install_languages' ) ) {
7072
$language = wp_download_language_pack( wp_unslash( $_POST['WPLANG'] ) );
7173
if ( $language ) {
7274
$meta['WPLANG'] = $language;
@@ -234,7 +236,7 @@
234236
'selected' => $lang,
235237
'languages' => $languages,
236238
'translations' => $translations,
237-
'show_available_translations' => wp_can_install_language_pack(),
239+
'show_available_translations' => current_user_can( 'install_languages' ),
238240
) );
239241
?>
240242
</td>

src/wp-admin/options-general.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@
151151
'selected' => $locale,
152152
'languages' => $languages,
153153
'translations' => $translations,
154-
'show_available_translations' => ( ! is_multisite() || is_super_admin() ) && wp_can_install_language_pack(),
154+
'show_available_translations' => current_user_can( 'install_languages' ),
155155
) );
156156

157157
// Add note about deprecated WPLANG constant.

src/wp-admin/options.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,12 @@
177177
}
178178

179179
// Handle translation install.
180-
if ( ! empty( $_POST['WPLANG'] ) && ( ! is_multisite() || is_super_admin() ) ) { // @todo: Skip if already installed
180+
if ( ! empty( $_POST['WPLANG'] ) && current_user_can( 'install_languages' ) ) {
181181
require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
182182

183-
if ( wp_can_install_language_pack() ) {
184-
$language = wp_download_language_pack( $_POST['WPLANG'] );
185-
if ( $language ) {
186-
$_POST['WPLANG'] = $language;
187-
}
183+
$language = wp_download_language_pack( $_POST['WPLANG'] );
184+
if ( $language ) {
185+
$_POST['WPLANG'] = $language;
188186
}
189187
}
190188
}

src/wp-admin/update-core.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
exit();
2020
}
2121

22-
if ( ! current_user_can( 'update_core' ) && ! current_user_can( 'update_themes' ) && ! current_user_can( 'update_plugins' ) )
22+
if ( ! current_user_can( 'update_core' ) && ! current_user_can( 'update_themes' ) && ! current_user_can( 'update_plugins' ) && ! current_user_can( 'update_languages' ) )
2323
wp_die( __( 'Sorry, you are not allowed to update this site.' ) );
2424

2525
/**
@@ -608,15 +608,19 @@ function do_undismiss_core_update() {
608608
echo ' &nbsp; <a class="button" href="' . esc_url( self_admin_url('update-core.php?force-check=1') ) . '">' . __( 'Check Again' ) . '</a>';
609609
echo '</p>';
610610

611-
if ( $core = current_user_can( 'update_core' ) )
611+
if ( current_user_can( 'update_core' ) ) {
612612
core_upgrade_preamble();
613-
if ( $plugins = current_user_can( 'update_plugins' ) )
613+
}
614+
if ( current_user_can( 'update_plugins' ) ) {
614615
list_plugin_updates();
615-
if ( $themes = current_user_can( 'update_themes' ) )
616+
}
617+
if ( current_user_can( 'update_themes' ) ) {
616618
list_theme_updates();
617-
if ( $core || $plugins || $themes )
619+
}
620+
if ( current_user_can( 'update_languages' ) ) {
618621
list_translation_updates();
619-
unset( $core, $plugins, $themes );
622+
}
623+
620624
/**
621625
* Fires after the core, plugin, and theme update tables.
622626
*
@@ -729,7 +733,7 @@ function do_undismiss_core_update() {
729733

730734
} elseif ( 'do-translation-upgrade' == $action ) {
731735

732-
if ( ! current_user_can( 'update_core' ) && ! current_user_can( 'update_plugins' ) && ! current_user_can( 'update_themes' ) )
736+
if ( ! current_user_can( 'update_languages' ) )
733737
wp_die( __( 'Sorry, you are not allowed to update this site.' ) );
734738

735739
check_admin_referer( 'upgrade-translations' );

src/wp-includes/capabilities.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,20 @@ function map_meta_cap( $cap, $user_id ) {
392392
$caps[] = $cap;
393393
}
394394
break;
395+
case 'install_languages':
396+
case 'update_languages':
397+
if ( ! function_exists( 'wp_can_install_language_pack' ) ) {
398+
require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
399+
}
400+
401+
if ( ! wp_can_install_language_pack() ) {
402+
$caps[] = 'do_not_allow';
403+
} elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
404+
$caps[] = 'do_not_allow';
405+
} else {
406+
$caps[] = 'install_languages';
407+
}
408+
break;
395409
case 'activate_plugins':
396410
$caps[] = $cap;
397411
if ( is_multisite() ) {
@@ -826,3 +840,22 @@ function revoke_super_admin( $user_id ) {
826840
}
827841
return false;
828842
}
843+
844+
/**
845+
* Filters the user capabilities to grant the 'install_languages' capability as necessary.
846+
*
847+
* A user must have at least one out of the 'update_core', 'install_plugins', and
848+
* 'install_themes' capabilities to qualify for 'install_languages'.
849+
*
850+
* @since 4.9.0
851+
*
852+
* @param array $allcaps An array of all the user's capabilities.
853+
* @return array Filtered array of the user's capabilities.
854+
*/
855+
function wp_maybe_grant_install_languages_cap( $allcaps ) {
856+
if ( ! empty( $allcaps['update_core'] ) || ! empty( $allcaps['install_plugins'] ) || ! empty( $allcaps['install_themes'] ) ) {
857+
$allcaps['install_languages'] = true;
858+
}
859+
860+
return $allcaps;
861+
}

src/wp-includes/default-filters.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,4 +512,7 @@
512512
add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 );
513513
add_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10, 3 );
514514

515+
// Capabilities
516+
add_filter( 'user_has_cap', 'wp_maybe_grant_install_languages_cap', 1 );
517+
515518
unset( $filter, $action );

tests/phpunit/tests/user/capabilities.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ final private function _getSingleSiteMetaCaps() {
233233
'upload_themes' => array( 'administrator' ),
234234
'customize' => array( 'administrator' ),
235235
'add_users' => array( 'administrator' ),
236+
'install_languages' => array( 'administrator' ),
237+
'update_languages' => array( 'administrator' ),
236238

237239
'edit_categories' => array( 'administrator', 'editor' ),
238240
'delete_categories' => array( 'administrator', 'editor' ),
@@ -261,6 +263,8 @@ final private function _getMultiSiteMetaCaps() {
261263
'upload_themes' => array(),
262264
'edit_css' => array(),
263265
'upgrade_network' => array(),
266+
'install_languages' => array(),
267+
'update_languages' => array(),
264268

265269
'customize' => array( 'administrator' ),
266270
'delete_site' => array( 'administrator' ),

0 commit comments

Comments
 (0)