2007-09-16 Microwave Lab(一)

又再消失了兩個星期,
實在是對不起我的讀者..

近來因為在做一單很有趣,
而且之前從沒有做過的類型的網站
而費枕忘餐的, 將工餘的時間都放了上去
連Drupal6 beta1 都還沒有下載
而且工作的過程之中, 更加發覺Drupal 的應用方面的強大

當初看見外國的 New york oberserver 網站
從它的一個 介紹 之中看到它的內部結構的精妙
為之著迷
一直想做一個類似的網站
但一直苦無一個資料性那麼強的網站作為試點
大家都好像一直在做社區性的網站
而忽略了"內容密集"型的

機緣巧合之下, 終於都找到一個資料性比較強網站的作為試點
雖然只是其中一個小的部份需要這麼複雜的結構
但也正好給我一個踏板
先從簡單的作起
而我也很快的接了這一案子

說了這麼久, 還是先介紹網站要求
這是一個大學其中一個實驗室的網站,
但因為實驗室的工作人員, 教授都會教學, 演講
各自有不同的班別
班別之中又有各種功課, 參考資料
全部的資料都會互相關連, 互相參考
工作人員(research staff), 教授(Professors), 班別(course), 功課(homework), lecture notes 等等
都會是一個node, 再用node reference, viewsfield 的型式 加上 argruments
互相控制, 做集合, 整匯
再加上複雜的角式分工
都是Drupal 的強項
所以花了特多的心機時間

因為項目還在功能試驗(functional test) 的階段
很多細節還沒有定下來
所以詳細的教學和各模組的相連關係要留待下一次再詳述
希望大家不要忘了我這個小小的站,
訂一個RSS, 有新的資料就會公告大家的了

Drupal 系統設計的事前企劃要注意事項

當你選用了drupal, 一個CMS,
作為你的網頁的系統
我想你的網頁應該是預計有一個定量的更新, 新增元件等等
所以, 在你設計你的系統的時候
記得一定是以"可持續發展"大前提

例如教學中的templates 部份,
因為可以改動的地方, 改動的方法等等都層出不窮
加一定量的注解是不可或缺的
而且, 注解是要在頁面的源碼中看到
即使用html 的注解方式,
使用<!--注解...-> 內嵌到template
令打開一個頁面, 查看源碼的時候
可以立即看到杓成這個頁面的元件, 使用過的template 等等
方便修改

而且, 同類的修改記使用同樣的方法作修改
網站一旦大起來, 維護的時間絕對會比開發的時間還長

這就是這三個星期沒有時間更新這裡換來的一個教訓
特此留字, 引以為鑑

使用templates 自定user 頁

終於來到預定的templates 最後一章
這次只是給多一個例子給大家參考
並沒有新的技術, 函數要認識, 使用

在一個用戶登入之後,
預設會到逹 user/[uid] 頁面
今次的目的就是改動這個頁面
例如:

  • 令登入都立即看到自己建立的nodes ( 配合使用views )
  • 不同的登入id 使用不同的頁面
  • 不同的roles 使用不同的頁面
  • 不同的profile fields(例如"城市")到不同的頁面

等等
建立社區主導的網站應該會使用到這個教學

因為url 為 user/[uid]
很有機會相關的輸出都是來自user/module
打開user/module, 到 user_menu() 函數
line 810 的 'path' 為 user/arg(1)
callback 到 user_view() 函數

line 1504 user_view(), 最後的一句:

<?php
 
return theme('user_profile', $account, $fields);
?>

找到了

到 user.module 內的 line 654, theme_user_profile()
將內裏的內容放到新建的 user_profile.tpl.php
'return' 改為 'print'
template 文件(user_profile.tpl.php) 放到你的theme 的目錄之下
user.module 的部份完成

到template.php 了, 打開你的theme 之下的template.php
新建一個函數, [theme_name]_user_profile()

<?php
function joe2_user_profile($account, $fields) {
  return
_phptemplate_callback( //此函數令drupal 找*.tpl.php
   
'user_profile', //找user_profile.tpl.php 文件來使用
   
array( 'account'=>$account , 'fields'=>$fields ), //傳給 user_profile.tpl.php
   
array( 'user_profile_'.$account->uid ) //根據你的特別要求, 使用不同的template, 注(一)
 
);
}
?>


注一:
這個例子建議使用user_profile_[uid].tpl.php (如有)
你也可以使用:
<?php
   
array( 'user_profile_'.$account->role )
?>

建議使用user_profile_[role].tpl.php (如有)

可以再配合template redirect, 轉到views 頁面等等,
就看你的創意了

以後要自定user 頁,
只要修改user_profile.tpl.php 就可以了

content-type 決定comment template

原本以為之前的一篇文章總結了*.tpl.php 的用法
但今天還是忍不住寫了這一篇:
content-type 決定comment template

例如, 如果有一個 comment-book.tpl.php 檔存在,
而你正在訪問的node 的node-type又是 book 的話,
drupal 就會使用comment-bookk.tpl.php, 而不使用comment.tpl.php

作為此系列的第二篇,
先從編程的角度解釋整個工作原理
再提供相關的代碼

首先打開modules/comment/comment.module
輕易的找到 theme_comment() 函數,
內裏包含了輸出的html 函數
根據drupal 的命名規則, 這個輸出用的函數可以在theme 內修改

例如, 一個module 內, 使用theme('example')
會順序找出一個輸出的函數, 順序為:
1. template.php 內的 %theme_name%_example() (注:%theme_name%為你的模版風格的名字)
2. template.php / phptemplate.engine 內的 phptemplate_example()
3. *.module 內的 theme_example()

這一次的theme_comment(), 我們可以用 phptemplate_comment() 或 %theme_name%_comment() 覆蓋它
令Drupal 的輸出使用我們定的template, 而不是comment.module 內的預設函數
但你會在phptemplate.engine 內發現一個phptemplate_comment() 函數
所以如果你重定義phptemplate_comment(), 會出現錯誤,
指你非法的"雙重定義"了
所以唯有使用 %theme_name%_comment()

在template.php 內建立一個函數

<?php
function joe2_comment(){
}
?>

(記得要將[joe2]改為你的theme 的名字)

這次的要求是 "不同的node-type 使用不同的comment輸出"
所以我們要知道node-type
要知道node-type 有很多方法
而這次使用了一個全局變量(global)
從theme('node') 的時候將node-type 放到全局變量
theme('comment') 的時候取回它

在template.php 內建立一個函數

<?php
function joe2_node($node, $teaser = 0, $page = 0) {
  if (
page == 0 ){ //只有full node view 的時候才需要這個變量
   
global $nodetype; //定義全局變量
   
$nodetype = $node->type; //設定變量值
 
}
  return
phptemplate_node($node, $teaser, $page); //呼叫phptmeplate.engine 內的函數
}
?>

(記得要將[joe2]改為你的theme 的名字)

上面的一小段代碼只是定義, 賦值一個全局變量
然後使用原本的phptemplate engine 的代碼
所以 joe2_comment() 可以使用 $nodetype 了

然後, 要令drupal 找出comment-[$nodetype].tpl.php (就像node-[$nodetype].tpl.php 一樣)
就要使用前一篇已經介紹過的 _phptemplate_callback() 函數

這一次使用到第三個參數:

<?php
function joe2_comment($comment, $links = 0){
  global
$nodetype; //使用全局變量
 
return _phptemplate_callback('comment', //第一個參數是預設template 檔, comment.tpl.php
   
array(  //第二個參數是一個陣列, 傳給template 檔(*.tpl.php)的
   
'author'    => theme('username', $comment),
   
'comment'   => $comment,
   
'content'   => $comment->comment,
   
'date'      => format_date($comment->timestamp),
   
'links'     => isset($links) ? theme('links', $links) : '',
   
'new'       => $comment->new ? t('new') : '',
   
'picture'   => theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', $comment) : '',
   
'submitted' => t('Submitted by !a on @b.',
                      array(
'!a' => theme('username', $comment),
                           
'@b' => format_date($comment->timestamp))),
   
'title'     => l($comment->subject, $_GET['q'], NULL, NULL, "comment-$comment->cid")
  ),array(
'comment-'.$nodetype) //第三個參數是建議的template 檔, 所以傳 'comment-'.$nodetype
);
}
?>

這樣, 如果有一個 comment-book.tpl.php 檔存在,
而你正在訪問的node 的node-type又是 book 的話,
drupal 就會使用comment-bookk.tpl.php, 而不使用comment.tpl.php 了

Regions

update2: Druapl 6.x regions
D6 update: Region 的定義在 .info 之內, 以下內容只適用於 D5 (2010-03-10)

新的模版有一個比較特別的地方,
就是自定了三個位於頁尾的regions,
而沒有使用panels.

當然, 第一是效能的考慮,
二來, 因為每一頁都會有這三個頁尾區
製作眾多panels 只費時失事

增加regions是theme 的管轄範圍
初初我也感到意外, 但為了保持彈性和可定製性
留在theme 的層面也是相當的合理
定製也只需要初階的編程能力
一般的模版開發者是可以應付得來的

在template.php 之內, 定義一個函數:

<?php
function mytheme_regions(){
  return array(
   
'right' => t('right sidebar'),
   
'content' => t('content'),
   
'header' => t('header'),
   
'footer' => t('footer'),
   
'bottom_left' => t('bottom left'),
   
'bottom_center' => t('bottom center'),
   
'bottom_right' => t('bottom right'),
  );
}
?>

mytheme 是這個theme的名字,
那樣, $bottom_right, $bottom_left, $bottom_center 等的變數就會出現在page.tpl.php 之內
你可以將它們放到自定的位置, div 之內
//page.tpl.php
<?php if ( $bottom_left || $bottom_center || $bottom_right || $feed_icons ):?>
......

到 admin->site building->blocks 就會看到有'bottom left' 等等的選項了

Pages

Google