Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect language installation status when plugin's slug is different from its text domain #136

Open
2 tasks done
mrcasual opened this issue Dec 1, 2023 · 4 comments
Open
2 tasks done

Comments

@mrcasual
Copy link

mrcasual commented Dec 1, 2023

Bug Report

Describe the current, buggy behavior

When listing available languages for a plugin using the wp language plugin list <plugin> command, the status is always uninstalled if the plugin's slug ≠ plugin's text domain.

This is due to the wp_get_installed_translations() method used in

protected function get_installed_languages( $slug = 'default' ) {
$available = wp_get_installed_translations( $this->obj_type );
$available = ! empty( $available[ $slug ] ) ? array_keys( $available[ $slug ] ) : array();
$available[] = 'en_US';
return $available;
}

wp_get_installed_translations() returns an array keyed by the text domain. As a result, the subsequent check for available languages ($available = ! empty( $available[ $slug ] ) ? array_keys( $available[ $slug ] ) : array();) results in an empty array if the plugin's slug is different from its text domain.

get_installed_languages() is used by the list command:

public function list_( $args, $assoc_args ) {
$all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false );
if ( ! $all && empty( $args ) ) {
WP_CLI::error( 'Please specify one or more plugins, or use --all.' );
}
if ( $all ) {
$args = array_map( '\WP_CLI\Utils\get_plugin_name', array_keys( $this->get_all_plugins() ) );
if ( empty( $args ) ) {
WP_CLI::success( 'No plugins installed.' );
return;
}
}
$updates = $this->get_translation_updates();
$current_locale = get_locale();
$translations = array();
$plugins = new \WP_CLI\Fetchers\Plugin();
foreach ( $args as $plugin ) {
if ( ! $plugins->get( $plugin ) ) {
WP_CLI::warning( "Plugin '{$plugin}' not found." );
continue;
}
$installed_translations = $this->get_installed_languages( $plugin );
$available_translations = $this->get_all_languages( $plugin );
foreach ( $available_translations as $translation ) {
$translation['plugin'] = $plugin;
$translation['status'] = in_array( $translation['language'], $installed_translations, true ) ? 'installed' : 'uninstalled';
if ( $current_locale === $translation['language'] ) {
$translation['status'] = 'active';
}
$filter_args = array(
'language' => $translation['language'],
'type' => 'plugin',
'slug' => $plugin,
);
$update = wp_list_filter( $updates, $filter_args );
$translation['update'] = $update ? 'available' : 'none';
// Support features like --status=active.
foreach ( array_keys( $translation ) as $field ) {
if ( isset( $assoc_args[ $field ] ) && $assoc_args[ $field ] !== $translation[ $field ] ) {
continue 2;
}
}
$translations[] = $translation;
}
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_items( $translations );
}

That's where the following check (against an empty $installed_translations array returned by get_installed_languages()) results in the uninstalled value:

$translation['status'] = in_array( $translation['language'], $installed_translations, true ) ? 'installed' : 'uninstalled';

A solution is to account for the discrepancy between plugin slugs and text domains in the get_installed_languages() method.

@swissspidy
Copy link
Member

Can you give an example of a plugin where this is happening?

How would WP-CLI know what the correct text domain would be for the plugin?

WordPress plugins are really meant to have matching slugs and text domains. If they don't match, this kind of situation is to be expected. I assume WordPress itself also doesn't recognize the translations as being installed in that case.

@mrcasual
Copy link
Author

mrcasual commented Dec 2, 2023

I assume WordPress itself also doesn't recognize the translations as being installed in that case.

It does because it relies on the text domain, not the plugin slug.

Can you give an example of a plugin where this is happening?

It can happen with any plugin if it's placed in a folder that doesn't match its text domain. For example, install Gravity Forms, rename the gravityforms folder to gfforms, and you will see an issue.

How would WP-CLI know what the correct text domain would be for the plugin?

Something like this:

$slug_to_text_domain_map = [];

foreach ( get_plugins() as $plugin_file => $plugin_data ) {
	$slug_to_text_domain_map[ dirname( $plugin_file ) ] = $plugin_data['TextDomain'];
}

@swissspidy
Copy link
Member

It does because it relies on the text domain, not the plugin slug.

For loading, yes, but for updates I don't think WP has any such logic. At least I can't find it.

Looking at the Text Domain header sounds like an interesting hardening step, but also a bit unusual because of that.

@mrcasual
Copy link
Author

mrcasual commented Dec 2, 2023

By the way, updating translations via WP CLI doesn't work since get_translations_update() also uses the get_installed_languages() method. Similarly, the update status is always none. Installation works just fine though except the status that always shows uninstalled (i.e., the issue at hand).

Anyway, this is an easy fix. Thanks for looking into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants