WordPress.org

Make WordPress Core

Ticket #18375: 18375.8.diff

File 18375.8.diff, 36.9 KB (added by swissspidy, 15 months ago)

Improve attachment support and body class handling

  • src/wp-admin/edit-form-advanced.php

    diff --git src/wp-admin/edit-form-advanced.php src/wp-admin/edit-form-advanced.php
    index 540f1ed..73cb63b 100644
    foreach ( get_object_taxonomies( $post ) as $tax_name ) { 
    259259        add_meta_box( $tax_meta_box_id, $label, $taxonomy->meta_box_cb, null, 'side', 'core', array( 'taxonomy' => $tax_name ) ); 
    260260} 
    261261 
    262 if ( post_type_supports($post_type, 'page-attributes') ) 
    263         add_meta_box('pageparentdiv', 'page' == $post_type ? __('Page Attributes') : __('Attributes'), 'page_attributes_meta_box', null, 'side', 'core'); 
     262if ( post_type_supports( $post_type, 'page-attributes' ) || count( get_page_templates( null, $post_type ) ) > 0 ) { 
     263        add_meta_box( 'pageparentdiv', $post_type_object->labels->attributes, 'page_attributes_meta_box', null, 'side', 'core' ); 
     264} 
    264265 
    265266if ( $thumbnail_support && current_user_can( 'upload_files' ) ) 
    266267        add_meta_box('postimagediv', esc_html( $post_type_object->labels->featured_image ), 'post_thumbnail_meta_box', null, 'side', 'low'); 
  • src/wp-admin/includes/class-wp-posts-list-table.php

    diff --git src/wp-admin/includes/class-wp-posts-list-table.php src/wp-admin/includes/class-wp-posts-list-table.php
    index 714a491..d26ab2f 100644
    class WP_Posts_List_Table extends WP_List_Table { 
    15281528                                <span class="input-text-wrap"><input type="text" name="menu_order" class="inline-edit-menu-order-input" value="<?php echo $post->menu_order ?>" /></span> 
    15291529                        </label> 
    15301530 
    1531         <?php   endif; // !$bulk 
    1532  
    1533                         if ( 'page' === $screen->post_type ) : 
    1534         ?> 
    1535  
    1536                         <label> 
    1537                                 <span class="title"><?php _e( 'Template' ); ?></span> 
    1538                                 <select name="page_template"> 
    1539         <?php   if ( $bulk ) : ?> 
    1540                                         <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option> 
    1541         <?php   endif; // $bulk ?> 
    1542                                 <?php 
    1543                                         /** This filter is documented in wp-admin/includes/meta-boxes.php */ 
    1544                                         $default_title = apply_filters( 'default_page_template_title',  __( 'Default Template' ), 'quick-edit' ); 
    1545                                 ?> 
    1546                                         <option value="default"><?php echo esc_html( $default_title ); ?></option> 
    1547                                         <?php page_template_dropdown() ?> 
    1548                                 </select> 
    1549                         </label> 
    1550  
    15511531        <?php 
    1552                         endif; // page post_type 
     1532                        endif; // !$bulk 
    15531533                endif; // page-attributes 
    15541534        ?> 
    15551535 
     1536        <?php if ( 0 < count( get_page_templates( null, $screen->post_type ) ) ) : ?> 
     1537                <label> 
     1538                        <span class="title"><?php _e( 'Template' ); ?></span> 
     1539                        <select name="page_template"> 
     1540<?php   if ( $bulk ) : ?> 
     1541                                <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option> 
     1542<?php   endif; // $bulk ?> 
     1543                <?php 
     1544                                /** This filter is documented in wp-admin/includes/meta-boxes.php */ 
     1545                                $default_title = apply_filters( 'default_page_template_title',  __( 'Default Template' ), 'quick-edit' ); 
     1546                ?> 
     1547                                <option value="default"><?php echo esc_html( $default_title ); ?></option> 
     1548                                <?php page_template_dropdown( $post->page_template, $screen->post_type ) ?> 
     1549                        </select> 
     1550                </label> 
     1551        <?php endif; ?> 
     1552 
    15561553        <?php if ( count( $flat_taxonomies ) && !$bulk ) : ?> 
    15571554 
    15581555        <?php foreach ( $flat_taxonomies as $taxonomy ) : ?> 
  • src/wp-admin/includes/meta-boxes.php

    diff --git src/wp-admin/includes/meta-boxes.php src/wp-admin/includes/meta-boxes.php
    index 48c5e37..13d463d 100644
    function post_revisions_meta_box( $post ) { 
    788788 * @param object $post 
    789789 */ 
    790790function page_attributes_meta_box($post) { 
    791         $post_type_object = get_post_type_object($post->post_type); 
    792         if ( $post_type_object->hierarchical ) { 
     791        if ( is_post_type_hierarchical( $post->post_type ) ) : 
    793792                $dropdown_args = array( 
    794793                        'post_type'        => $post->post_type, 
    795794                        'exclude_tree'     => $post->ID, 
    function page_attributes_meta_box($post) { 
    812811                 */ 
    813812                $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post ); 
    814813                $pages = wp_dropdown_pages( $dropdown_args ); 
    815                 if ( ! empty($pages) ) { 
     814                if ( ! empty($pages) ) : 
    816815?> 
    817816<p><strong><?php _e('Parent') ?></strong></p> 
    818817<label class="screen-reader-text" for="parent_id"><?php _e('Parent') ?></label> 
    819818<?php echo $pages; ?> 
    820819<?php 
    821                 } // end empty pages check 
    822         } // end hierarchical check. 
    823         if ( 'page' == $post->post_type && 0 != count( get_page_templates( $post ) ) && get_option( 'page_for_posts' ) != $post->ID ) { 
    824                 $template = !empty($post->page_template) ? $post->page_template : false; 
     820                endif; // end empty pages check 
     821        endif;  // end hierarchical check. 
     822 
     823        if ( count( get_page_templates( $post ) ) > 0 && get_option( 'page_for_posts' ) != $post->ID ) : 
     824                $template = ! empty( $post->page_template ) ? $post->page_template : false; 
    825825                ?> 
    826826<p><strong><?php _e('Template') ?></strong><?php 
    827827        /** 
    function page_attributes_meta_box($post) { 
    835835         */ 
    836836        do_action( 'page_attributes_meta_box_template', $template, $post ); 
    837837?></p> 
    838 <label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select name="page_template" id="page_template"> 
     838<label class="screen-reader-text" for="page_template"> 
     839        <?php 
     840        $post_type_object = get_post_type_object( $post->post_type ); 
     841        echo esc_html( $post_type_object->labels->attributes ); 
     842        ?> 
     843</label> 
     844<select name="page_template" id="page_template"> 
    839845<?php 
    840846/** 
    841847 * Filters the title of the default page template displayed in the drop-down. 
    function page_attributes_meta_box($post) { 
    849855$default_title = apply_filters( 'default_page_template_title',  __( 'Default Template' ), 'meta-box' ); 
    850856?> 
    851857<option value="default"><?php echo esc_html( $default_title ); ?></option> 
    852 <?php page_template_dropdown($template); ?> 
     858<?php page_template_dropdown( $template, $post->post_type ); ?> 
    853859</select> 
    854 <?php 
    855         } ?> 
     860<?php endif; ?> 
     861<?php if ( post_type_supports( $post->post_type, 'page-attributes' ) ) : ?> 
    856862<p><strong><?php _e('Order') ?></strong></p> 
    857863<p><label class="screen-reader-text" for="menu_order"><?php _e('Order') ?></label><input name="menu_order" type="text" size="4" id="menu_order" value="<?php echo esc_attr($post->menu_order) ?>" /></p> 
    858 <?php if ( 'page' == $post->post_type && get_current_screen()->get_help_tabs() ) { ?> 
     864<?php if ( 'page' == $post->post_type && get_current_screen()->get_help_tabs() ) : ?> 
    859865<p><?php _e( 'Need help? Use the Help tab above the screen title.' ); ?></p> 
    860 <?php 
    861         } 
     866<?php endif; 
     867        endif; 
    862868} 
    863869 
    864870// -- Link related Meta Boxes 
  • src/wp-admin/includes/template.php

    diff --git src/wp-admin/includes/template.php src/wp-admin/includes/template.php
    index cd4c00f..54bc4cf 100644
    function get_inline_data($post) { 
    293293        <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div> 
    294294        <div class="post_password">' . esc_html( $post->post_password ) . '</div>'; 
    295295 
    296         if ( $post_type_object->hierarchical ) 
     296        if ( $post_type_object->hierarchical ) { 
    297297                echo '<div class="post_parent">' . $post->post_parent . '</div>'; 
     298        } 
    298299 
    299         if ( $post->post_type == 'page' ) 
    300                 echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>'; 
     300        echo '<div class="page_template">' . esc_html( $post->page_template ) . '</div>'; 
    301301 
    302         if ( post_type_supports( $post->post_type, 'page-attributes' ) ) 
     302        if ( post_type_supports( $post->post_type, 'page-attributes' ) ) { 
    303303                echo '<div class="menu_order">' . $post->menu_order . '</div>'; 
     304        } 
    304305 
    305306        $taxonomy_names = get_object_taxonomies( $post->post_type ); 
    306307        foreach ( $taxonomy_names as $taxonomy_name) { 
    function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) { 
    761762 * Print out option HTML elements for the page templates drop-down. 
    762763 * 
    763764 * @since 1.5.0 
     765 * @since 4.7.0 Added the `$post_type` parameter. 
    764766 * 
    765  * @param string $default Optional. The template file name. Default empty. 
     767 * @param string $default   Optional. The template file name. Default empty. 
     768 * @param string $post_type Optional. Post type to get templates for. Default 'post'. 
    766769 */ 
    767 function page_template_dropdown( $default = '' ) { 
    768         $templates = get_page_templates( get_post() ); 
     770function page_template_dropdown( $default = '', $post_type = 'page' ) { 
     771        $templates = get_page_templates( null, $post_type ); 
    769772        ksort( $templates ); 
    770773        foreach ( array_keys( $templates ) as $template ) { 
    771774                $selected = selected( $default, $templates[ $template ], false ); 
  • src/wp-admin/includes/theme.php

    diff --git src/wp-admin/includes/theme.php src/wp-admin/includes/theme.php
    index 4eb01ea..b2cc0eb 100644
    function delete_theme($stylesheet, $redirect = '') { 
    102102 * Get the Page Templates available in this theme 
    103103 * 
    104104 * @since 1.5.0 
     105 * @since 4.7.0 Added the `$post_type` parameter. 
    105106 * 
    106  * @param WP_Post|null $post Optional. The post being edited, provided for context. 
     107 * @param WP_Post|null $post      Optional. The post being edited, provided for context. 
     108 * @param string       $post_type Optional. Post type to get the templates for. Default 'page'. 
    107109 * @return array Key is the template name, value is the filename of the template 
    108110 */ 
    109 function get_page_templates( $post = null ) { 
    110         return array_flip( wp_get_theme()->get_page_templates( $post ) ); 
     111function get_page_templates( $post = null, $post_type = 'page' ) { 
     112        return array_flip( wp_get_theme()->get_page_templates( $post, $post_type ) ); 
    111113} 
    112114 
    113115/** 
  • src/wp-includes/class-wp-post.php

    diff --git src/wp-includes/class-wp-post.php src/wp-includes/class-wp-post.php
    index a21776f..c966934 100644
    final class WP_Post { 
    254254                        return true; 
    255255 
    256256                if ( 'page_template' == $key ) 
    257                         return ( 'page' == $this->post_type ); 
     257                        return true; 
    258258 
    259259                if ( 'post_category' == $key ) 
    260260                   return true; 
  • src/wp-includes/class-wp-theme.php

    diff --git src/wp-includes/class-wp-theme.php src/wp-includes/class-wp-theme.php
    index 05211d8..66f623e 100644
    final class WP_Theme implements ArrayAccess { 
    538538         * @since 3.4.0 
    539539         * @access private 
    540540         * 
    541          * @param string $key Type of data to store (theme, screenshot, headers, page_templates) 
     541         * @param string $key Type of data to store (theme, screenshot, headers, post_templates) 
    542542         * @param string $data Data to store 
    543543         * @return bool Return value from wp_cache_add() 
    544544         */ 
    final class WP_Theme implements ArrayAccess { 
    554554         * @since 3.4.0 
    555555         * @access private 
    556556         * 
    557          * @param string $key Type of data to retrieve (theme, screenshot, headers, page_templates) 
     557         * @param string $key Type of data to retrieve (theme, screenshot, headers, post_templates) 
    558558         * @return mixed Retrieved data 
    559559         */ 
    560560        private function cache_get( $key ) { 
    final class WP_Theme implements ArrayAccess { 
    568568         * @access public 
    569569         */ 
    570570        public function cache_delete() { 
    571                 foreach ( array( 'theme', 'screenshot', 'headers', 'page_templates' ) as $key ) 
     571                foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key ) 
    572572                        wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' ); 
    573573                $this->template = $this->textdomain_loaded = $this->theme_root_uri = $this->parent = $this->errors = $this->headers_sanitized = $this->name_translated = null; 
    574574                $this->headers = array(); 
    final class WP_Theme implements ArrayAccess { 
    10061006        } 
    10071007 
    10081008        /** 
    1009          * Returns the theme's page templates. 
     1009         * Returns the theme's post templates. 
    10101010         * 
    1011          * @since 3.4.0 
     1011         * @since 4.7.0 
    10121012         * @access public 
    10131013         * 
    1014          * @param WP_Post|null $post Optional. The post being edited, provided for context. 
    1015          * @return array Array of page templates, keyed by filename, with the value of the translated header name. 
     1014         * @return array Array of page templates, keyed by filename and post type, 
     1015         *               with the value of the translated header name. 
    10161016         */ 
    1017         public function get_page_templates( $post = null ) { 
     1017        public function get_post_templates() { 
    10181018                // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide. 
    1019                 if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) 
     1019                if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) { 
    10201020                        return array(); 
     1021                } 
    10211022 
    1022                 $page_templates = $this->cache_get( 'page_templates' ); 
     1023                $post_templates = $this->cache_get( 'post_templates' ); 
    10231024 
    1024                 if ( ! is_array( $page_templates ) ) { 
    1025                         $page_templates = array(); 
     1025                if ( ! is_array( $post_templates ) ) { 
     1026                        $post_templates = array(); 
    10261027 
    10271028                        $files = (array) $this->get_files( 'php', 1 ); 
    10281029 
    10291030                        foreach ( $files as $file => $full_path ) { 
    1030                                 if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) 
     1031                                if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) { 
    10311032                                        continue; 
    1032                                 $page_templates[ $file ] = _cleanup_header_comment( $header[1] ); 
     1033                                } 
     1034 
     1035                                $types = array( 'page' ); 
     1036                                if ( preg_match( '|Template Post Type:(.*)$|mi', file_get_contents( $full_path ), $type ) ) { 
     1037                                        $types = explode( ',', _cleanup_header_comment( $type[1] ) ); 
     1038                                } 
     1039 
     1040                                foreach ( $types as $type ) { 
     1041                                        $type = trim( $type ); 
     1042                                        if ( ! isset( $post_templates[ $type ] ) ) { 
     1043                                                $post_templates[ $type ] = array(); 
     1044                                        } 
     1045 
     1046                                        $post_templates[ $type ][ $file ] = _cleanup_header_comment( $header[1] ); 
     1047                                } 
    10331048                        } 
    10341049 
    1035                         $this->cache_add( 'page_templates', $page_templates ); 
     1050                        $this->cache_add( 'post_templates', $post_templates ); 
    10361051                } 
    10371052 
    10381053                if ( $this->load_textdomain() ) { 
    1039                         foreach ( $page_templates as &$page_template ) { 
    1040                                 $page_template = $this->translate_header( 'Template Name', $page_template ); 
     1054                        foreach ( $post_templates as &$post_type ) { 
     1055                                foreach ( $post_type as &$post_template ) { 
     1056                                        $post_template = $this->translate_header( 'Template Name', $post_template ); 
     1057                                } 
    10411058                        } 
    10421059                } 
    10431060 
    1044                 if ( $this->parent() ) 
    1045                         $page_templates += $this->parent()->get_page_templates( $post ); 
     1061                return $post_templates; 
     1062        } 
     1063 
     1064        /** 
     1065         * Returns the theme's post templates for a given post type. 
     1066         * 
     1067         * @since 3.4.0 
     1068         * @since 4.7.0 Added the `$post_type` parameter. 
     1069         * @access public 
     1070         * 
     1071         * @param WP_Post|null $post      Optional. The post being edited, provided for context. 
     1072         * @param string       $post_type Optional. Post type to get the templates for. Default 'page'. 
     1073         *                                If a post is provided, its post type is used. 
     1074         * @return array Array of page templates, keyed by filename, with the value of the translated header name. 
     1075         */ 
     1076        public function get_page_templates( $post = null, $post_type = 'page' ) { 
     1077                if ( $post ) { 
     1078                        $post_type = get_post_type( $post ); 
     1079                } 
     1080 
     1081                $post_templates = $this->get_post_templates(); 
     1082                $post_templates = isset( $post_templates[ $post_type ] ) ? $post_templates[ $post_type ] : array(); 
     1083 
     1084                if ( $this->parent() ) { 
     1085                        $post_templates += $this->parent()->get_page_templates( $post ); 
     1086                } 
    10461087 
    10471088                /** 
    10481089                 * Filters list of page templates for a theme. 
    10491090                 * 
     1091                 * The dynamic portion of the hook name, `$post_type`, refers to the post type. 
     1092                 * 
    10501093                 * @since 3.9.0 
    10511094                 * @since 4.4.0 Converted to allow complete control over the `$page_templates` array. 
     1095                 * @since 4.7.0 Added the `$post_type` parameter. 
    10521096                 * 
    1053                  * @param array        $page_templates Array of page templates. Keys are filenames, 
     1097                 * @param array        $post_templates Array of page templates. Keys are filenames, 
    10541098                 *                                     values are translated names. 
    10551099                 * @param WP_Theme     $this           The theme object. 
    10561100                 * @param WP_Post|null $post           The post being edited, provided for context, or null. 
     1101                 * @param string       $post_type      Post type to get the templates for. 
    10571102                 */ 
    1058                 return (array) apply_filters( 'theme_page_templates', $page_templates, $this, $post ); 
     1103                return (array) apply_filters( "theme_{$post_type}_templates", $post_templates, $this, $post, $post_type ); 
    10591104        } 
    10601105 
    10611106        /** 
  • src/wp-includes/post-template.php

    diff --git src/wp-includes/post-template.php src/wp-includes/post-template.php
    index 9e2b3a0..ac88643 100644
    function get_body_class( $class = '' ) { 
    594594        if ( is_404() ) 
    595595                $classes[] = 'error404'; 
    596596 
    597         if ( is_single() ) { 
     597        if ( is_singular() ) { 
    598598                $post_id = $wp_query->get_queried_object_id(); 
    599599                $post = $wp_query->get_queried_object(); 
     600                $post_type = $post->post_type; 
    600601 
    601                 $classes[] = 'single'; 
    602                 if ( isset( $post->post_type ) ) { 
    603                         $classes[] = 'single-' . sanitize_html_class($post->post_type, $post_id); 
    604                         $classes[] = 'postid-' . $post_id; 
     602                if ( is_page_template() ) { 
     603                        $classes[] = "{$post_type}-template"; 
    605604 
    606                         // Post Format 
    607                         if ( post_type_supports( $post->post_type, 'post-formats' ) ) { 
    608                                 $post_format = get_post_format( $post->ID ); 
     605                        $template_slug  = get_page_template_slug( $post_id ); 
     606                        $template_parts = explode( '/', $template_slug ); 
    609607 
    610                                 if ( $post_format && !is_wp_error($post_format) ) 
    611                                         $classes[] = 'single-format-' . sanitize_html_class( $post_format ); 
    612                                 else 
    613                                         $classes[] = 'single-format-standard'; 
     608                        foreach ( $template_parts as $part ) { 
     609                                $classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) ); 
     610                        } 
     611                        $classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( '.', '-', $template_slug ) ); 
     612                } else { 
     613                        $classes[] = "{$post_type}-template-default"; 
     614                } 
     615 
     616                if ( is_single() ) { 
     617                        $classes[] = 'single'; 
     618                        if ( isset( $post->post_type ) ) { 
     619                                $classes[] = 'single-' . sanitize_html_class( $post->post_type, $post_id ); 
     620                                $classes[] = 'postid-' . $post_id; 
     621 
     622                                // Post Format 
     623                                if ( post_type_supports( $post->post_type, 'post-formats' ) ) { 
     624                                        $post_format = get_post_format( $post->ID ); 
     625 
     626                                        if ( $post_format && !is_wp_error($post_format) ) 
     627                                                $classes[] = 'single-format-' . sanitize_html_class( $post_format ); 
     628                                        else 
     629                                                $classes[] = 'single-format-standard'; 
     630                                } 
    614631                        } 
    615632                } 
    616633 
    function get_body_class( $class = '' ) { 
    619636                        $mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' ); 
    620637                        $classes[] = 'attachmentid-' . $post_id; 
    621638                        $classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type ); 
     639                } elseif ( is_page() ) { 
     640                        $classes[] = 'page'; 
     641 
     642                        $page_id = $wp_query->get_queried_object_id(); 
     643 
     644                        $post = get_post($page_id); 
     645 
     646                        $classes[] = 'page-id-' . $page_id; 
     647 
     648                        if ( get_pages( array( 'parent' => $page_id, 'number' => 1 ) ) ) { 
     649                                $classes[] = 'page-parent'; 
     650                        } 
     651 
     652                        if ( $post->post_parent ) { 
     653                                $classes[] = 'page-child'; 
     654                                $classes[] = 'parent-pageid-' . $post->post_parent; 
     655                        } 
    622656                } 
    623657        } elseif ( is_archive() ) { 
    624658                if ( is_post_type_archive() ) { 
    function get_body_class( $class = '' ) { 
    671705                                $classes[] = 'term-' . $term->term_id; 
    672706                        } 
    673707                } 
    674         } elseif ( is_page() ) { 
    675                 $classes[] = 'page'; 
    676  
    677                 $page_id = $wp_query->get_queried_object_id(); 
    678  
    679                 $post = get_post($page_id); 
    680  
    681                 $classes[] = 'page-id-' . $page_id; 
    682  
    683                 if ( get_pages( array( 'parent' => $page_id, 'number' => 1 ) ) ) { 
    684                         $classes[] = 'page-parent'; 
    685                 } 
    686  
    687                 if ( $post->post_parent ) { 
    688                         $classes[] = 'page-child'; 
    689                         $classes[] = 'parent-pageid-' . $post->post_parent; 
    690                 } 
    691                 if ( is_page_template() ) { 
    692                         $classes[] = 'page-template'; 
    693  
    694                         $template_slug  = get_page_template_slug( $page_id ); 
    695                         $template_parts = explode( '/', $template_slug ); 
    696  
    697                         foreach ( $template_parts as $part ) { 
    698                                 $classes[] = 'page-template-' . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) ); 
    699                         } 
    700                         $classes[] = 'page-template-' . sanitize_html_class( str_replace( '.', '-', $template_slug ) ); 
    701                 } else { 
    702                         $classes[] = 'page-template-default'; 
    703                 } 
    704708        } 
    705709 
    706710        if ( is_user_logged_in() ) 
    function get_the_password_form( $post = 0 ) { 
    16211625 * 
    16221626 * @since 2.5.0 
    16231627 * @since 4.2.0 The `$template` parameter was changed to also accept an array of page templates. 
     1628 * @since 4.7.0 Now works with any post type, not just pages. 
    16241629 * 
    16251630 * @param string|array $template The specific template name or array of templates to match. 
    16261631 * @return bool True on success, false on failure. 
    16271632 */ 
    16281633function is_page_template( $template = '' ) { 
    1629         if ( ! is_page() ) 
    1630                 return false; 
    1631  
    16321634        $page_template = get_page_template_slug( get_queried_object_id() ); 
    16331635 
    16341636        if ( empty( $template ) ) 
    function is_page_template( $template = '' ) { 
    16491651} 
    16501652 
    16511653/** 
    1652  * Get the specific template name for a page. 
     1654 * Get the specific template name for a given post. 
    16531655 * 
    16541656 * @since 3.4.0 
     1657 * @since 4.7.0 Now works with any post type, not just pages. 
    16551658 * 
    1656  * @param int $post_id Optional. The page ID to check. Defaults to the current post, when used in the loop. 
     1659 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 
    16571660 * @return string|false Page template filename. Returns an empty string when the default page template 
    1658  *      is in use. Returns false if the post is not a page. 
     1661 *      is in use. Returns false if the post does not exist. 
    16591662 */ 
    1660 function get_page_template_slug( $post_id = null ) { 
    1661         $post = get_post( $post_id ); 
    1662         if ( ! $post || 'page' != $post->post_type ) 
     1663function get_page_template_slug( $post = null ) { 
     1664        $post = get_post( $post ); 
     1665 
     1666        if ( ! $post ) { 
    16631667                return false; 
     1668        } 
     1669 
    16641670        $template = get_post_meta( $post->ID, '_wp_page_template', true ); 
    1665         if ( ! $template || 'default' == $template ) 
     1671 
     1672        if ( ! $template || 'default' == $template ) { 
    16661673                return ''; 
     1674        } 
     1675 
    16671676        return $template; 
    16681677} 
    16691678 
  • src/wp-includes/post.php

    diff --git src/wp-includes/post.php src/wp-includes/post.php
    index cfb941f..89ddaaa 100644
    function create_initial_post_types() { 
    6666                        'add_new' => _x( 'Add New', 'add new media' ), 
    6767                        'edit_item' => __( 'Edit Media' ), 
    6868                        'view_item' => __( 'View Attachment Page' ), 
     69                        'attributes' => __( 'Attachment Attributes' ), 
    6970                ), 
    7071                'public' => true, 
    7172                'show_ui' => true, 
    function _post_type_meta_capabilities( $capabilities = null ) { 
    13261327 *                       post types. Default is 'Parent Page:'. 
    13271328 * - `all_items` - Label to signify all items in a submenu link. Default is 'All Posts' / 'All Pages'. 
    13281329 * - `archives` - Label for archives in nav menus. Default is 'Post Archives' / 'Page Archives'. 
     1330 * - `attributes` - Label for the attributes meta box. Default is 'Post Attributes' / 'Page Attributes'. 
    13291331 * - `insert_into_item` - Label for the media frame button. Default is 'Insert into post' / 'Insert into page'. 
    13301332 * - `uploaded_to_this_item` - Label for the media frame filter. Default is 'Uploaded to this post' / 
    13311333 *                           'Uploaded to this page'. 
    function _post_type_meta_capabilities( $capabilities = null ) { 
    13511353 * @since 4.4.0 Added the `insert_into_item`, `uploaded_to_this_item`, `filter_items_list`, 
    13521354 *              `items_list_navigation`, and `items_list` labels. 
    13531355 * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object. 
    1354  * @since 4.7.0 Added the `view_items` label. 
     1356 * @since 4.7.0 Added the `view_items` and `attributes` labels. 
    13551357 * 
    13561358 * @access private 
    13571359 * 
    function get_post_type_labels( $post_type_object ) { 
    13741376                'parent_item_colon' => array( null, __('Parent Page:') ), 
    13751377                'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) ), 
    13761378                'archives' => array( __( 'Post Archives' ), __( 'Page Archives' ) ), 
     1379                'attributes' => array( __( 'Post Attributes' ), __( 'Page Attributes' ) ), 
    13771380                'insert_into_item' => array( __( 'Insert into post' ), __( 'Insert into page' ) ), 
    13781381                'uploaded_to_this_item' => array( __( 'Uploaded to this post' ), __( 'Uploaded to this page' ) ), 
    13791382                'featured_image' => array( __( 'Featured Image' ), __( 'Featured Image' ) ), 
    function wp_insert_post( $postarr, $wp_error = false ) { 
    33933396 
    33943397        $post = get_post( $post_ID ); 
    33953398 
    3396         if ( ! empty( $postarr['page_template'] ) && 'page' == $data['post_type'] ) { 
     3399        if ( ! empty( $postarr['page_template'] ) ) { 
    33973400                $post->page_template = $postarr['page_template']; 
    33983401                $page_templates = wp_get_theme()->get_page_templates( $post ); 
    33993402                if ( 'default' != $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) { 
  • src/wp-includes/template.php

    diff --git src/wp-includes/template.php src/wp-includes/template.php
    index fd0476b..636cb90 100644
    function get_search_template() { 
    449449 * 
    450450 * The hierarchy for this template looks like: 
    451451 * 
    452  * 1. single-{post_type}-{post_name}.php 
    453  * 2. single-{post_type}.php 
    454  * 3. single.php 
     452 * 1. {Post Type Template}.php 
     453 * 2. single-{post_type}-{post_name}.php 
     454 * 3. single-{post_type}.php 
     455 * 4. single.php 
    455456 * 
    456457 * An example of this is: 
    457458 * 
    458  * 1. single-post-hello-world.php 
    459  * 2. single-post.php 
    460  * 3. single.php 
     459 * 1. templates/full-width.php 
     460 * 2. single-post-hello-world.php 
     461 * 3. single-post.php 
     462 * 4. single.php 
    461463 * 
    462464 * The template hierarchy is filterable via the {@see 'single_template_hierarchy'} hook. 
    463465 * The template path is filterable via the {@see 'single_template'} hook. 
    function get_search_template() { 
    466468 * @since 4.4.0 `single-{post_type}-{post_name}.php` was added to the top of the template hierarchy. 
    467469 * @since 4.7.0 The decoded form of `single-{post_type}-{post_name}.php` was added to the top of the 
    468470 *              template hierarchy when the post name contains multibyte characters. 
     471 * @since 4.7.0 {Post Type Template}.php was added to the top of the template hierarchy. 
    469472 * 
    470473 * @see get_query_template() 
    471474 * 
    function get_single_template() { 
    477480        $templates = array(); 
    478481 
    479482        if ( ! empty( $object->post_type ) ) { 
     483                $template = get_page_template_slug( $object ); 
     484                if ( $template && 0 === validate_file( $template ) ) { 
     485                        $templates[] = $template; 
     486                } 
    480487 
    481488                $name_decoded = urldecode( $object->post_name ); 
    482489                if ( $name_decoded !== $object->post_name ) { 
  • new file tests/phpunit/data/themedir1/page-templates/subdir/template-sub-dir-post-types.php

    diff --git tests/phpunit/data/themedir1/page-templates/subdir/template-sub-dir-post-types.php tests/phpunit/data/themedir1/page-templates/subdir/template-sub-dir-post-types.php
    new file mode 100644
    index 0000000..1f2e99d
    - +  
     1<?php 
     2/* 
     3   Template Name: Sub Dir 
     4   Template Post Type: foo, post 
     5 */ 
  • new file tests/phpunit/data/themedir1/page-templates/template-top-level-post-types.php

    diff --git tests/phpunit/data/themedir1/page-templates/template-top-level-post-types.php tests/phpunit/data/themedir1/page-templates/template-top-level-post-types.php
    new file mode 100644
    index 0000000..8df098c
    - +  
     1<?php 
     2/* 
     3   Template Name: Top Level 
     4   Template Post Type: foo, post 
     5 */ 
  • tests/phpunit/tests/admin/includesTheme.php

    diff --git tests/phpunit/tests/admin/includesTheme.php tests/phpunit/tests/admin/includesTheme.php
    index 382c6bb..ba76bf1 100644
    class Tests_Admin_includesTheme extends WP_UnitTestCase { 
    4848 
    4949                switch_theme( $theme['Template'], $theme['Stylesheet'] ); 
    5050 
    51                 $templates = get_page_templates(); 
    52                 $this->assertCount( 3, $templates ); 
    53                 $this->assertEquals( "template-top-level.php", $templates['Top Level'] ); 
    54                 $this->assertEquals( "subdir/template-sub-dir.php", $templates['Sub Dir'] ); 
    55                 $this->assertEquals( "template-header.php", $templates['This Template Header Is On One Line'] ); 
     51                $this->assertEqualSetsWithIndex( array( 
     52                        'Top Level'                           => 'template-top-level.php', 
     53                        'Sub Dir'                             => 'subdir/template-sub-dir.php', 
     54                        'This Template Header Is On One Line' => 'template-header.php', 
     55                ), get_page_templates() ); 
    5656 
    5757                $theme = wp_get_theme( 'page-templates' ); 
    5858                $this->assertNotEmpty( $theme ); 
    5959 
    6060                switch_theme( $theme['Template'], $theme['Stylesheet'] ); 
    6161 
    62                 $templates = get_page_templates(); 
    63                 $this->assertCount( 3, $templates ); 
    64                 $this->assertEquals( "template-top-level.php", $templates['Top Level'] ); 
    65                 $this->assertEquals( "subdir/template-sub-dir.php", $templates['Sub Dir'] ); 
    66                 $this->assertEquals( "template-header.php", $templates['This Template Header Is On One Line'] ); 
     62                $this->assertEqualSetsWithIndex( array( 
     63                        'Top Level'                           => 'template-top-level.php', 
     64                        'Sub Dir'                             => 'subdir/template-sub-dir.php', 
     65                        'This Template Header Is On One Line' => 'template-header.php', 
     66                ), get_page_templates() ); 
     67        } 
     68 
     69        /** 
     70         * @ticket 18375 
     71         */ 
     72        function test_page_templates_different_post_types() { 
     73                $theme = wp_get_theme( 'page-templates' ); 
     74                $this->assertNotEmpty( $theme ); 
     75 
     76                switch_theme( $theme['Template'], $theme['Stylesheet'] ); 
     77 
     78                $this->assertEqualSetsWithIndex( array( 
     79                        'Top Level' => 'template-top-level-post-types.php', 
     80                        'Sub Dir'   => 'subdir/template-sub-dir-post-types.php', 
     81                ), get_page_templates( null, 'foo' ) ); 
     82                $this->assertEqualSetsWithIndex( array( 
     83                        'Top Level' => 'template-top-level-post-types.php', 
     84                        'Sub Dir'   => 'subdir/template-sub-dir-post-types.php', 
     85                ), get_page_templates( null, 'post' ) ); 
     86                $this->assertEquals( array(), get_page_templates( null, 'bar' ) ); 
    6787        } 
    6888} 
  • tests/phpunit/tests/post/getBodyClass.php

    diff --git tests/phpunit/tests/post/getBodyClass.php tests/phpunit/tests/post/getBodyClass.php
    index 7401ce6..771b8e3 100644
    class Tests_Post_GetBodyClass extends WP_UnitTestCase { 
    9292                $this->assertContains( "single-format-standard", $class ); 
    9393        } 
    9494 
     95        public function test_page_template_body_classes_no_template() { 
     96                $post_id = self::factory()->post->create( array( 
     97                        'post_type' => 'page', 
     98                ) ); 
     99                $this->go_to( get_permalink( $post_id ) ); 
     100 
     101                $class = get_body_class(); 
     102 
     103                $this->assertNotContains( 'page-template', $class ); 
     104                $this->assertContains( 'page-template-default', $class ); 
     105        } 
     106 
     107        public function test_page_template_body_classes() { 
     108                $post_id = self::factory()->post->create( array( 
     109                        'post_type' => 'page', 
     110                ) ); 
     111 
     112                add_post_meta( $post_id, '_wp_page_template', 'templates/cpt.php' ); 
     113 
     114                $this->go_to( get_permalink( $post_id ) ); 
     115 
     116                $class = get_body_class(); 
     117 
     118                $this->assertContains( 'page-template', $class ); 
     119                $this->assertContains( 'page-template-templates', $class ); 
     120                $this->assertContains( 'page-template-cpt', $class ); 
     121                $this->assertContains( 'page-template-templatescpt-php', $class ); 
     122        } 
     123 
     124        /** 
     125         * @ticket 18375 
     126         */ 
     127        public function test_page_template_body_classes_attachment() { 
     128                $post_id = self::factory()->post->create( array( 
     129                        'post_type' => 'attachment', 
     130                ) ); 
     131 
     132                add_post_meta( $post_id, '_wp_page_template', 'templates/cpt.php' ); 
     133 
     134                $this->go_to( get_permalink( $post_id ) ); 
     135 
     136                $class = get_body_class(); 
     137 
     138                $this->assertContains( 'attachment-template', $class ); 
     139                $this->assertContains( 'attachment-template-templates', $class ); 
     140                $this->assertContains( 'attachment-template-cpt', $class ); 
     141                $this->assertContains( 'attachment-template-templatescpt-php', $class ); 
     142        } 
     143 
     144        /** 
     145         * @ticket 18375 
     146         */ 
     147        public function test_page_template_body_classes_post() { 
     148                $post_id = self::factory()->post->create(); 
     149 
     150                add_post_meta( $post_id, '_wp_page_template', 'templates/cpt.php' ); 
     151 
     152                $this->go_to( get_permalink( $post_id ) ); 
     153 
     154                $class = get_body_class(); 
     155 
     156                $this->assertContains( 'post-template', $class ); 
     157                $this->assertContains( 'post-template-templates', $class ); 
     158                $this->assertContains( 'post-template-cpt', $class ); 
     159                $this->assertContains( 'post-template-templatescpt-php', $class ); 
     160        } 
    95161} 
  • tests/phpunit/tests/post/objects.php

    diff --git tests/phpunit/tests/post/objects.php tests/phpunit/tests/post/objects.php
    index 5ad92c6..4bcc951 100644
    class Tests_Post_Objects extends WP_UnitTestCase { 
    145145                update_post_meta( $post_id, '_wp_page_template', 'foo.php' ); 
    146146                $template = get_post_meta( $post->ID, '_wp_page_template', true ); 
    147147                $this->assertEquals( 'foo.php', $template ); 
    148                 // The post is not a page so the template is still empty 
    149                 $this->assertEquals( '', $post->page_template ); 
    150  
    151                 // Now the post is a page and should retrieve the template 
    152                 wp_update_post( array( 'ID' => $post->ID, 'post_type' => 'page' ) ); 
    153                 $post = get_post( $post_id ); 
    154148                $this->assertEquals( $template, $post->page_template ); 
    155149        } 
    156150 
  • tests/phpunit/tests/post/template.php

    diff --git tests/phpunit/tests/post/template.php tests/phpunit/tests/post/template.php
    index ac5958d..062b04a 100644
    NO; 
    271271 
    272272        /** 
    273273         * @ticket 31389 
     274         * @ticket 18375 
    274275         */ 
    275276        public function test_get_page_template_slug_non_page() { 
    276                 $post_id = self::factory()->post->create( array( 
    277                         'post_type' => 'post', 
    278                 ) ); 
     277                $post_id = self::factory()->post->create(); 
     278 
     279                $this->assertEquals( '', get_page_template_slug( $post_id ) ); 
     280 
     281                update_post_meta( $post_id, '_wp_page_template', 'default' ); 
    279282 
    280                 $this->assertFalse( get_page_template_slug( $post_id ) ); 
     283                $this->assertEquals( '', get_page_template_slug( $post_id ) ); 
     284 
     285                update_post_meta( $post_id, '_wp_page_template', 'example.php' ); 
     286                $this->assertEquals( 'example.php', get_page_template_slug( $post_id ) ); 
     287        } 
     288 
     289        /** 
     290         * @ticket 18375 
     291         */ 
     292        public function test_get_page_template_slug_non_page_from_loop() { 
     293                $post_id = self::factory()->post->create(); 
     294 
     295                update_post_meta( $post_id, '_wp_page_template', 'example.php' ); 
    281296 
    282297                $this->go_to( get_permalink( $post_id ) ); 
    283                 $this->assertFalse( get_page_template_slug() ); 
     298 
     299                $this->assertEquals( 'example.php', get_page_template_slug() ); 
    284300        } 
    285301 
    286302        /** 
  • tests/phpunit/tests/query/conditionals.php

    diff --git tests/phpunit/tests/query/conditionals.php tests/phpunit/tests/query/conditionals.php
    index a3df6d0..4a6d2be 100644
    class Tests_Query_Conditionals extends WP_UnitTestCase { 
    10441044        } 
    10451045 
    10461046        /** 
     1047         * @ticket 18375 
     1048         */ 
     1049        function test_is_page_template_other_post_type() { 
     1050                $post_id = self::factory()->post->create( array( 'post_type' => 'post' ) ); 
     1051                update_post_meta( $post_id, '_wp_page_template', 'example.php' ); 
     1052                $this->go_to( get_post_permalink( $post_id ) ); 
     1053                $this->assertFalse( is_page_template( array( 'test.php' ) ) ); 
     1054                $this->assertTrue( is_page_template( array( 'test.php', 'example.php' ) ) ); 
     1055        } 
     1056 
     1057        /** 
    10471058         * @ticket 35902 
    10481059         */ 
    10491060        public function test_is_attachment_should_not_match_numeric_id_to_post_title_beginning_with_id() { 
  • tests/phpunit/tests/template.php

    diff --git tests/phpunit/tests/template.php tests/phpunit/tests/template.php
    index 00030f2..fe5ecfe 100644
    class Tests_Template extends WP_UnitTestCase { 
    3636                        'post_date' => '1984-02-25 12:34:56', 
    3737                ) ); 
    3838                set_post_format( self::$post, 'quote' ); 
     39                add_post_meta( self::$post->ID, '_wp_page_template', 'templates/post.php' ); 
    3940        } 
    4041 
    4142        public function setUp() { 
    class Tests_Template extends WP_UnitTestCase { 
    203204                ) ); 
    204205        } 
    205206 
     207        /** 
     208         * @ticket 18375 
     209         */ 
    206210        public function test_single_template_hierarchy_for_post() { 
    207211                $this->assertTemplateHierarchy( get_permalink( self::$post ), array( 
     212                        'templates/post.php', 
    208213                        'single-post-post-name-😀.php', 
    209214                        'single-post-post-name-%f0%9f%98%80.php', 
    210215                        'single-post.php', 
    class Tests_Template extends WP_UnitTestCase { 
    228233                ) ); 
    229234        } 
    230235 
     236        /** 
     237         * @ticket 18375 
     238         */ 
     239        public function test_single_template_hierarchy_for_custom_post_type_with_template() { 
     240                $cpt = self::factory()->post->create_and_get( array( 
     241                        'post_type' => 'cpt', 
     242                        'post_name' => 'cpt-name-😀', 
     243                ) ); 
     244                add_post_meta( $cpt->ID, '_wp_page_template', 'templates/cpt.php' ); 
     245 
     246                $this->assertTemplateHierarchy( get_permalink( $cpt ), array( 
     247                        'templates/cpt.php', 
     248                        'single-cpt-cpt-name-😀.php', 
     249                        'single-cpt-cpt-name-%f0%9f%98%80.php', 
     250                        'single-cpt.php', 
     251                        'single.php', 
     252                        'singular.php', 
     253                ) ); 
     254        } 
     255 
    231256        public function test_attachment_template_hierarchy() { 
    232257                $attachment = self::factory()->attachment->create_and_get( array( 
    233258                        'post_name'      => 'attachment-name-😀', 
    class Tests_Template extends WP_UnitTestCase { 
    247272                ) ); 
    248273        } 
    249274 
     275        /** 
     276         * @ticket 18375 
     277         */ 
     278        public function test_attachment_template_hierarchy_with_template() { 
     279                $attachment = self::factory()->attachment->create_and_get( array( 
     280                        'post_name'      => 'attachment-name-😀', 
     281                        'file'           => 'image.jpg', 
     282                        'post_mime_type' => 'image/jpeg', 
     283                ) ); 
     284 
     285                add_post_meta( $attachment, '_wp_page_template', 'templates/cpt.php' ); 
     286 
     287                $this->assertTemplateHierarchy( get_permalink( $attachment ), array( 
     288                        'image-jpeg.php', 
     289                        'jpeg.php', 
     290                        'image.php', 
     291                        'attachment.php', 
     292                        'single-attachment-attachment-name-😀.php', 
     293                        'single-attachment-attachment-name-%f0%9f%98%80.php', 
     294                        'single-attachment.php', 
     295                        'single.php', 
     296                        'singular.php', 
     297                ) ); 
     298        } 
     299 
    250300        public function test_embed_template_hierarchy_for_post() { 
    251301                $this->assertTemplateHierarchy( get_post_embed_url( self::$post ), array( 
    252302                        'embed-post-quote.php', 
    253303                        'embed-post.php', 
    254304                        'embed.php', 
     305                        'templates/post.php', 
    255306                        'single-post-post-name-😀.php', 
    256307                        'single-post-post-name-%f0%9f%98%80.php', 
    257308                        'single-post.php',