Posts, Post Types: Add support for post type templates.

WordPress has supported custom page templates for over 12 years, allowing developers to create various layouts for specific pages.
While this feature is very helpful, it has always been limited to the 'page' post type and not was not available to other post types.

By opening up the page template functionality to all post types, we continue to improve the template hierarchy's flexibility.

In addition to the `Template Name` file header, the post types supported by a template can be specified using `Template Post Type: post, foo, bar`.
When at least one template exists for a post type, the 'Post Attributes' meta box will be displayed in the back end, without the need to add post type support for `'page-attributes'`. 'Post Attributes' can be customized per post type using the `'attributes'` label when registering a post type.

Props johnbillion, Mte90, dipesh.kakadiya, swissspidy.
Fixes #18375.

git-svn-id: https://develop.svn.wordpress.org/trunk@38951 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Pascal Birchler 2016-10-26 08:06:43 +00:00
parent ee14487043
commit a9516abb54
18 changed files with 391 additions and 150 deletions

View File

@ -259,8 +259,9 @@ foreach ( get_object_taxonomies( $post ) as $tax_name ) {
add_meta_box( $tax_meta_box_id, $label, $taxonomy->meta_box_cb, null, 'side', 'core', array( 'taxonomy' => $tax_name ) );
}
if ( post_type_supports($post_type, 'page-attributes') )
add_meta_box('pageparentdiv', 'page' == $post_type ? __('Page Attributes') : __('Attributes'), 'page_attributes_meta_box', null, 'side', 'core');
if ( post_type_supports( $post_type, 'page-attributes' ) || count( get_page_templates( null, $post_type ) ) > 0 ) {
add_meta_box( 'pageparentdiv', $post_type_object->labels->attributes, 'page_attributes_meta_box', null, 'side', 'core' );
}
if ( $thumbnail_support && current_user_can( 'upload_files' ) )
add_meta_box('postimagediv', esc_html( $post_type_object->labels->featured_image ), 'post_thumbnail_meta_box', null, 'side', 'low');

View File

@ -1528,31 +1528,28 @@ class WP_Posts_List_Table extends WP_List_Table {
<span class="input-text-wrap"><input type="text" name="menu_order" class="inline-edit-menu-order-input" value="<?php echo $post->menu_order ?>" /></span>
</label>
<?php endif; // !$bulk
if ( 'page' === $screen->post_type ) :
?>
<label>
<span class="title"><?php _e( 'Template' ); ?></span>
<select name="page_template">
<?php if ( $bulk ) : ?>
<option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
<?php endif; // $bulk ?>
<?php
/** This filter is documented in wp-admin/includes/meta-boxes.php */
$default_title = apply_filters( 'default_page_template_title', __( 'Default Template' ), 'quick-edit' );
?>
<option value="default"><?php echo esc_html( $default_title ); ?></option>
<?php page_template_dropdown() ?>
</select>
</label>
<?php
endif; // page post_type
endif; // !$bulk
endif; // page-attributes
?>
<?php if ( 0 < count( get_page_templates( null, $screen->post_type ) ) ) : ?>
<label>
<span class="title"><?php _e( 'Template' ); ?></span>
<select name="page_template">
<?php if ( $bulk ) : ?>
<option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
<?php endif; // $bulk ?>
<?php
/** This filter is documented in wp-admin/includes/meta-boxes.php */
$default_title = apply_filters( 'default_page_template_title', __( 'Default Template' ), 'quick-edit' );
?>
<option value="default"><?php echo esc_html( $default_title ); ?></option>
<?php page_template_dropdown( $post->page_template, $screen->post_type ) ?>
</select>
</label>
<?php endif; ?>
<?php if ( count( $flat_taxonomies ) && !$bulk ) : ?>
<?php foreach ( $flat_taxonomies as $taxonomy ) : ?>

View File

@ -788,8 +788,7 @@ function post_revisions_meta_box( $post ) {
* @param object $post
*/
function page_attributes_meta_box($post) {
$post_type_object = get_post_type_object($post->post_type);
if ( $post_type_object->hierarchical ) {
if ( is_post_type_hierarchical( $post->post_type ) ) :
$dropdown_args = array(
'post_type' => $post->post_type,
'exclude_tree' => $post->ID,
@ -812,16 +811,17 @@ function page_attributes_meta_box($post) {
*/
$dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post );
$pages = wp_dropdown_pages( $dropdown_args );
if ( ! empty($pages) ) {
if ( ! empty($pages) ) :
?>
<p><strong><?php _e('Parent') ?></strong></p>
<label class="screen-reader-text" for="parent_id"><?php _e('Parent') ?></label>
<?php echo $pages; ?>
<?php
} // end empty pages check
} // end hierarchical check.
if ( 'page' == $post->post_type && 0 != count( get_page_templates( $post ) ) && get_option( 'page_for_posts' ) != $post->ID ) {
$template = !empty($post->page_template) ? $post->page_template : false;
endif; // end empty pages check
endif; // end hierarchical check.
if ( count( get_page_templates( $post ) ) > 0 && get_option( 'page_for_posts' ) != $post->ID ) :
$template = ! empty( $post->page_template ) ? $post->page_template : false;
?>
<p><strong><?php _e('Template') ?></strong><?php
/**
@ -835,7 +835,13 @@ function page_attributes_meta_box($post) {
*/
do_action( 'page_attributes_meta_box_template', $template, $post );
?></p>
<label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select name="page_template" id="page_template">
<label class="screen-reader-text" for="page_template">
<?php
$post_type_object = get_post_type_object( $post->post_type );
echo esc_html( $post_type_object->labels->attributes );
?>
</label>
<select name="page_template" id="page_template">
<?php
/**
* Filters the title of the default page template displayed in the drop-down.
@ -849,16 +855,16 @@ function page_attributes_meta_box($post) {
$default_title = apply_filters( 'default_page_template_title', __( 'Default Template' ), 'meta-box' );
?>
<option value="default"><?php echo esc_html( $default_title ); ?></option>
<?php page_template_dropdown($template); ?>
<?php page_template_dropdown( $template, $post->post_type ); ?>
</select>
<?php
} ?>
<?php endif; ?>
<?php if ( post_type_supports( $post->post_type, 'page-attributes' ) ) : ?>
<p><strong><?php _e('Order') ?></strong></p>
<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>
<?php if ( 'page' == $post->post_type && get_current_screen()->get_help_tabs() ) { ?>
<?php if ( 'page' == $post->post_type && get_current_screen()->get_help_tabs() ) : ?>
<p><?php _e( 'Need help? Use the Help tab above the screen title.' ); ?></p>
<?php
}
<?php endif;
endif;
}
// -- Link related Meta Boxes

View File

@ -293,14 +293,15 @@ function get_inline_data($post) {
<div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
<div class="post_password">' . esc_html( $post->post_password ) . '</div>';
if ( $post_type_object->hierarchical )
if ( $post_type_object->hierarchical ) {
echo '<div class="post_parent">' . $post->post_parent . '</div>';
}
if ( $post->post_type == 'page' )
echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
echo '<div class="page_template">' . esc_html( $post->page_template ) . '</div>';
if ( post_type_supports( $post->post_type, 'page-attributes' ) )
if ( post_type_supports( $post->post_type, 'page-attributes' ) ) {
echo '<div class="menu_order">' . $post->menu_order . '</div>';
}
$taxonomy_names = get_object_taxonomies( $post->post_type );
foreach ( $taxonomy_names as $taxonomy_name) {
@ -761,11 +762,13 @@ function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
* Print out option HTML elements for the page templates drop-down.
*
* @since 1.5.0
* @since 4.7.0 Added the `$post_type` parameter.
*
* @param string $default Optional. The template file name. Default empty.
* @param string $default Optional. The template file name. Default empty.
* @param string $post_type Optional. Post type to get templates for. Default 'post'.
*/
function page_template_dropdown( $default = '' ) {
$templates = get_page_templates( get_post() );
function page_template_dropdown( $default = '', $post_type = 'page' ) {
$templates = get_page_templates( null, $post_type );
ksort( $templates );
foreach ( array_keys( $templates ) as $template ) {
$selected = selected( $default, $templates[ $template ], false );

View File

@ -102,12 +102,14 @@ function delete_theme($stylesheet, $redirect = '') {
* Get the Page Templates available in this theme
*
* @since 1.5.0
* @since 4.7.0 Added the `$post_type` parameter.
*
* @param WP_Post|null $post Optional. The post being edited, provided for context.
* @param WP_Post|null $post Optional. The post being edited, provided for context.
* @param string $post_type Optional. Post type to get the templates for. Default 'page'.
* @return array Key is the template name, value is the filename of the template
*/
function get_page_templates( $post = null ) {
return array_flip( wp_get_theme()->get_page_templates( $post ) );
function get_page_templates( $post = null, $post_type = 'page' ) {
return array_flip( wp_get_theme()->get_page_templates( $post, $post_type ) );
}
/**

View File

@ -254,7 +254,7 @@ final class WP_Post {
return true;
if ( 'page_template' == $key )
return ( 'page' == $this->post_type );
return true;
if ( 'post_category' == $key )
return true;

View File

@ -538,7 +538,7 @@ final class WP_Theme implements ArrayAccess {
* @since 3.4.0
* @access private
*
* @param string $key Type of data to store (theme, screenshot, headers, page_templates)
* @param string $key Type of data to store (theme, screenshot, headers, post_templates)
* @param string $data Data to store
* @return bool Return value from wp_cache_add()
*/
@ -554,7 +554,7 @@ final class WP_Theme implements ArrayAccess {
* @since 3.4.0
* @access private
*
* @param string $key Type of data to retrieve (theme, screenshot, headers, page_templates)
* @param string $key Type of data to retrieve (theme, screenshot, headers, post_templates)
* @return mixed Retrieved data
*/
private function cache_get( $key ) {
@ -568,7 +568,7 @@ final class WP_Theme implements ArrayAccess {
* @access public
*/
public function cache_delete() {
foreach ( array( 'theme', 'screenshot', 'headers', 'page_templates' ) as $key )
foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key )
wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' );
$this->template = $this->textdomain_loaded = $this->theme_root_uri = $this->parent = $this->errors = $this->headers_sanitized = $this->name_translated = null;
$this->headers = array();
@ -1006,56 +1006,101 @@ final class WP_Theme implements ArrayAccess {
}
/**
* Returns the theme's page templates.
* Returns the theme's post templates.
*
* @since 3.4.0
* @since 4.7.0
* @access public
*
* @param WP_Post|null $post Optional. The post being edited, provided for context.
* @return array Array of page templates, keyed by filename, with the value of the translated header name.
* @return array Array of page templates, keyed by filename and post type,
* with the value of the translated header name.
*/
public function get_page_templates( $post = null ) {
public function get_post_templates() {
// If you screw up your current theme and we invalidate your parent, most things still work. Let it slide.
if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) )
if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) {
return array();
}
$page_templates = $this->cache_get( 'page_templates' );
$post_templates = $this->cache_get( 'post_templates' );
if ( ! is_array( $page_templates ) ) {
$page_templates = array();
if ( ! is_array( $post_templates ) ) {
$post_templates = array();
$files = (array) $this->get_files( 'php', 1 );
foreach ( $files as $file => $full_path ) {
if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) )
if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) {
continue;
$page_templates[ $file ] = _cleanup_header_comment( $header[1] );
}
$types = array( 'page' );
if ( preg_match( '|Template Post Type:(.*)$|mi', file_get_contents( $full_path ), $type ) ) {
$types = explode( ',', _cleanup_header_comment( $type[1] ) );
}
foreach ( $types as $type ) {
$type = trim( $type );
if ( ! isset( $post_templates[ $type ] ) ) {
$post_templates[ $type ] = array();
}
$post_templates[ $type ][ $file ] = _cleanup_header_comment( $header[1] );
}
}
$this->cache_add( 'page_templates', $page_templates );
$this->cache_add( 'post_templates', $post_templates );
}
if ( $this->load_textdomain() ) {
foreach ( $page_templates as &$page_template ) {
$page_template = $this->translate_header( 'Template Name', $page_template );
foreach ( $post_templates as &$post_type ) {
foreach ( $post_type as &$post_template ) {
$post_template = $this->translate_header( 'Template Name', $post_template );
}
}
}
if ( $this->parent() )
$page_templates += $this->parent()->get_page_templates( $post );
return $post_templates;
}
/**
* Returns the theme's post templates for a given post type.
*
* @since 3.4.0
* @since 4.7.0 Added the `$post_type` parameter.
* @access public
*
* @param WP_Post|null $post Optional. The post being edited, provided for context.
* @param string $post_type Optional. Post type to get the templates for. Default 'page'.
* If a post is provided, its post type is used.
* @return array Array of page templates, keyed by filename, with the value of the translated header name.
*/
public function get_page_templates( $post = null, $post_type = 'page' ) {
if ( $post ) {
$post_type = get_post_type( $post );
}
$post_templates = $this->get_post_templates();
$post_templates = isset( $post_templates[ $post_type ] ) ? $post_templates[ $post_type ] : array();
if ( $this->parent() ) {
$post_templates += $this->parent()->get_page_templates( $post );
}
/**
* Filters list of page templates for a theme.
*
* The dynamic portion of the hook name, `$post_type`, refers to the post type.
*
* @since 3.9.0
* @since 4.4.0 Converted to allow complete control over the `$page_templates` array.
* @since 4.7.0 Added the `$post_type` parameter.
*
* @param array $page_templates Array of page templates. Keys are filenames,
* @param array $post_templates Array of page templates. Keys are filenames,
* values are translated names.
* @param WP_Theme $this The theme object.
* @param WP_Post|null $post The post being edited, provided for context, or null.
* @param string $post_type Post type to get the templates for.
*/
return (array) apply_filters( 'theme_page_templates', $page_templates, $this, $post );
return (array) apply_filters( "theme_{$post_type}_templates", $post_templates, $this, $post, $post_type );
}
/**

View File

@ -594,23 +594,40 @@ function get_body_class( $class = '' ) {
if ( is_404() )
$classes[] = 'error404';
if ( is_single() ) {
if ( is_singular() ) {
$post_id = $wp_query->get_queried_object_id();
$post = $wp_query->get_queried_object();
$post_type = $post->post_type;
$classes[] = 'single';
if ( isset( $post->post_type ) ) {
$classes[] = 'single-' . sanitize_html_class($post->post_type, $post_id);
$classes[] = 'postid-' . $post_id;
if ( is_page_template() ) {
$classes[] = "{$post_type}-template";
// Post Format
if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
$post_format = get_post_format( $post->ID );
$template_slug = get_page_template_slug( $post_id );
$template_parts = explode( '/', $template_slug );
if ( $post_format && !is_wp_error($post_format) )
$classes[] = 'single-format-' . sanitize_html_class( $post_format );
else
$classes[] = 'single-format-standard';
foreach ( $template_parts as $part ) {
$classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) );
}
$classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( '.', '-', $template_slug ) );
} else {
$classes[] = "{$post_type}-template-default";
}
if ( is_single() ) {
$classes[] = 'single';
if ( isset( $post->post_type ) ) {
$classes[] = 'single-' . sanitize_html_class( $post->post_type, $post_id );
$classes[] = 'postid-' . $post_id;
// Post Format
if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
$post_format = get_post_format( $post->ID );
if ( $post_format && !is_wp_error($post_format) )
$classes[] = 'single-format-' . sanitize_html_class( $post_format );
else
$classes[] = 'single-format-standard';
}
}
}
@ -619,6 +636,23 @@ function get_body_class( $class = '' ) {
$mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' );
$classes[] = 'attachmentid-' . $post_id;
$classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type );
} elseif ( is_page() ) {
$classes[] = 'page';
$page_id = $wp_query->get_queried_object_id();
$post = get_post($page_id);
$classes[] = 'page-id-' . $page_id;
if ( get_pages( array( 'parent' => $page_id, 'number' => 1 ) ) ) {
$classes[] = 'page-parent';
}
if ( $post->post_parent ) {
$classes[] = 'page-child';
$classes[] = 'parent-pageid-' . $post->post_parent;
}
}
} elseif ( is_archive() ) {
if ( is_post_type_archive() ) {
@ -671,36 +705,6 @@ function get_body_class( $class = '' ) {
$classes[] = 'term-' . $term->term_id;
}
}
} elseif ( is_page() ) {
$classes[] = 'page';
$page_id = $wp_query->get_queried_object_id();
$post = get_post($page_id);
$classes[] = 'page-id-' . $page_id;
if ( get_pages( array( 'parent' => $page_id, 'number' => 1 ) ) ) {
$classes[] = 'page-parent';
}
if ( $post->post_parent ) {
$classes[] = 'page-child';
$classes[] = 'parent-pageid-' . $post->post_parent;
}
if ( is_page_template() ) {
$classes[] = 'page-template';
$template_slug = get_page_template_slug( $page_id );
$template_parts = explode( '/', $template_slug );
foreach ( $template_parts as $part ) {
$classes[] = 'page-template-' . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) );
}
$classes[] = 'page-template-' . sanitize_html_class( str_replace( '.', '-', $template_slug ) );
} else {
$classes[] = 'page-template-default';
}
}
if ( is_user_logged_in() )
@ -1621,14 +1625,12 @@ function get_the_password_form( $post = 0 ) {
*
* @since 2.5.0
* @since 4.2.0 The `$template` parameter was changed to also accept an array of page templates.
* @since 4.7.0 Now works with any post type, not just pages.
*
* @param string|array $template The specific template name or array of templates to match.
* @return bool True on success, false on failure.
*/
function is_page_template( $template = '' ) {
if ( ! is_page() )
return false;
$page_template = get_page_template_slug( get_queried_object_id() );
if ( empty( $template ) )
@ -1649,21 +1651,28 @@ function is_page_template( $template = '' ) {
}
/**
* Get the specific template name for a page.
* Get the specific template name for a given post.
*
* @since 3.4.0
* @since 4.7.0 Now works with any post type, not just pages.
*
* @param int $post_id Optional. The page ID to check. Defaults to the current post, when used in the loop.
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string|false Page template filename. Returns an empty string when the default page template
* is in use. Returns false if the post is not a page.
* is in use. Returns false if the post does not exist.
*/
function get_page_template_slug( $post_id = null ) {
$post = get_post( $post_id );
if ( ! $post || 'page' != $post->post_type )
function get_page_template_slug( $post = null ) {
$post = get_post( $post );
if ( ! $post ) {
return false;
}
$template = get_post_meta( $post->ID, '_wp_page_template', true );
if ( ! $template || 'default' == $template )
if ( ! $template || 'default' == $template ) {
return '';
}
return $template;
}

View File

@ -66,6 +66,7 @@ function create_initial_post_types() {
'add_new' => _x( 'Add New', 'add new media' ),
'edit_item' => __( 'Edit Media' ),
'view_item' => __( 'View Attachment Page' ),
'attributes' => __( 'Attachment Attributes' ),
),
'public' => true,
'show_ui' => true,
@ -1326,6 +1327,7 @@ function _post_type_meta_capabilities( $capabilities = null ) {
* post types. Default is 'Parent Page:'.
* - `all_items` - Label to signify all items in a submenu link. Default is 'All Posts' / 'All Pages'.
* - `archives` - Label for archives in nav menus. Default is 'Post Archives' / 'Page Archives'.
* - `attributes` - Label for the attributes meta box. Default is 'Post Attributes' / 'Page Attributes'.
* - `insert_into_item` - Label for the media frame button. Default is 'Insert into post' / 'Insert into page'.
* - `uploaded_to_this_item` - Label for the media frame filter. Default is 'Uploaded to this post' /
* 'Uploaded to this page'.
@ -1351,7 +1353,7 @@ function _post_type_meta_capabilities( $capabilities = null ) {
* @since 4.4.0 Added the `insert_into_item`, `uploaded_to_this_item`, `filter_items_list`,
* `items_list_navigation`, and `items_list` labels.
* @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.
* @since 4.7.0 Added the `view_items` label.
* @since 4.7.0 Added the `view_items` and `attributes` labels.
*
* @access private
*
@ -1374,6 +1376,7 @@ function get_post_type_labels( $post_type_object ) {
'parent_item_colon' => array( null, __('Parent Page:') ),
'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) ),
'archives' => array( __( 'Post Archives' ), __( 'Page Archives' ) ),
'attributes' => array( __( 'Post Attributes' ), __( 'Page Attributes' ) ),
'insert_into_item' => array( __( 'Insert into post' ), __( 'Insert into page' ) ),
'uploaded_to_this_item' => array( __( 'Uploaded to this post' ), __( 'Uploaded to this page' ) ),
'featured_image' => array( __( 'Featured Image' ), __( 'Featured Image' ) ),
@ -3393,7 +3396,7 @@ function wp_insert_post( $postarr, $wp_error = false ) {
$post = get_post( $post_ID );
if ( ! empty( $postarr['page_template'] ) && 'page' == $data['post_type'] ) {
if ( ! empty( $postarr['page_template'] ) ) {
$post->page_template = $postarr['page_template'];
$page_templates = wp_get_theme()->get_page_templates( $post );
if ( 'default' != $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) {

View File

@ -449,15 +449,17 @@ function get_search_template() {
*
* The hierarchy for this template looks like:
*
* 1. single-{post_type}-{post_name}.php
* 2. single-{post_type}.php
* 3. single.php
* 1. {Post Type Template}.php
* 2. single-{post_type}-{post_name}.php
* 3. single-{post_type}.php
* 4. single.php
*
* An example of this is:
*
* 1. single-post-hello-world.php
* 2. single-post.php
* 3. single.php
* 1. templates/full-width.php
* 2. single-post-hello-world.php
* 3. single-post.php
* 4. single.php
*
* The template hierarchy is filterable via the {@see 'single_template_hierarchy'} hook.
* The template path is filterable via the {@see 'single_template'} hook.
@ -466,6 +468,7 @@ function get_search_template() {
* @since 4.4.0 `single-{post_type}-{post_name}.php` was added to the top of the template hierarchy.
* @since 4.7.0 The decoded form of `single-{post_type}-{post_name}.php` was added to the top of the
* template hierarchy when the post name contains multibyte characters.
* @since 4.7.0 {Post Type Template}.php was added to the top of the template hierarchy.
*
* @see get_query_template()
*
@ -477,6 +480,10 @@ function get_single_template() {
$templates = array();
if ( ! empty( $object->post_type ) ) {
$template = get_page_template_slug( $object );
if ( $template && 0 === validate_file( $template ) ) {
$templates[] = $template;
}
$name_decoded = urldecode( $object->post_name );
if ( $name_decoded !== $object->post_name ) {

View File

@ -0,0 +1,5 @@
<?php
/*
Template Name: Sub Dir
Template Post Type: foo, post
*/

View File

@ -0,0 +1,5 @@
<?php
/*
Template Name: Top Level
Template Post Type: foo, post
*/

View File

@ -48,21 +48,41 @@ class Tests_Admin_includesTheme extends WP_UnitTestCase {
switch_theme( $theme['Template'], $theme['Stylesheet'] );
$templates = get_page_templates();
$this->assertCount( 3, $templates );
$this->assertEquals( "template-top-level.php", $templates['Top Level'] );
$this->assertEquals( "subdir/template-sub-dir.php", $templates['Sub Dir'] );
$this->assertEquals( "template-header.php", $templates['This Template Header Is On One Line'] );
$this->assertEqualSetsWithIndex( array(
'Top Level' => 'template-top-level.php',
'Sub Dir' => 'subdir/template-sub-dir.php',
'This Template Header Is On One Line' => 'template-header.php',
), get_page_templates() );
$theme = wp_get_theme( 'page-templates' );
$this->assertNotEmpty( $theme );
switch_theme( $theme['Template'], $theme['Stylesheet'] );
$templates = get_page_templates();
$this->assertCount( 3, $templates );
$this->assertEquals( "template-top-level.php", $templates['Top Level'] );
$this->assertEquals( "subdir/template-sub-dir.php", $templates['Sub Dir'] );
$this->assertEquals( "template-header.php", $templates['This Template Header Is On One Line'] );
$this->assertEqualSetsWithIndex( array(
'Top Level' => 'template-top-level.php',
'Sub Dir' => 'subdir/template-sub-dir.php',
'This Template Header Is On One Line' => 'template-header.php',
), get_page_templates() );
}
/**
* @ticket 18375
*/
function test_page_templates_different_post_types() {
$theme = wp_get_theme( 'page-templates' );
$this->assertNotEmpty( $theme );
switch_theme( $theme['Template'], $theme['Stylesheet'] );
$this->assertEqualSetsWithIndex( array(
'Top Level' => 'template-top-level-post-types.php',
'Sub Dir' => 'subdir/template-sub-dir-post-types.php',
), get_page_templates( null, 'foo' ) );
$this->assertEqualSetsWithIndex( array(
'Top Level' => 'template-top-level-post-types.php',
'Sub Dir' => 'subdir/template-sub-dir-post-types.php',
), get_page_templates( null, 'post' ) );
$this->assertEquals( array(), get_page_templates( null, 'bar' ) );
}
}

View File

@ -92,4 +92,70 @@ class Tests_Post_GetBodyClass extends WP_UnitTestCase {
$this->assertContains( "single-format-standard", $class );
}
public function test_page_template_body_classes_no_template() {
$post_id = self::factory()->post->create( array(
'post_type' => 'page',
) );
$this->go_to( get_permalink( $post_id ) );
$class = get_body_class();
$this->assertNotContains( 'page-template', $class );
$this->assertContains( 'page-template-default', $class );
}
public function test_page_template_body_classes() {
$post_id = self::factory()->post->create( array(
'post_type' => 'page',
) );
add_post_meta( $post_id, '_wp_page_template', 'templates/cpt.php' );
$this->go_to( get_permalink( $post_id ) );
$class = get_body_class();
$this->assertContains( 'page-template', $class );
$this->assertContains( 'page-template-templates', $class );
$this->assertContains( 'page-template-cpt', $class );
$this->assertContains( 'page-template-templatescpt-php', $class );
}
/**
* @ticket 18375
*/
public function test_page_template_body_classes_attachment() {
$post_id = self::factory()->post->create( array(
'post_type' => 'attachment',
) );
add_post_meta( $post_id, '_wp_page_template', 'templates/cpt.php' );
$this->go_to( get_permalink( $post_id ) );
$class = get_body_class();
$this->assertContains( 'attachment-template', $class );
$this->assertContains( 'attachment-template-templates', $class );
$this->assertContains( 'attachment-template-cpt', $class );
$this->assertContains( 'attachment-template-templatescpt-php', $class );
}
/**
* @ticket 18375
*/
public function test_page_template_body_classes_post() {
$post_id = self::factory()->post->create();
add_post_meta( $post_id, '_wp_page_template', 'templates/cpt.php' );
$this->go_to( get_permalink( $post_id ) );
$class = get_body_class();
$this->assertContains( 'post-template', $class );
$this->assertContains( 'post-template-templates', $class );
$this->assertContains( 'post-template-cpt', $class );
$this->assertContains( 'post-template-templatescpt-php', $class );
}
}

View File

@ -145,12 +145,6 @@ class Tests_Post_Objects extends WP_UnitTestCase {
update_post_meta( $post_id, '_wp_page_template', 'foo.php' );
$template = get_post_meta( $post->ID, '_wp_page_template', true );
$this->assertEquals( 'foo.php', $template );
// The post is not a page so the template is still empty
$this->assertEquals( '', $post->page_template );
// Now the post is a page and should retrieve the template
wp_update_post( array( 'ID' => $post->ID, 'post_type' => 'page' ) );
$post = get_post( $post_id );
$this->assertEquals( $template, $post->page_template );
}

View File

@ -271,16 +271,32 @@ NO;
/**
* @ticket 31389
* @ticket 18375
*/
public function test_get_page_template_slug_non_page() {
$post_id = self::factory()->post->create( array(
'post_type' => 'post',
) );
$post_id = self::factory()->post->create();
$this->assertFalse( get_page_template_slug( $post_id ) );
$this->assertEquals( '', get_page_template_slug( $post_id ) );
update_post_meta( $post_id, '_wp_page_template', 'default' );
$this->assertEquals( '', get_page_template_slug( $post_id ) );
update_post_meta( $post_id, '_wp_page_template', 'example.php' );
$this->assertEquals( 'example.php', get_page_template_slug( $post_id ) );
}
/**
* @ticket 18375
*/
public function test_get_page_template_slug_non_page_from_loop() {
$post_id = self::factory()->post->create();
update_post_meta( $post_id, '_wp_page_template', 'example.php' );
$this->go_to( get_permalink( $post_id ) );
$this->assertFalse( get_page_template_slug() );
$this->assertEquals( 'example.php', get_page_template_slug() );
}
/**

View File

@ -1043,6 +1043,17 @@ class Tests_Query_Conditionals extends WP_UnitTestCase {
$this->assertTrue( is_page_template( array('test.php', 'example.php') ) );
}
/**
* @ticket 18375
*/
function test_is_page_template_other_post_type() {
$post_id = self::factory()->post->create( array( 'post_type' => 'post' ) );
update_post_meta( $post_id, '_wp_page_template', 'example.php' );
$this->go_to( get_post_permalink( $post_id ) );
$this->assertFalse( is_page_template( array( 'test.php' ) ) );
$this->assertTrue( is_page_template( array( 'test.php', 'example.php' ) ) );
}
/**
* @ticket 35902
*/

View File

@ -36,6 +36,7 @@ class Tests_Template extends WP_UnitTestCase {
'post_date' => '1984-02-25 12:34:56',
) );
set_post_format( self::$post, 'quote' );
add_post_meta( self::$post->ID, '_wp_page_template', 'templates/post.php' );
}
public function setUp() {
@ -203,8 +204,12 @@ class Tests_Template extends WP_UnitTestCase {
) );
}
/**
* @ticket 18375
*/
public function test_single_template_hierarchy_for_post() {
$this->assertTemplateHierarchy( get_permalink( self::$post ), array(
'templates/post.php',
'single-post-post-name-😀.php',
'single-post-post-name-%f0%9f%98%80.php',
'single-post.php',
@ -228,6 +233,26 @@ class Tests_Template extends WP_UnitTestCase {
) );
}
/**
* @ticket 18375
*/
public function test_single_template_hierarchy_for_custom_post_type_with_template() {
$cpt = self::factory()->post->create_and_get( array(
'post_type' => 'cpt',
'post_name' => 'cpt-name-😀',
) );
add_post_meta( $cpt->ID, '_wp_page_template', 'templates/cpt.php' );
$this->assertTemplateHierarchy( get_permalink( $cpt ), array(
'templates/cpt.php',
'single-cpt-cpt-name-😀.php',
'single-cpt-cpt-name-%f0%9f%98%80.php',
'single-cpt.php',
'single.php',
'singular.php',
) );
}
public function test_attachment_template_hierarchy() {
$attachment = self::factory()->attachment->create_and_get( array(
'post_name' => 'attachment-name-😀',
@ -247,11 +272,37 @@ class Tests_Template extends WP_UnitTestCase {
) );
}
/**
* @ticket 18375
*/
public function test_attachment_template_hierarchy_with_template() {
$attachment = self::factory()->attachment->create_and_get( array(
'post_name' => 'attachment-name-😀',
'file' => 'image.jpg',
'post_mime_type' => 'image/jpeg',
) );
add_post_meta( $attachment, '_wp_page_template', 'templates/cpt.php' );
$this->assertTemplateHierarchy( get_permalink( $attachment ), array(
'image-jpeg.php',
'jpeg.php',
'image.php',
'attachment.php',
'single-attachment-attachment-name-😀.php',
'single-attachment-attachment-name-%f0%9f%98%80.php',
'single-attachment.php',
'single.php',
'singular.php',
) );
}
public function test_embed_template_hierarchy_for_post() {
$this->assertTemplateHierarchy( get_post_embed_url( self::$post ), array(
'embed-post-quote.php',
'embed-post.php',
'embed.php',
'templates/post.php',
'single-post-post-name-😀.php',
'single-post-post-name-%f0%9f%98%80.php',
'single-post.php',