diff --git a/src/wp-admin/includes/template.php b/src/wp-admin/includes/template.php index 418bfd7def697..a67a1769eb163 100644 --- a/src/wp-admin/includes/template.php +++ b/src/wp-admin/includes/template.php @@ -904,6 +904,8 @@ function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) { * * @since 1.5.0 * @since 4.7.0 Added the `$post_type` parameter. + * @since 7.2.0 Templates are no longer re-sorted here; the order from + * WP_Theme::get_post_templates() (by translated name) is preserved. * * @param string $default_template Optional. The template file name. Default empty. * @param string $post_type Optional. Post type to get templates for. Default 'page'. @@ -911,8 +913,6 @@ function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) { function page_template_dropdown( $default_template = '', $post_type = 'page' ) { $templates = get_page_templates( null, $post_type ); - ksort( $templates ); - foreach ( array_keys( $templates ) as $template ) { $selected = selected( $default_template, $templates[ $template ], false ); echo "\n\t'; diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index 6a18e7a534daa..ae64ac8d228ae 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -1320,6 +1320,7 @@ public function get_files( $type = null, $depth = 0, $search_parent = false ) { * * @since 4.7.0 * @since 5.8.0 Include block templates. + * @since 7.2.0 Templates are sorted by their translated name. * * @return array[] Array of page template arrays, keyed by post type and filename, * with the value of the translated header name. @@ -1392,8 +1393,15 @@ public function get_post_templates() { $post_template = $this->translate_header( 'Template Name', $post_template ); } } + unset( $post_type, $post_template ); } + // Sort each post type's templates by their translated name, keeping the file names as keys. + foreach ( $post_templates as &$post_type ) { + uasort( $post_type, 'strnatcasecmp' ); + } + unset( $post_type ); + return $post_templates; } diff --git a/tests/phpunit/data/themedir1/page-templates-sort/a-template.php b/tests/phpunit/data/themedir1/page-templates-sort/a-template.php new file mode 100644 index 0000000000000..f2fefd9456e9e --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/a-template.php @@ -0,0 +1,5 @@ + diff --git a/tests/phpunit/data/themedir1/page-templates-sort/b-template.php b/tests/phpunit/data/themedir1/page-templates-sort/b-template.php new file mode 100644 index 0000000000000..0adcd83fe489e --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/b-template.php @@ -0,0 +1,5 @@ + diff --git a/tests/phpunit/data/themedir1/page-templates-sort/c-template.php b/tests/phpunit/data/themedir1/page-templates-sort/c-template.php new file mode 100644 index 0000000000000..8d58782577cb5 --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/c-template.php @@ -0,0 +1,5 @@ + diff --git a/tests/phpunit/data/themedir1/page-templates-sort/index.php b/tests/phpunit/data/themedir1/page-templates-sort/index.php new file mode 100644 index 0000000000000..db70785b6ee11 --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/index.php @@ -0,0 +1,3 @@ + diff --git a/tests/phpunit/data/themedir1/page-templates-sort/section-10.php b/tests/phpunit/data/themedir1/page-templates-sort/section-10.php new file mode 100644 index 0000000000000..f55509cc3d537 --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/section-10.php @@ -0,0 +1,5 @@ + diff --git a/tests/phpunit/data/themedir1/page-templates-sort/section-2.php b/tests/phpunit/data/themedir1/page-templates-sort/section-2.php new file mode 100644 index 0000000000000..3107edb2ff8c8 --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/section-2.php @@ -0,0 +1,5 @@ + diff --git a/tests/phpunit/data/themedir1/page-templates-sort/style.css b/tests/phpunit/data/themedir1/page-templates-sort/style.css new file mode 100644 index 0000000000000..72a34c67a5987 --- /dev/null +++ b/tests/phpunit/data/themedir1/page-templates-sort/style.css @@ -0,0 +1,11 @@ +/* +Theme Name: Page Template Sorting Theme +Theme URI: http://example.org/ +Description: An example theme for testing that page templates are sorted by name. +Version: 0.1 +Author: Mr. WordPress +Author URI: http://wordpress.org/ + +This is just a stub to test that get_post_templates() sorts by the template name. + +*/ diff --git a/tests/phpunit/tests/admin/includesTemplate.php b/tests/phpunit/tests/admin/includesTemplate.php index 4b9b8bc68034e..a402971e225ce 100644 --- a/tests/phpunit/tests/admin/includesTemplate.php +++ b/tests/phpunit/tests/admin/includesTemplate.php @@ -547,4 +547,32 @@ public function data_get_submit_button_shorthand() { 'raw button-compact unchanged' => array( 'button-compact', 'button button-compact' ), ); } + + /** + * The template drop-down should list options in the order provided by + * WP_Theme::get_post_templates() (by translated name), not re-sort them. + * + * @ticket 49194 + * + * @covers ::page_template_dropdown + */ + public function test_page_template_dropdown_preserves_name_order() { + $current_theme = wp_get_theme(); + switch_theme( 'page-templates-sort' ); + + ob_start(); + page_template_dropdown( '', 'page' ); + $output = ob_get_clean(); + + switch_theme( $current_theme->get_stylesheet() ); + + // Options follow the translated name order from WP_Theme::get_post_templates(). + $expected = "\n\t"; + $expected .= "\n\t"; + $expected .= "\n\t"; + $expected .= "\n\t"; + $expected .= "\n\t"; + + $this->assertSameIgnoreEOL( $expected, $output ); + } } diff --git a/tests/phpunit/tests/theme/themeDir.php b/tests/phpunit/tests/theme/themeDir.php index a953a04bc5533..f4f3dd10af490 100644 --- a/tests/phpunit/tests/theme/themeDir.php +++ b/tests/phpunit/tests/theme/themeDir.php @@ -169,6 +169,7 @@ public function test_theme_list() { 'My Subdir Theme', // Theme in a subdirectory should work. 'Page Template Child Theme', // Theme which inherits page templates. 'Page Template Theme', // Theme with page templates for other test code. + 'Page Template Sorting Theme', // Theme for testing page templates are sorted by name. 'Theme with Spaces in the Directory', 'Internationalized Theme', 'Custom Internationalized Theme', diff --git a/tests/phpunit/tests/theme/wpThemeGetPostTemplates.php b/tests/phpunit/tests/theme/wpThemeGetPostTemplates.php index 9a4775124cdbf..5fdb348ffc5fb 100644 --- a/tests/phpunit/tests/theme/wpThemeGetPostTemplates.php +++ b/tests/phpunit/tests/theme/wpThemeGetPostTemplates.php @@ -117,4 +117,29 @@ public function test_get_post_templates_uses_get_file_data() { // Verify the `extra_theme_headers` filter is called. $this->assertGreaterThan( 0, $filter->get_call_count(), 'The `extra_theme_headers` filter should be called at least once.' ); } + + /** + * Templates should be ordered by their human-readable name, not by the file name. + * + * @ticket 49194 + */ + public function test_get_post_templates_are_sorted_by_name() { + $theme = wp_get_theme( 'page-templates-sort' ); + $this->assertNotEmpty( $theme ); + + $post_templates = $theme->get_post_templates(); + $this->assertArrayHasKey( 'page', $post_templates ); + + // Templates are sorted by name (case-insensitive, natural order), keeping the file names as keys. + $this->assertSame( + array( + 'c-template.php' => 'Apple Template', + 'b-template.php' => 'mango template', + 'section-2.php' => 'Section 2', + 'section-10.php' => 'Section 10', + 'a-template.php' => 'Zebra Template', + ), + $post_templates['page'] + ); + } }