php – Joomla! 製作模板

自訂一個模板路徑,假設名稱叫做 mynewtemplate 那就放在 template/mynewtemplate 。新增一些檔案與路徑:

  • css/ 自行設計的樣式
    • template.css 範例樣式
  • html/ 改寫模組的輸出 HTML 區塊
    • style/ 我自訂的視覺 HTML,為了將區塊 Chrome 分離出視覺
      • banner.html 這些都是視覺模板
      • XXX.html
      • ……
    • modules.php 覆蓋渲染樣式區塊的定義,這裡只處理邏輯的部分
  • 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 放置在專案根目錄。

發表迴響