php – Joomla! 製作模板
自訂一個模板路徑,假設名稱叫做 mynewtemplate 那就放在 template/mynewtemplate 。新增一些檔案與路徑:
- css/ 自行設計的樣式
- template.css 範例樣式
- html/ 改寫模組的輸出 HTML 區塊
- style/ 我自訂的視覺 HTML,為了將區塊 Chrome 分離出視覺
- banner.html 這些都是視覺模板
- XXX.html
- ……
- modules.php 覆蓋渲染樣式區塊的定義,這裡只處理邏輯的部分
- style/ 我自訂的視覺 HTML,為了將區塊 Chrome 分離出視覺
- images/ 自訂放圖片的位置
- javascript/ 自訂 JS 的部分
- views/ (官方沒有這個項目,這是我為了將模板做出邏輯視覺分離。官方的程式碼都夾在一起)
- main.php 提供給 index.php 的模板
- index.php 邏輯處理後,使用 views/main.php 輸出模板
- templateDetails.xml 提供給 Joomla! 的安裝資訊
安裝設定檔
templateDetails.xml
<?xml version="1.0" encoding="utf-8"?> <extension version="3.1" type="template"> <name>mynewtemplate</name> <creationDate>2008-05-01</creationDate> <author>John Doe</author> <authorEmail>john@example.com</authorEmail> <authorUrl>http://www.example.com</authorUrl> <copyright>John Doe 2008</copyright> <license>GNU/GPL</license> <version>1.0.2</version> <description>My New Template</description> <files> <filename>index.php</filename> <filename>templateDetails.xml</filename> <folder>images</folder> <folder>css</folder> </files> <positions> <position>breadcrumb</position> <position>header</position> <position>left</position> <position>right</position> <position>top</position> <position>user1</position> <position>user2</position> <position>user3</position> <position>user4</position> <position>footer</position> </positions> </extension>
<files> 底下的 <filename> 主要是當壓製成 zip 安裝道系統時,Joomla! 會知道要複製那些文件。但因為我的範例使用 Joomla! 探索直接安裝,所以 <filename> 這部分不是很重要。
<positions> 底下放置定位的位置名稱,例如 left ,這個是讓我們在後台指定模板時,打算呈現在哪個位置的標記名稱。
邏輯架構
index.php
<?php defined('_JEXEC') or die('Restricted access'); require_once JPATH_ROOT . '/vendor/autoload.php'; $loader = new \Jsnlib\Joomla\Template\Loader($this); // 指定資源 $loader->setAssets( [ // 全域 'global' => [ 'global' => [ [$loader->site("css/template.css"), "css"], ] ], // 分頁 'com_todolist' => [ 'form.index' => [ [$loader->site("css/template.css"), "css"], ], 'form.upload' => [ [$loader->site("javascript/global.js"), "js"], ], ], // 首頁 'com_content' => [ // 網址沒有 task 的時候 'default' => [ [$loader->site("css/template.css"), "css"], ], ], ]); echo $loader->render(__DIR__ . "/views", function ($properties) { // 可查看內部屬性 // print_r($properties['option']); });
我這裡透過 composer 安裝我寫好的套件 jsnlib/joomla_template_loader,可以將邏輯視覺分離。index.php 基本上只判斷目前網頁位於哪個元件(component) 或使用了哪個 task,再引用不同的 CSS 或 JavaScript 。
透過 setAssets() 指定不同 component 與不同 task 所需要用到的資源,再使用 render() 渲染 views/main.php 模板。
視覺模板
views/main.php
<!DOCTYPE html> <html xml:lang="{{doc.language}}" lang="{{doc.language}}" > <head> <jdoc:include type="head" /> {% for path in assets.css %} <link rel="stylesheet" type="text/css" href="{{ path }}"> {% endfor %} {% for js in assets.js %} <script src="{{js}}"></script> {% endfor %} </head> <body> <header> <jdoc:include type="modules" name="header" style="header" /> </header> <div class="container"> <div class="top"> <jdoc:include type="modules" name="top" style="banner" /> </div> <div class="left"> <jdoc:include type="modules" name="left" style="left" /> </div> <div class="main"> <jdoc:include type="component" /> </div> <div class="right"> <jdoc:include type="modules" name="right" style="right" /> </div> <div style="clear: both"></div> </div> <footer> <jdoc:include type="modules" name="footer" style="footer" /> </footer> </body> </html>
<header>
我們使用了 Twig 這套知名的模板語言,我們輸出了 index.php 定義不同頁面會用到的資源。
<jdoc>
這邊使用了許多 <jdoc> 標籤,當 type=”modules” 代表這是給模組使用的插槽,而 name=”top” 對應的是我們 xml 中定義 <position>top</position>,表示這個模組的位置叫做 top,通常我們會放在網頁上方。
至於更詳細呈現 “上方” 我們則提供給 CSS 去決定。所以在這些模組中的 name,我們只做定義,而不實作樣式。
<jdoc:include type=”component” /> 則無法指定 name。整份文件理論上只會出現一個 component 元件,因為元件的概念就是整個最外層的功能架構:一個元件中可以包含多個模組。
自訂模組的呈現 HTML
html/modules.php
<?php require_once JPATH_BASE . '/vendor/autoload.php'; use \Jsnlib\Joomla\Template\Chrome; Chrome::dir(__DIR__); function modChrome_banner($module, &$params, &$attribs) { Chrome::render('banner.html', function () use ($module) { return ['module' => $module]; }); }
我們在 views/main.php 看到許多 <jdoc> 有個 style=”banner” 這種自訂的屬性,代表 banner 是一個我們自訂的呈現方式。它將對應 html/modules.php 中的 modChrome_banner() 。
modChrome_{我們自訂的 style 名稱}
因為使用了我寫的輔助功能 jsnlib/joomla_template_chrome,所以也能將 Chrome 區塊將邏輯與視覺分離。邏輯 function 的定義全放在 html/modules.php ,透過 render() 可以讀取 html/style/xxx.html 模板。所以這個範例 modChrome_banner() 會讀取 html/style/banner.html:
<div class="{{ module.module }}"> {{ module.content | raw }} </div>
因為模板語言 {{ }} 會顯示純文字,但是 module.content 屬於 HTML 編碼,我們要添加 | raw 來讓 HTML 不會被 Twig 安全性過濾掉,可以參考官方說明。
同理若 <jdoc:include type=”modules” name=”header” style=”header” /> 會使用 modChrome_header() 呼叫 view/style/header.html 。
關於資源的部分
因為模板是整個資料夾封裝起來,所以引用任何的 JavaScript 與 CSS 不建議與其他模板共用。當然 PHP 引用 Library 的時候,其實也應該一併放在自訂模板 mynewtemplate 底下,例如 mynewtemplate/vendor/ 。但因為 PHP 在 Joomla! 扮演的角色屬於整體架構,而且自訂模板的部分,我不打算上傳提供給每個人使用,只做應用在客製化接案的個案上,所以 vendor 我選擇與主程式共用,也就是 vendor 放置在專案根目錄。