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

Use a single WordPress.org API request to get information for all plugins #1562

Merged

Conversation

narenin
Copy link
Contributor

@narenin narenin commented Sep 25, 2024

Summary

In this PR we have implemented a single WordPress.org API request to get plugin information because currently, the Performance features screen makes individual plugin_information queries to the WordPress.org API, which is rather inefficient, especially the more plugins we have.

https://api.wordpress.org/plugins/info/1.2/?action=query_plugins&request[author]=wordpressdotorg&request[tag]=performance&request[per_page]=100

Fixes #1542

Relevant technical choices

Copy link

github-actions bot commented Sep 25, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: narenin <[email protected]>
Co-authored-by: westonruter <[email protected]>
Co-authored-by: felixarntz <[email protected]>
Co-authored-by: mukeshpanchal27 <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@westonruter westonruter added [Type] Enhancement A suggestion for improvement of an existing feature [Plugin] Performance Lab Issue relates to work in the Performance Lab Plugin only labels Sep 25, 2024
@westonruter westonruter added this to the performance-lab n.e.x.t milestone Sep 25, 2024
'download_link',
'version', // Needed by install_plugin_install_status().
);
$request = wp_remote_get( 'https://api.wordpress.org/plugins/info/1.2/?action=query_plugins&request[author]=wordpressdotorg&request[tag]=performance&request[per_page]=100' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use plugins_api() here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter Thanks for reviewing this PR. I have not used plugins_api() because this does not support passing multiple specific slugs (which would be ideal) . Please let me know if I am missing anything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plugins_api() is a wrapper for any API calls to https://api.wordpress.org/plugins/, so you can use it here too. It's only the API itself that doesn't support passing multiple specific slugs, but we're not doing that here anyway.

You can call the plugins_api() function with the query_plugins action and provide the relevant request arguments.

Copy link
Member

@westonruter westonruter Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to work fine:

$response = plugins_api(
	'query_plugins',
	array(
		'author'   => 'wordpressdotorg',
		'tag'      => 'performance',
		'per_page' => 100,
	)
);

I can see that $response->plugins is populated as expected.

Copy link
Contributor Author

@narenin narenin Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@felixarntz @westonruter Thanks for the feedback, I have implemented the same.

Comment on lines 31 to 32
if ( is_wp_error( $request ) ) {
return new WP_Error( 'api_error', __( 'Failed to retrieve plugins data from WordPress.org API.', 'default' ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the error being returned would be passed through.

This string isn't actually part of core, right? So default can't be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have corrected the same, please check.


if ( is_wp_error( $plugin ) ) {
return $plugin;
if ( is_wp_error( $request ) ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better variable name would be $response, right? But I think plugins_api() should be used instead in any case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter I have corrected the same please check.

$data = json_decode( $body, true );

if ( ! isset( $data['plugins'] ) || ! is_array( $data['plugins'] ) ) {
return new WP_Error( 'no_plugins', __( 'No plugins found in the API response.', 'default' ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, is this string actually found in core? If not, then default cannot be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter This has been fixed.

'download_link',
'version', // Needed by install_plugin_install_status().
);
if ( is_array( $plugins ) && isset( $plugins[ $plugin_slug ] ) ) {
Copy link
Member

@felixarntz felixarntz Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second check here is problematic. We can't check that in the same clause, otherwise a missing plugin will lead to endless re-issuing of the API request and bypassing the cache.

If the cache data is an array, we know it's a cache hit. So then we need to check on that data if the $plugin_slug is not set, and if not return the same error as below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@felixarntz I have implemented this, could you please take a look.

@narenin
Copy link
Contributor Author

narenin commented Sep 25, 2024

@westonruter @felixarntz I have implemented the feedbacks, could you please take a look and share your valuable feedback on this.

Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor point in comment styles

plugins/performance-lab/includes/admin/plugins.php Outdated Show resolved Hide resolved
}

if ( is_object( $plugin ) ) {
$plugin = (array) $plugin;
/* Check if the response contains plugins. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* Check if the response contains plugins. */
// Check if the response contains plugins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter Thanks for the feedback, I have implemented this one.

Copy link
Member

@felixarntz felixarntz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@narenin This looks almost good to go. A few last notes.

plugins/performance-lab/includes/admin/plugins.php Outdated Show resolved Hide resolved
plugins/performance-lab/includes/admin/plugins.php Outdated Show resolved Hide resolved
Comment on lines 74 to 77
// Ensure the 'requires_plugins' is always an array.
if ( ! isset( $plugin_info['requires_plugins'] ) || ! is_array( $plugin_info['requires_plugins'] ) ) {
$plugin_info['requires_plugins'] = array();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this code needed? Right below the if $plugin_info['requires_plugins'] is not set, then it is set to false, which will then never occur. Apparently this if statement could be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 70 to 84
$plugins = array();
foreach ( $response->plugins as $plugin_data ) {
$plugin_info = wp_array_slice_assoc( $plugin_data, $fields );

// Ensure the 'requires_plugins' is always an array.
if ( ! isset( $plugin_info['requires_plugins'] ) || ! is_array( $plugin_info['requires_plugins'] ) ) {
$plugin_info['requires_plugins'] = array();
}

// Make sure all fields default to false in case another plugin is modifying the response from WordPress.org via the plugins_api filter.
$plugin = array_merge( array_fill_keys( $fields, false ), $plugin );
// Ensure 'requires' and 'requires_php' are either strings or false.
$plugin_info['requires'] = isset( $plugin_info['requires'] ) ? $plugin_info['requires'] : false;
$plugin_info['requires_php'] = isset( $plugin_info['requires_php'] ) ? $plugin_info['requires_php'] : false;

set_transient( 'perflab_plugin_info_' . $plugin_slug, $plugin, HOUR_IN_SECONDS );
$plugins[ $plugin_data['slug'] ] = $plugin_info;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be the equivalent of the existing code:

	$plugins = array();
	foreach ( $response->plugins as $plugin_data ) {
		$plugins[ $plugin_data['slug'] ] = wp_array_slice_assoc( $plugin_data, $fields );
	}

I'm curious why the additional requires and requires_php checks are now present?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@narenin
Copy link
Contributor Author

narenin commented Sep 27, 2024

@westonruter thanks for the suggestions, I have implemented them, please take a look.

Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Member

@felixarntz felixarntz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@narenin Thank you for the PR, this looks great!

@felixarntz felixarntz merged commit ddf297d into WordPress:trunk Sep 27, 2024
18 of 20 checks passed
@felixarntz felixarntz changed the title Implemented single WordPress.org API request to get plugin information Use a single WordPress.org API request to get information for all plugins Sep 27, 2024
@narenin
Copy link
Contributor Author

narenin commented Sep 27, 2024

Thanks @westonruter @felixarntz for your continuous feedback and support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Plugin] Performance Lab Issue relates to work in the Performance Lab Plugin only [Type] Enhancement A suggestion for improvement of an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use a single WordPress.org API request to get plugin information
3 participants