Skip to content

query_plugins returns full plugin-detail payloads, causing multi-megabyte responses and timeouts #84

Description

@kasparsd

Declaimer: used gpt-5.6-sol to create this issue out of debugging session around API response sizes while working on fairpm/fair-plugin#525

Summary

The WordPress-compatible plugins/info/1.2 endpoint returns excessively large responses for action=query_plugins.

A standard Add Plugins Featured-tab request currently returns approximately 3.37 MB from AspireCloud, compared with approximately 86 KB from WordPress.org. This can cause FAIR Connect's Add Plugins request to exceed WordPress's 15-second HTTP timeout on some hosts.

Reproduction

Request:

GET /plugins/info/1.2/
?action=query_plugins
&request[page]=1
&request[per_page]=36
&request[locale]=en_US
&request[browse]=featured
&request[wp_version]=6.8

Example endpoints:

  • AspireCloud: https://api.aspirecloud.net/plugins/info/1.2/
  • WordPress.org: https://api.wordpress.org/plugins/info/1.2/

Observed results

Measurements taken using the same request parameters:

API Plugins Response body
WordPress.org 8 85,831 characters
AspireCloud 36 3,368,723 characters

The AspireCloud response is approximately 39 times larger overall.

This is not explained only by the different result count. With per_page=8, AspireCloud returns approximately 710 KB, still about 8.3 times larger than the WordPress.org response containing 8 plugins.

Pagination also differs:

WordPress.org: page=1, pages=1, results=8
AspireCloud:   page=1, pages=31, results=1089

Cause

QueryPluginsService currently maps every listing result to the full PluginResponse:

https://github.com/fairpm/aspirecloud/blob/main/app/Services/PluginServices/QueryPluginsService.php

PluginResponse::fromPlugin() includes both listing fields and fields intended for plugin_information:

https://github.com/fairpm/aspirecloud/blob/main/app/Values/WpOrg/Plugins/PluginResponse.php

Detail-only data included for every listing entry includes:

  • sections, including FAQ and review HTML
  • Complete versions maps
  • contributors
  • Structured screenshots
  • support_url
  • upgrade_notice
  • banners
  • Repository and commercial-support metadata
  • AspireCloud-specific metadata

Some plugins have hundreds of versions or large review and screenshot sections.

QueryPluginsRequest accepts fields, but QueryPluginsService does not apply it. Explicitly disabling versions, sections, screenshots, description, and contributors currently produces the same 3,368,723-character response.

The service also eagerly loads contributors for every listing result, even though WordPress.org does not include contributors in its default query_plugins response.

Expected behavior

query_plugins should return a compact listing representation comparable to WordPress.org.

Full plugin metadata should remain available through:

action=plugin_information

Explicit request[fields] values should also be honored.

Suggested implementation

  1. Introduce a dedicated QueryPluginResponse DTO containing only the fields needed for plugin listings.

  2. Continue using the existing full PluginResponse for plugin_information.

  3. Change QueryPluginsService to map results to QueryPluginResponse rather than PluginResponse.

  4. Normalize and apply QueryPluginsRequest::$fields, including associative values such as:

    request[fields][description]=false
    request[fields][versions]=false
    

    The theme API's ThemeFields/withFields() implementation may provide a useful pattern.

  5. Avoid eager-loading contributors for ordinary listing requests.

  6. Review browse=featured. It currently matches more than 1,000 plugins using rating/origin criteria, whereas WordPress.org returns a small curated set. If AspireCloud intentionally defines its own Featured collection, it should still be bounded appropriately.

  7. Ensure any response cache varies on request parameters, particularly fields, page, per_page, browse, locale, and WordPress version.

Tests

Add feature tests confirming that:

  • Default query_plugins responses omit detail-only fields such as versions, sections, contributors, screenshots, and banners.
  • plugin_information continues returning full details.
  • Explicitly disabled fields are omitted.
  • per_page and pagination remain correct.
  • The default listing response does not eagerly serialize full plugin metadata.
  • browse=featured returns the intended bounded collection.

Impact

This affects FAIR Connect's Add Plugins screen because it uses the standard WordPress query_plugins request with a 15-second timeout. Downloading and decoding a multi-megabyte response can result in http_request_failed/cURL timeout errors even when AspireCloud itself is reachable.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions