From 95ce19a49a461f6d04d5946c1e6e8e68bba15c5d Mon Sep 17 00:00:00 2001 From: Andy Fragen Date: Thu, 30 Oct 2025 10:51:11 -0700 Subject: [PATCH 1/6] sort plugin modal tabs Signed-off-by: Andy Fragen Fixes #279 --- inc/packages/admin/namespace.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 6b62a69a..8b9b27b5 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -35,6 +35,7 @@ function bootstrap() { add_action( 'load-plugin-install.php', __NAMESPACE__ . '\\load_plugin_install' ); add_action( 'install_plugins_pre_plugin-information', __NAMESPACE__ . '\\maybe_hijack_plugin_info', 0 ); add_filter( 'plugins_api_result', __NAMESPACE__ . '\\alter_slugs', 10, 3 ); + add_filter( 'plugins_api_result', __NAMESPACE__ . '\\sort_sections_in_api', 15, 1 ); add_filter( 'plugin_install_action_links', __NAMESPACE__ . '\\maybe_hijack_plugin_install_button', 10, 2 ); add_filter( 'plugin_install_description', __NAMESPACE__ . '\\maybe_add_data_to_description', 10, 2 ); add_action( 'wp_ajax_check_plugin_dependencies', __NAMESPACE__ . '\\set_slug_to_hashed' ); @@ -427,6 +428,32 @@ function alter_slugs( $res, $action, $args ) { return $res; } +/** + * Sort plugin modal tabs. + * + * Based on standard tab listing order. + * + * @param object|WP_Error $res Response object or WP_Error. + * @return object|WP_Error + */ +function sort_sections_in_api( $res ) { + $ordered_sections = [ + 'description', + 'installation', + 'faq', + 'screenshots', + 'changelog', + 'upgrade_notice', + 'other_notes', + ]; + if ( property_exists( $res, 'sections' ) ) { + $properly_ordered = array_merge( array_fill_keys( $ordered_sections, '' ), $res->sections ); + $res->sections = array_filter( $properly_ordered ); + } + + return $res; +} + /** * Override the install button, for bridged plugins. * From 707e5e138872c32f58c578c2e7c8215783213cd0 Mon Sep 17 00:00:00 2001 From: Andy Fragen Date: Thu, 30 Oct 2025 19:01:57 -0700 Subject: [PATCH 2/6] add additional sections Signed-off-by: Andy Fragen --- inc/packages/admin/namespace.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 8b9b27b5..808b07f3 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -444,7 +444,9 @@ function sort_sections_in_api( $res ) { 'screenshots', 'changelog', 'upgrade_notice', + 'security', 'other_notes', + 'reviews', ]; if ( property_exists( $res, 'sections' ) ) { $properly_ordered = array_merge( array_fill_keys( $ordered_sections, '' ), $res->sections ); From d2f7864e755aeded46276b43eb12f7f587a16f53 Mon Sep 17 00:00:00 2001 From: Andy Fragen Date: Thu, 30 Oct 2025 19:13:44 -0700 Subject: [PATCH 3/6] add tests, borrowed liberally from @meszarosrob Signed-off-by: Andy Fragen --- inc/packages/admin/namespace.php | 2 +- .../Packages/Admin/SortSectionsInApiTest.php | 107 ++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index 808b07f3..e120fdaf 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -453,7 +453,7 @@ function sort_sections_in_api( $res ) { $res->sections = array_filter( $properly_ordered ); } - return $res; + return $res; } /** diff --git a/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php b/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php new file mode 100644 index 00000000..96266065 --- /dev/null +++ b/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php @@ -0,0 +1,107 @@ +sections = $sections; + $actual = sort_sections_in_api( $res ); + $this->assertIsObject( $actual, 'The response is not an object.' ); + // $this->assertObjectHasProperty( 'sections', $actual, 'The response object has no sections.' ); + $this->assertSame( + $expected_order, + $actual->sections, + 'The sections were not in the expected order.' + ); + } + + /** + * Data provider. + */ + public static function data_plugin_detail_sections(): array { + return [ + 'expected sections' => [ + 'sections' => [ + 'faq' => 'faq', + 'screenshots' => 'screenshots', + 'changelog' => 'changelog', + 'description' => 'description', + 'security' => 'security', + 'reviews' => 'reviews', + 'other_notes' => 'other_notes', + 'installation' => 'installation', + 'upgrade_notice' => 'upgrade_notice', + ], + 'expected_order' => [ + 'description' => 'description', + 'installation' => 'installation', + 'faq' => 'faq', + 'screenshots' => 'screenshots', + 'changelog' => 'changelog', + 'upgrade_notice' => 'upgrade_notice', + 'security' => 'security', + 'other_notes' => 'other_notes', + 'reviews' => 'reviews', + ], + ], + 'unknown sections' => [ + 'sections' => [ + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => 'baz', + ], + 'expected_order' => [ + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => 'baz', + ], + ], + 'expected and unknown sections' => [ + 'sections' => [ + 'faq' => 'faq', + 'foo' => 'foo', + 'screenshots' => 'screenshots', + 'changelog' => 'changelog', + 'bar' => 'bar', + 'reviews' => 'reviews', + 'installation' => 'installation', + 'security' => 'security', + ], + 'expected_order' => [ + 'installation' => 'installation', + 'faq' => 'faq', + 'screenshots' => 'screenshots', + 'changelog' => 'changelog', + 'security' => 'security', + 'reviews' => 'reviews', + 'foo' => 'foo', + 'bar' => 'bar', + ], + ], + 'empty sections' => [ + 'sections' => [], + 'expected_order' => [], + ], + ]; + } +} From 2b96148ce378115f0ae6a1ab5fca87cfa0e2bd3b Mon Sep 17 00:00:00 2001 From: Andy Fragen Date: Thu, 30 Oct 2025 22:14:29 -0700 Subject: [PATCH 4/6] sort sections in fetch_metadoc_doc for caching Signed-off-by: Andy Fragen --- inc/packages/namespace.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/inc/packages/namespace.php b/inc/packages/namespace.php index 469320f6..3b95fd5c 100644 --- a/inc/packages/namespace.php +++ b/inc/packages/namespace.php @@ -13,6 +13,7 @@ use FAIR\Packages\DID\PLC; use FAIR\Packages\DID\Web; use FAIR\Updater; +use function FAIR\Packages\Admin\sort_sections_in_api; use WP_Error; use WP_Upgrader; @@ -170,6 +171,14 @@ function fetch_metadata_doc( string $url ) { } elseif ( $code !== 200 ) { return new WP_Error( 'fair.packages.metadata.failure', __( 'HTTP error code received', 'fair' ) ); } + + // Reorder sections before caching. + $body = json_decode( $response['body'] ); + $body->sections = (array) $body->sections; + $body = sort_sections_in_api( $body ); + $body->sections = (object) $body->sections; + $response['body'] = json_encode( $body ); + set_transient( $cache_key, $response, CACHE_LIFETIME ); } From 5f5e2690ad9217a5665c69d92071ed35301e5637 Mon Sep 17 00:00:00 2001 From: Andy Fragen Date: Fri, 31 Oct 2025 06:25:18 -0700 Subject: [PATCH 5/6] additional guard Signed-off-by: Andy Fragen --- inc/packages/admin/namespace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index e120fdaf..7199664b 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -448,7 +448,7 @@ function sort_sections_in_api( $res ) { 'other_notes', 'reviews', ]; - if ( property_exists( $res, 'sections' ) ) { + if ( property_exists( $res, 'sections' ) && is_array( $res->sections ) ) { $properly_ordered = array_merge( array_fill_keys( $ordered_sections, '' ), $res->sections ); $res->sections = array_filter( $properly_ordered ); } From 1a67b127680e5d55e6dbc80087bbb8e037dbbfe1 Mon Sep 17 00:00:00 2001 From: Andy Fragen Date: Sat, 1 Nov 2025 18:11:20 -0700 Subject: [PATCH 6/6] add tests Signed-off-by: Andy Fragen --- .../Packages/Admin/SortSectionsInApiTest.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php b/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php index 96266065..0f78f21c 100644 --- a/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php +++ b/tests/phpunit/tests/Packages/Admin/SortSectionsInApiTest.php @@ -98,7 +98,23 @@ public static function data_plugin_detail_sections(): array { 'bar' => 'bar', ], ], - 'empty sections' => [ + 'some empty sections' => [ + 'sections' => [ + 'faq' => '', + 'foo' => '', + 'screenshots' => 'screenshots', + 'changelog' => '', + 'bar' => '', + 'reviews' => 'reviews', + 'installation' => '', + 'security' => '', + ], + 'expected_order' => [ + 'screenshots' => 'screenshots', + 'reviews' => 'reviews', + ], + ], + 'no sections' => [ 'sections' => [], 'expected_order' => [], ],