theming

自定Views 欄位輸出 Views fields display

開發多了以後, 慢慢發展了一個自己比較喜歡的 views templating 方式, 分享一下

1. Row style
絕大部份 "Row style" 都會使用 "fields",
是為了靈活性, 可以在 "Fields" 取需要的欄位
相反 "Row style" "node" 只可以選擇 "full node" 或者 "teaser"
而且它的輸出就會使用 node.tpl.php
不方便, 我習慣自己建立 "frontpage" 資料夾專門用作放置該 views 的 template 的

2. *.tpl.php 儲存結構
續上, 一個 views 在該 theme 之內都有一個資料夾
甚至是一個 display 一個, 例如 views "frontpage":
--theme_joe (資料夾)
----frontpage (資料夾)
------views-view-fields--frontpage.tpl.php
----taxonomy (資料夾)
------views-view-fields--taxonomy.tpl.php

3. 專注在 "Row style" 自定輸出
在 theme information 中的 views-view-field*.tpl.php 是最好用的
可以自定以一個 result 為單位的 templates,
通常我都將views 自定的 HTML tags 全部移除
換上我需要的, 以一個 row 為單位重覆的 HTML,

<div class="row">
  <div class="pic"><?php echo $field_picture[0]['view'?></div>
  <div class="right">
    <div class="title"><?php echo $title; ?></div>
    <div class="description"><?php echo $field_description[0]['view'?></div>
  </div>
</div>

要留意的是, 使用 <?php echo $field_description[0]['view'?>
便要自己設定 "display as"
上例的的 picture 便要使用 "image" 或者 "image link to node"
而不可以使用 "generic file" 或者 "URL to file"

又或者, 你打算 image 的 alt 使用 title,
pic 用 "URL to file", views-view-fields*.tpl.php:

<img src="<?php echo $field_picture[0]['view'?>" alt="<?php echo $title; ?>" />

Render Imagecached image through PHP

<?php
echo theme('imagecache', $preset, $imagepath, $alt, $image_title)
?>

在 node.tpl.php 內可用
其中 $preset 是imagecache profile 的 machine name

ref: http://drupal.org/node/163561

views 表格頭 theming (table header theming)

先修文章:
http://joetsuihk.com/node/94
http://joetsuihk.com/node/95

Views 的table header是可以使用 *.tpl.php 修改的,
常見的應用包括使用 icon 而不使用 text 作為 label
只要修改 style output 的 views-view-table.tpl.php

<?php
// $Id: views-view-table.tpl.php,v 1.8 2009/01/28 00:43:43 merlinofchaos Exp $
/**
* @file views-view-table.tpl.php
* Template to display a view as a table.
*
* - $title : The title of this group of rows.  May be empty.
* - $header: An array of header labels keyed by field id.
* - $fields: An array of CSS IDs to use for each field id.
* - $class: A class or classes to apply to the table, based on settings.
* - $row_classes: An array of classes to apply to each row, indexed by row
*   number. This matches the index in $rows.
* - $rows: An array of row items. Each row is an array of content.
*   $rows are keyed by row number, fields within rows are keyed by field ID.
* @ingroup views_templates
*/
?>

<table class="<?php print $class; ?>">
  <?php if (!empty($title)) : ?>
    <caption><?php print $title; ?></caption>
  <?php endif; ?>
  <thead>
    <tr>
<?php //表格頭輸出開始: ?>
      <?php foreach ($header as $field => $label): ?>
        <th class="views-field views-field-<?php print $fields[$field]; ?>">
          <?php print $label; ?>
        </th>
<?php //表格頭輸出完結:?>
      <?php endforeach; ?>
    </tr>
  </thead>
  <tbody>
    <?php foreach ($rows as $count => $row): ?>
      <tr class="<?php print implode(' ', $row_classes[$count]); ?>">
        <?php foreach ($row as $field => $content): ?>
          <td class="views-field views-field-<?php print $fields[$field]; ?>">
            <?php print $content; ?>
          </td>
        <?php endforeach; ?>
      </tr>
    <?php endforeach; ?>
  </tbody>
</table>

開發者只需要將 foreach 改成多個 if
就個別欄位表格頭輸出所需之 icon 圖像

看似簡單, 但如果表格頭需要 sortable, 並指示排序方向的話
便要再加一個 if case 檢查 $_GET['order'] 作不同輸出
奇怪 $views 變數之中竟然沒有 sort order 的資料

魔鬼都在細節之中...

Drupal7 的 模版改變 Drupal7 theming changes

DrupalCon SF 之後, 有很多 video 和session 都放到網上了
花了幾天的時間看了些自己喜歡的, 例如 A peek at Drupal 7 theme system changes

翻譯一下 http://www.slideshare.net/pingv/grok-drupal-7-theming (不是全部的改變, 詳情參考 ref2)
1. Drupal 7 theme 需要有以下元素:

  • CSS file
  • image
  • template (*.tpl.php)
  • js
  • preprocess 和 process (new)
  • .info

2. 將 page.tpl.php 分成 html.tpl.php 和 page.tpl.php
html.tpl.php 會放 DOCTYPE 一類的 tag

3. node.tpl.php 需要用 <?php render($content['comments']); ?> 才會顯示留言 (D6是預設自動加上)

4. 新增 region.tpl.php

5. node-[contenttype].tpl.php 改成 node--[contenttype].tpl.php
單劃表示連接字, 例如 content type 為 "super story" 時, 便使用 node--super-stoty.tpl.php

ref1: A peek at Drupal 7 theme system changes http://pingv.com/blog/a-peek-at-drupal-7-theme-system-changes

ref2: Converting 6.x themes to 7.x http://drupal.org/update/theme/6/7

模版的預處理 template preprocess in Drupal 6.x

繼續 Drupal templates 的深度遊

Preprocess 是一個在你的theme 之內的 template.php 內的一組函數
用"一組" 的原因是因為一個theme 是可以有很多 preprocess function
正確來講, 一個 hook 便已經可以有10個 preprocess function (當然, 和 hook 一樣, 不用也是可以的)

而preprocess 的真正功用是,

  1. 為 templates 提供更多的變數以供使用
  2. 為hook 提供更多的template suggestion

第一點的功能很明顯, 因為 drupal 內建的 preprocess function (無錯, Drupal core 都是使用 preprocess 的)沒法為你的theme 的特殊性供你需要的變數
你便可以使用preprocess function:

<?php
//template.php 中提供一個 $foo_list 陣列
function yourtheme_preprocess_foo(&$vars) {
 
$vars['foo_list'] = array(
   
'list item 1',
   
'list item 2',
   
'list item 3',
  );
}

//sites/all/themes/yourtheme/foo.tpl.php 中便可以使用:
print $foo_list;
?>

待續 template suggestions......

ref:
preprocess functions http://drupal.org/node/223430

進階 views 模版(二): HTML 列表 Complex views templating, part 2, table, HTML list templates

part1

補一下 table 顯示之下的 theming.

假如你的 table 有4個 fields, views 的 theming information 便有6個 templates:
1個 display 的 tpl (page 或block)
1個 style tpl, 包含了 <table>
每1個 field 都可以有一個自己的 tpl (詳見 attachment)

HTML list (ul, ol) 也是同樣的情況
display + style tpl, 外加每個field 一個tpl
也可以做 field by field 的 tpl, 修改 <ul> 的class, <li>多個 span 之類

最後, 雖然和 views 無關, 但pager 也經常由 views 產生
但 views 的 pager 都是使用 core 的pager, theme_pager()
theme 的時候沒有 tpl, 要在 template.php 修改, 或者使用preprocess 提供 tpl

Theme-ing "login to post comment", theme_comment_post_forbidden()

Recently, i have find some theme-ing functions that cannot be simply find by theme developer module, as that theme function only calls when you are anonymous user.

comment.module theme_comment_post_forbidden() is an example.
This function render the "Please login to post comments" to anonymous user, request them to login in order to get access to the comment form.

As theme developer do not appears when you are not admin, so when i want to theme this sentence, i spend some time to find out the function is defined in comment module, which is reasonable.

Hope this small tips helps someone.

加js, css file 到theme, Add a theme specific js/css to a page

如題, 你可以在 theme 的 .info file 用以下的方法

scripts[] = js/gallery.js

stylesheets[all][] = css/gallery.css

你可以加第三方的 js/css, 例如 jquery ui, fancybox 之類
如果你看到你的page.tpl.php 有<script type="text/javascript" src=""></script>你可能會考慮用以上的方法include 了

Note1: 路徑是相對到theme 的資料夾
Node2: 它們會被優化的, 如果你開啟了壓縮 js/css 檔案的話

As titled, if you want to add a js or css file only to a theme, you may:

scripts[] = js/gallery.js

stylesheets[all][] = css/gallery.css

This should contain mostly contain some 3rd party js/css libraries/frameworks.
if you find you put some <script type="text/javascript" src=""></script> in page.tpl.php, you better think again to put it like above.

Note1: the path they refered is CURRENT_THEME directory
Node2: They will got aggregated if you turn on compressing js/css files in "Performance" page

將註冊時連續輸入兩次密碼的表單的字眼改掉

將註冊時連續輸入兩次密碼的表單的字眼改掉的方法:

theme 的 template.php 內:

<?php
function phptemplate_password($element) {
  if(
$element['#id']=='edit-pass-pass1'){
   
$element['#title']=t('joe');
  }

  if(
$element['#id']=='edit-pass-pass2'){
   
$element['#title']=t('confirm joe');
  }

 
$size = $element['#size'] ? ' size="'. $element['#size'] .'" ' : '';
 
$maxlength = $element['#maxlength'] ? ' maxlength="'. $element['#maxlength'] .'" ' : '';

 
_form_set_class($element, array('form-text'));
 
$output = '<input type="password" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. $maxlength . $size . drupal_attributes($element['#attributes']) .' />';
  return
theme('form_element', $element, $output);
}
?>

其實其他的form 元素都可以用同一個方法改
甚至改為select 都可以
但亂改一通可能會令數據庫資料丟失
所以, 結構邏輯的修改還是使用 hook_form_alter() 吧

Drupal6.x 自定form template

今日重看form template 的組成 :http://www.joetsuihk.com/form_templates6
混亂得我自己都看不明白, 所以重寫

目的: 重新排位, 令建立新node 的表單簡單點

假設: 要重新排位的 content type 名為 story

  1. 在theme 內建立檔案 node_form.tpl.php
  2. http://api.drupal.org/api/function/theme_node_form 的函數內容貼到 node_form.tpl.php (除去函數開頭結尾), return 改為 print (或直接使用附件)
  3. 打開theme 內的 template.php
  4. 建立函數 function phptemplate_preprocess_node_form()
  5. function phptemplate_preprocess_node_form(&$vars) {
      $vars['template_files'][] = $vars['form']['type']['#value']."-node_form";
    }

  6. 複製node_form.tpl.php 為 story-node_form.tpl.php (theme 內要保留一個可用的node_form.tpl.php)
  7. 修改為:(附件2)
  8.   $output = "\n<div class=\"node-form\">\n";

      $admin = '';
      if (isset($form['author'])) {
        $admin .= "    <div class=\"authored\">\n";
        $admin .= drupal_render($form['author']);
        $admin .= "    </div>\n";
      }
      if (isset($form['options'])) {
        $admin .= "    <div class=\"options\">\n";
        $admin .= drupal_render($form['options']);
        $admin .= "    </div>\n";
      }
      $buttons = drupal_render($form['buttons']);

      $advance = drupal_render($form['menu']);
      $advance .= drupal_render($form['revision_information']);
      $advance .= drupal_render($form['comment_settings']);

      // Everything else gets rendered here, and is displayed before the admin form
      // field and the submit buttons.
      $output .= "  <div class=\"standard\">\n";
      $output .= drupal_render($form);
      $output .= "  </div>\n";

      if (!empty($admin)) {
        $output .= "<div><fieldset class='collapsible collapsed advanced standard'>";
        $output .= "<legend>Advance</legend>";
        $output .= "<div class='fieldset-wrapper'>";
        $output .= $admin.$advance;
        $output .= "</fieldset></div></div>\n";
       
      }
      $output .= "<div>$buttons</div>";
      $output .= "</div>\n";

      print $output;

重點:
第四步, $vars['form']['type']['#value'] 是content type 名, $vars 可以用kprint_r() 或者 theme developer 查看可以變數
第五步, 一定要留一個node_form.tpl.php 在theme 之內, 是Drupal 對自定義template 的要求
第六步, 使用過drupal_render() 的表單元素並不會在drupal_render($form); 再輸出, 只輸出未使用過的元素, 很方便