diff --git a/inc/packages/admin/info.php b/inc/packages/admin/info.php index d42610b6..fbc6255f 100644 --- a/inc/packages/admin/info.php +++ b/inc/packages/admin/info.php @@ -124,7 +124,7 @@ function render_page( MetadataDocument $metadata, string $tab, string $section ) * @param string $section Page section. */ function render( MetadataDocument $doc, string $tab, string $section ) { - $sections = (array) $doc->sections; + $sections = Admin\order_sections_by_predefined_order( (array) $doc->sections ); if ( ! isset( $sections[ $section ] ) ) { $section = array_keys( $sections )[0]; diff --git a/inc/packages/admin/namespace.php b/inc/packages/admin/namespace.php index b7ff2093..075d8d0a 100644 --- a/inc/packages/admin/namespace.php +++ b/inc/packages/admin/namespace.php @@ -12,6 +12,7 @@ use FAIR\Packages\MetadataDocument; use FAIR\Packages\ReleaseDocument; use FAIR\Updater; +use WP_Error; const TAB_DIRECT = 'fair_direct'; const ACTION_INSTALL = 'fair-install-plugin'; @@ -34,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__ . '\\order_plugin_information_sections', 11, 2 ); 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' ); @@ -450,6 +452,53 @@ function alter_slugs( $res, $action, $args ) { return $res; } +/** + * Order the sections of Plugin Installation API response. + * + * @param object|WP_Error $res Response object or WP_Error. + * @param string $action The type of information being requested from the Plugin Installation API. + */ +function order_plugin_information_sections( $res, $action ) { + if ( is_wp_error( $res ) || 'plugin_information' !== $action || empty( $res->sections ) ) { + return $res; + } + + $res->sections = order_sections_by_predefined_order( $res->sections ); + + return $res; +} + +/** + * Order sections by a predefined order. + * + * @param array $sections Sections to order. + * + * @return array Ordered sections. + */ +function order_sections_by_predefined_order( array $sections ) : array { + $desired_order = [ + 'description', + 'installation', + 'faq', + 'screenshots', + 'changelog', + 'security', + 'reviews', + 'other_notes', + ]; + + $desired_order_index = array_flip( $desired_order ); + + uksort($sections, function( $a, $b ) use ( $desired_order_index ) { + $pos_a = $desired_order_index[ $a ] ?? PHP_INT_MAX; + $pos_b = $desired_order_index[ $b ] ?? PHP_INT_MAX; + + return $pos_a <=> $pos_b; + }); + + return $sections; +} + /** * Override the install button, for bridged plugins. * diff --git a/tests/phpunit/tests/Packages/Admin/OrderSectionsByPredefinedOrderTest.php b/tests/phpunit/tests/Packages/Admin/OrderSectionsByPredefinedOrderTest.php new file mode 100644 index 00000000..3427d789 --- /dev/null +++ b/tests/phpunit/tests/Packages/Admin/OrderSectionsByPredefinedOrderTest.php @@ -0,0 +1,99 @@ +assertSame( + $expected_order, + order_sections_by_predefined_order( $sections ) + ); + } + + /** + * Data provider. + */ + public static function data_plugin_detail_sections(): array { + return [ + 'expected sections' => [ + 'sections' => [ + 'faq' => '', + 'screenshots' => '', + 'changelog' => '', + 'description' => '', + 'security' => '', + 'reviews' => '', + 'other_notes' => '', + 'installation' => '', + ], + 'expected_order' => [ + 'description' => '', + 'installation' => '', + 'faq' => '', + 'screenshots' => '', + 'changelog' => '', + 'security' => '', + 'reviews' => '', + 'other_notes' => '', + ], + ], + 'unknown sections' => [ + 'sections' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], + 'expected_order' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], + ], + 'expected and unknown sections' => [ + 'sections' => [ + 'faq' => '', + 'foo' => '', + 'screenshots' => '', + 'changelog' => '', + 'bar' => '', + 'reviews' => '', + 'installation' => '', + 'security' => '', + ], + 'expected_order' => [ + 'installation' => '', + 'faq' => '', + 'screenshots' => '', + 'changelog' => '', + 'security' => '', + 'reviews' => '', + 'foo' => '', + 'bar' => '', + ], + ], + 'empty sections' => [ + 'sections' => [], + 'expected_order' => [], + ], + ]; + } +}