問題描述

(主持人注意:標題最初是 「如何將”Page Attributes” 和/或」 頁面屬性> 模板 「選擇器添加到 POSTS 編輯器」)

WP 目前只允許將”template” 分配給 Pages(即 post_type=='page') 。我也想將此功能擴展到帖子 (即 post_type=='post') 。

如何添加”Page Attributes” 元框,更具體地説,模板切換到帖子編輯器?

我假設這是代碼,我將放在我的 functions.php 為我的主題。

更新:我已經設法添加硬編碼模板下拉菜單到我的帖子編輯器,只需將選擇框 html 添加到我現有的自定義元選項框。這是我正在使用的代碼…

add_meta_box('categorydiv2', __('Post Options'), 'post_categories_meta_box_modified', 'post', 'side', 'high');

這裏是寫出選項和模板選擇框的功能…

//adds the custom categories box
function post_categories_meta_box_modified() {
    global $post;
    if( get_post_meta($post->ID, '_noindex', true) ) $noindexChecked = " checked='checked'";
    if( get_post_meta($post->ID, '_nofollow', true) ) $nofollowChecked = " checked='checked'";
?>
<div id="categories-all" class="ui-tabs-panel">
    <ul id="categorychecklist" class="list:category categorychecklist form-no-clear">
        <li id='noIndex' class="popular-category"><label class="selectit"><input value="noIndex" type="checkbox" name="chk_noIndex" id="chk_noIndex"<?php echo $noindexChecked ?> /> noindex</label></li>
        <li id='noFollow' class="popular-category"><label class="selectit"><input value="noFollow" type="checkbox" name="chk_noFollow" id="chk_noFollow"<?php echo $nofollowChecked ?> /> nofollow</label></li>
    </ul>

    <p><strong>Template</strong></p>
    <label class="screen-reader-text" for="page_template">Post Template</label><select name="page_template" id="page_template">
    <option value='default'>Default Template</option>
    <option value='template-wide.php' >No Sidebar</option>
    <option value='template-salespage.php' >Salespage</option>
    </select>
</div>
<?php
}

最後,代碼捕獲所選值保存…

function save_post_categories_meta($post_id) {
    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $post_id;
    $noIndex = $_POST['chk_noIndex'];
    $noFollow = $_POST['chk_noFollow'];
    update_post_meta( $post_id, '_noindex', $noIndex );
    update_post_meta( $post_id, '_nofollow', $noFollow );
    return $post_id;
}

現在,我相信剩下的是 (1) 捕獲所選模板並將其添加到此帖子的後期元素中,(2) 修改 index.php 和 single.php,以便它使用所選的模板。

最佳解決方案

不喜歡成為壞消息的承載者,但是 WordPress 將頁面模板功能重新編碼為”page” 的帖子類型,至少在 v3.0 中 (可能會在將來的版本中更改,但是我沒有注意到改變它的具體方案。所以這是很少的時候,我正在努力找出如何擺脱一些沒有黑客核心的東西。)

我提出的解決方案是從 WordPress 核心基本上覆制相關代碼,並將其修改為我們的需求。以下是步驟 (行號為 v3.0.1):

  1. 複製/wp-admin/includes/meta-boxes.php 的第 535 行 page_attributes_meta_box()功能,並進行修改。

  2. 編寫一個 add_meta_boxes 鈎子來添加在#1 中創建的 metabox 。

  3. 複製/wp-admin/includes/theme.php 的第 166 行 get_page_templates()功能,修改即可。

  4. /wp-admin/includes/template.php 的 2550 行復制 page_template_dropdown()功能,並進行修改。

  5. 添加一個帖子模板到您的主題。

  6. 編寫一個 save_post 鈎子,以保存保存後的模板文件名。

  7. 編寫一個 single_template 鈎子,以啓用相關帖子的帖子模板的加載。

現在吧!


1. 複製 page_attributes_meta_box()功能

作為我們的第一步,您需要從/wp-admin/includes/meta-boxes.php 的第 535 行復制 page_attributes_meta_box()功能,我選擇將其重命名為 post_template_meta_box()。由於您只要求頁面模板,因此我省略了指定父帖子的代碼,並指定使代碼更簡單的順序。我也選擇使用 postmeta,而不是嘗試重用 page_template 對象屬性,以避免由於無意耦合引起的潛在的不兼容性。所以這裏是代碼:

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. 編寫一個 add_meta_boxes 鈎子

下一步是使用 add_meta_boxes 鈎子添加 metabox:

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. 複製 get_page_templates()功能

我認為區分頁面模板和帖子模板是有意義的,因此需要基於/wp-admin/includes/theme.php 第 166 行的 get_page_templates()get_post_templates()功能。但是,不使用 Template Name: 標記,該頁面模板使用該功能使用 Post Template: 標記,而您可以在下面看到。

我也濾除了 functions.php 的檢查 (不知道 get_page_templates()如何正常工作沒有,但無論如何!) 而唯一的事情是將 page 這個詞改為 post,以便維護可讀性:

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. 複製 page_template_dropdown()功能

同樣從/wp-admin/includes/template.php 的第 2550 行復制 page_template_dropdown(),創建 post_template_dropdown(),然後將其更改為調用 get_post_templates()

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 "nt<option value='".$templates[$template]."' $selected>$template</option>";
  endforeach;
}

5. 添加一個帖子模板

下一步是添加一個 post 模板進行測試。使用步驟 3 中提到的 Post Template: 標記將 single.php 從您的主題複製到 single-test.php,並添加以下注釋標題 (請確保在 single-test.php 中修改某些內容,以便您可以知道它正在加載而不是 single.php):

/**
 * Post Template: My Test Template
 */

一旦您完成步驟#1 到#5,您可以看到您的”Post Templates” metabox 出現在您的帖子編輯器頁面上:

6. 編寫一個 save_post 鈎子

現在你的編輯器已經平倉了,當用户點擊”Publish” 時,您需要實際將頁面模板文件名保存到 postmeta 。這是代碼:

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. 編寫一個 single_template 鈎子

最後你需要真正讓 WordPress 使用你的新帖子模板。您可以通過掛接 single_template 併為已分配的帖子返回所需的模板名稱:

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;
}

這就是它!

注意我沒有考慮到自定義帖子類型,只有 post_type=='post'。在我看來,解決定製職位類型需要區分不同的職位類型,而不是過分困難,我沒有在這裏嘗試。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。