Ghét phải là người mang tin xấu nhưng WordPress đã mã hóa chức năng Mẫu trang thành loại bài đăng "trang" , ít nhất là trong phiên bản 3.0 (có thể thay đổi trong các phiên bản trong tương lai nhưng không có sáng kiến cụ thể nào tôi biết để thay đổi nó Tuy nhiên, đây là một trong số rất ít lần tôi đấu tranh để tìm ra cách khắc phục thứ gì đó mà không hack lõi.)
Giải pháp tôi đã đưa ra là về cơ bản sao chép mã có liên quan từ lõi WordPress và sửa đổi nó theo nhu cầu của chúng tôi. Dưới đây là các bước (số dòng từ v3.0.1):
Sao chép page_attributes_meta_box()chức năng từ dòng 535 /wp-admin/includes/meta-boxes.phpvà sửa đổi cho phù hợp.
Mã hóa một add_meta_boxescái móc để thêm metabox được tạo trong # 1.
Sao chép get_page_templates()chức năng từ dòng 166 /wp-admin/includes/theme.php
và sửa đổi cho phù hợp.
Sao chép page_template_dropdown()chức năng từ dòng 2550 /wp-admin/includes/template.phpvà sửa đổi cho phù hợp.
Thêm một mẫu bài viết vào chủ đề của bạn.
Mã một save_posthook để cho phép lưu trữ tên tệp bài đăng khi lưu.
Mã một single_templatehook để cho phép tải mẫu bài đăng cho các bài đăng liên quan.
Bây giờ với nó!
1. Sao chép page_attributes_meta_box()chức năng
Là bước đầu tiên của chúng tôi, bạn cần sao chép page_attributes_meta_box()chức năng từ dòng 535 /wp-admin/includes/meta-boxes.phpvà tôi đã chọn đổi tên nó post_template_meta_box(). Vì bạn chỉ yêu cầu các mẫu trang, tôi đã bỏ qua mã để chỉ định một bài đăng gốc và để chỉ định thứ tự làm cho mã đơn giản hơn nhiều. Tôi cũng đã chọn sử dụng postmeta cho việc này thay vì cố gắng sử dụng lại thuộc tính page_templateđối tượng để tránh và sự không tương thích tiềm ẩn gây ra bởi khớp nối không chủ ý. Vì vậy, đây là mã:
function post_template_meta_box($post) {
if ( 'post' == $post->post_type && 0 != count( get_post_templates() ) ) {
$template = get_post_meta($post->ID,'_post_template',true);
?>
<label class="screen-reader-text" for="post_template"><?php _e('Post Template') ?></label><select name="post_template" id="post_template">
<option value='default'><?php _e('Default Template'); ?></option>
<?php post_template_dropdown($template); ?>
</select>
<?php
} ?>
<?php
}
2. Mã một add_meta_boxescái móc
Bước tiếp theo là thêm metabox bằng add_meta_boxeshook:
add_action('add_meta_boxes','add_post_template_metabox');
function add_post_template_metabox() {
add_meta_box('postparentdiv', __('Post Template'), 'post_template_meta_box', 'post', 'side', 'core');
}
3. Sao chép get_page_templates()chức năng
Tôi giả định rằng sẽ chỉ có ý nghĩa để phân biệt giữa các mẫu trang và mẫu bài do đó cần một get_post_templates()chức năng dựa trên get_page_templates()dòng 166 của /wp-admin/includes/theme.php. Nhưng thay vì sử dụng Template Name:điểm đánh dấu, mẫu trang nào sử dụng chức năng này sử dụng Post Template:điểm đánh dấu thay vì bạn có thể thấy bên dưới.
Tôi cũng đã lọc ra kiểm tra functions.php (không chắc bao get_page_templates()giờ hoạt động chính xác mà không có điều đó, nhưng bất cứ điều gì!) Và điều duy nhất còn lại là thay đổi các tham chiếu đến từ pageđể postbảo trì dễ đọc trên đường:
function get_post_templates() {
$themes = get_themes();
$theme = get_current_theme();
$templates = $themes[$theme]['Template Files'];
$post_templates = array();
if ( is_array( $templates ) ) {
$base = array( trailingslashit(get_template_directory()), trailingslashit(get_stylesheet_directory()) );
foreach ( $templates as $template ) {
$basename = str_replace($base, '', $template);
if ($basename != 'functions.php') {
// don't allow template files in subdirectories
if ( false !== strpos($basename, '/') )
continue;
$template_data = implode( '', file( $template ));
$name = '';
if ( preg_match( '|Post Template:(.*)$|mi', $template_data, $name ) )
$name = _cleanup_header_comment($name[1]);
if ( !empty( $name ) ) {
$post_templates[trim( $name )] = $basename;
}
}
}
}
return $post_templates;
}
4. Sao chép page_template_dropdown()chức năng
Tương tự sao chép page_template_dropdown()từ dòng 2550 của /wp-admin/includes/template.phpđể tạo post_template_dropdown()và chỉ cần thay đổi nó để gọi get_post_templates()thay thế:
function post_template_dropdown( $default = '' ) {
$templates = get_post_templates();
ksort( $templates );
foreach (array_keys( $templates ) as $template )
: if ( $default == $templates[$template] )
$selected = " selected='selected'";
else
$selected = '';
echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
endforeach;
}
5. Thêm một mẫu bài
Bước tiếp theo là thêm một mẫu bài đăng để thử nghiệm. Sử dụng Post Template:điểm đánh dấu được đề cập trong bước 3 sao chép single.phptừ chủ đề của bạn vào single-test.phpvà thêm tiêu đề nhận xét sau ( hãy chắc chắn sửa đổi một cái gì đó single-test.phpđể bạn có thể biết nó đang tải thay vì single.php) :
/**
* Post Template: My Test Template
*/
Khi bạn đã thực hiện các bước # 1 đến # 5, bạn có thể thấy metabox "Bài mẫu" xuất hiện trên trang biên tập bài đăng của mình:

(nguồn: mikechinkel.com )
6. Mã một save_postcái móc
Bây giờ bạn đã có trình soạn thảo bình phương, bạn cần phải thực sự lưu tên tệp mẫu trang của mình vào postmeta khi người dùng nhấp vào "Xuất bản". Đây là mã cho điều đó:
add_action('save_post','save_post_template',10,2);
function save_post_template($post_id,$post) {
if ($post->post_type=='post' && !empty($_POST['post_template']))
update_post_meta($post->ID,'_post_template',$_POST['post_template']);
}
7. Mã một single_templatecái móc
Và cuối cùng, bạn cần phải thực sự có được WordPress để sử dụng các mẫu bài đăng mới của bạn. Bạn làm điều đó bằng cách móc single_templatevà trả lại tên mẫu mong muốn của bạn cho những bài đăng đã được gán:
add_filter('single_template','get_post_template_for_template_loader');
function get_post_template_for_template_loader($template) {
global $wp_query;
$post = $wp_query->get_queried_object();
if ($post) {
$post_template = get_post_meta($post->ID,'_post_template',true);
if (!empty($post_template) && $post_template!='default')
$template = get_stylesheet_directory() . "/{$post_template}";
}
return $template;
}
Và đó là về nó!
LƯU Ý rằng tôi đã không xem xét các loại bài tùy chỉnh , chỉ post_type=='post'. Theo ý kiến của tôi, việc giải quyết các loại bài đăng tùy chỉnh sẽ yêu cầu phân biệt giữa các loại bài đăng khác nhau và trong khi không quá khó khăn, tôi đã không thử điều đó ở đây.