file

目前本站採用的 WordPress 佈景主題是 Mynote,這個主題整體來說並不差,但是因為我個人實在太龜毛,難免會有一些小地方是我並不完全滿意、想要自己加以調整的。當然,向作者請求功能也是一種辦法,但是就我所見這個主題的作者並沒有非常積極地在回應 GitHub 上頭的各種 issue。當然我這樣講並不是要批評啦,畢竟有的時候人就是會有別的事要忙、或是也有很多時候維護一個套件的程式碼久了也會逐漸失去動力之類的,這都很難避免。

幸好,作者在 Mynote 的第二版當中已經把其程式架構用 WordPress 的正規寫法改寫成很容易被覆寫的形式,使得我們可以很容易製作子佈景主題(child theme)來達成在不去修改原始佈景主題的情況下增添或修改一些功能。子佈景主題的意義就是其依賴的父佈景主題可以繼續自動更新,而使得父佈景主題更新完成之後、子佈景主題當中客製化的部份不會跟著消失。我不知道 Mynote 的作者是否改天又會再來繼續維護,而當那發生的時候,我確實也希望希望可以跟著更新(哪怕只是為了不要讓 WordPress 持續提示我「有可用的更新」的這種動機也好),此時我就需要一個子佈景主題了。

本篇中我簡單介紹一下子佈景主題的製作方法;更多資訊可以參考官方的說明文件

基本設置

雖然存在一些 WordPress 的外掛號稱可以用來簡單製作子佈景主題,但我很懷疑那類的外掛真的實用,畢竟子佈景主題要做得好是真的需要一定程度的程式碼理解能力的;如果存在一個使用上很簡單、連不懂程式碼的人都能用的子佈景主題產生器,那我相信它肯定沒辦法做到很好的客製化。所以這種東西我想還是手刻比較實在。

Mynote 很好心地在原始碼裡面放了一套最陽春的子佈景主題基本配置、放在 mynote-child 資料夾當中,裡面包括了必要的 style.css 檔案、以及要顯示在佈景主題列表中的 screenshot.png 圖片。其中 style.css 的重點在於最一開始的註解中會需要給出此子佈景主題的相關資訊:

/*
Theme Name: Mynote Child
Theme URL: https://terryl.in
Description: Mynote Child Theme
Author: Mu-Tsun Tsai
Author URL: https://github.com/MuTsunTsai
Template: mynote
Version: 1.0.0
Text Domain: mynote-child
*/

其中 Template 一行就只是指定父佈景主題用的,其餘的都很好理解。要安裝此佈景主題,只要把 mynote-child 資料夾的內容做成一個 zip 壓縮檔,再到 WordPress 後台上傳安裝即可。

覆寫樣式規則

直覺上可能會以為此時我們只要在這個 style.css 檔案裡面寫上覆寫的樣式規則就會立刻生效;可惜沒那麼簡單。這個 style.css 終究只是一個樣式表檔案,如果沒有加入對應的 <link> 到產出的頁面之上的話、寫在裡頭的規則當然不會生效。為了要注入樣式表,我們需要利用 wp_enqueue_scripts 的 action hook:

add_action( 'wp_enqueue_scripts', 'mynote_child_styles' );
function mynote_child_styles() {
    // 用這個函數來產生出 `<link>` 標籤
    wp_enqueue_style(
        // 第一個參數是這個樣式表的 id;其它的樣式表可以依賴此 id
        'child-style',
        // 第二個參數要傳入樣式表的路徑;
        // 用底下這個函數便可抓出佈景主題的 style.css 的路徑
        get_stylesheet_uri(),
        // 第三個參數傳入的陣列表示此樣式表要依賴的其它樣式表的 id;
        // WordPress 會自動把這個樣式表擺在這些依賴樣式表的後面,
        // 以便可以覆寫掉這些樣式表中定義的規則
        array( 'mynote', 'bootstrap' ),
        // 最後一個參數是協助快取控制用的版本號,
        // 可以用底下的方法直接抓取
        wp_get_theme()->get('Version')
    );
}

覆寫範本檔

除了 functions.php 之外,任何出現在子佈景主題目錄中的範本 php 檔案都會取代掉父佈景主題中對應路徑的檔案。有的時候我們未必需要覆寫掉一整個檔案、可能可以只去修改檔案當中引用到的一些 hook 就達到想要的修改效果,但是其中一個我想做的修改是使得 Mynote 的頁面也出現側欄(原本的設計是只有文章會出現側欄),而我發現對應的範本檔 page.php 當中側欄理論上應該出現的位置那邊根本沒有任何的 hook 可以用,此時我就只好把一整個 page.php 複製過來,然後在我指定的地方插入側欄的程式碼:

...
            </main>

            <?php
                // 在頁面上也添加側欄
                do_action( 'mynote_page_sidebar' );
            ?>

        </div><!-- .row -->
...

這個 mynote_page_sidebar 的 action 是我自己定義出來的,原本的 Mynote 裡面只有 mynote_post_sidebar 而已,而且我不能直接拿一樣得來用,因為原本定義的 action 裡頭下了一個判斷 mynote_is_sidebar()、這個函數並沒有開放覆寫、且其判斷就是會忽略掉頁面的情況。我當然也可以去覆寫掉 mynote_post_sidebar 的 action,但基於語意起見我還是乾脆宣告了自己的 action 比較妥當。

覆寫函數

跟範本檔案不同地,唯獨 functions.php 這個檔案不會覆寫掉父佈景主題中的對應檔案,而是會搶在父佈景主題的 functions.php 之前先執行,因此我們可以在這裡面搶先宣告一些同名的函數來覆寫掉父佈景主題中的函數。不過,這有個前提是父佈景主題中的函數必須允許我們來覆寫。那樣的函數在宣告上會有類似下面這樣的結構:

if ( ! function_exists( 'my_function' ) ) {
    function my_function() {
        ...
    }
}

也就是說,只有當這個函數名稱還不存在的時候,父佈景主題才會去佔用掉這個函數名稱,因此只要在這之前先宣告了一樣名字的函數,該函數就會取代掉父佈景主題中定義的同名函數。

如果父佈景主題中的函數不是採用這種結構宣告的、而是直接寫在程式碼的最上層,那麼該函數就沒有辦法被覆寫,此時我們就只能看看有沒有別手法可以達到我們想要的修改,例如去更改呼叫該函數的上層結構(尤其是範本,如前一節中所示)、或者去修改該函數裡面用到的、可覆寫的下層函數,又或者是註冊 filter 來改變父佈景主題輸出的結果等等,可能性很多,必須見招拆招來改。


分享此頁至:
最後修改日期: 2021/07/07

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。