別再只會 echo ‘Hello World’!資深工程師帶你打造第一個『真正有用』的 WordPress 外掛
嗨,我是浪花科技的 Eric。在網路上搜尋「WordPress 外掛開發教學」,你大概會看到一百篇教你如何建立一個只會印出「Hello World」的外掛。沒錯,那是一個起點,但然後呢?很多教學就停在這裡了,讓你望著那行孤單的文字,不知道下一步該往哪走。說實話,這種感覺就像是駕訓班教練只教你發動引擎,然後就叫你上高速公路一樣,有點不負責任啦。
今天,我這個有點囉嗦的工程師就要帶你跨出那關鍵的下一步。我們不只做「Hello World」,我們要打造一個「真正有用」的外掛。這個外掛或許很簡單,但它會涵蓋外掛開發的核心概念:檔案結構、鉤點(Hooks)、短代碼(Shortcode),以及一些重要的開發好習慣。準備好了嗎?泡杯咖啡,打開你的編輯器,我們來寫點真正能派上用場的 Code!
WordPress 外掛的骨架:不只是個 PHP 檔案
在我們開始寫任何功能之前,必須先理解 WordPress 是如何「辨識」一個外掛的。它不是靠檔名,也不是靠你虔誠的祈禱,而是靠一個寫在 PHP 檔案最上方的「外掛標頭」(Plugin Header)。這就像是一個外掛的身分證,告訴 WordPress 它的名字、作者、版本等重要資訊。
一個最基本的外掛結構長這樣:
- 一個專屬的資料夾,例如
my-first-useful-plugin - 一個主要的 PHP 檔案,例如
my-first-useful-plugin.php
為什麼要多此一舉用資料夾包起來?工程師的囉嗦時間又到了:這是為了「可擴展性」和「整潔」。未來你的外掛可能會需要加入 CSS、JavaScript 檔案,或是其他的 PHP 檔案。從一開始就把所有東西都放在一個專屬的資料夾裡,才不會讓你的 wp-content/plugins 目錄變成一場災難。相信我,你未來的同事(或幾個月後的你自己)會感謝你今天的好習慣。
關鍵的身分證:外掛標頭 (Plugin Header)
打開你的主 PHP 檔案,在最一開始的地方,我們要加入這段註解。這就是外掛的身分證:
<?php
/**
* Plugin Name: 我的第一個實用外掛
* Plugin URI: https://roamer-tech.com/
* Description: 這是一個用來展示短代碼功能的示範外掛,比 Hello World 有用多了!
* Version: 1.0.0
* Author: Eric @ Roamer Tech
* Author URI: https://roamer-tech.com/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: my-first-useful-plugin
* Domain Path: /languages
*/
// 如果這個檔案被直接存取,就中止執行。保護你的程式碼是基本功!
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
這裡面,Plugin Name 是最重要的,沒有它,WordPress 根本不會在後台顯示你的外掛。其他的欄位也都盡量填寫完整,這是一個專業開發者的表現。特別注意最後那段 if ( ! defined( 'ABSPATH' ) ),這是一道基本的安全防線,防止有人直接透過 URL 存取你的 PHP 檔案,幾乎所有專業的外掛和主題都會有這行,把它當成你的起手式吧!
實戰開始:打造一個可客製化的「公告」短代碼
我們的目標是建立一個短代碼,讓使用者可以在文章或頁面中輕鬆插入一個樣式化的公告訊息。例如,輸入 [my_announcement]這是一則重要的公告![/my_announcement],就會顯示一個漂亮的公告框。
步驟一:註冊你的短代碼
我們要用 WordPress 提供的 add_shortcode() 函數來「註冊」我們的短代碼。這個函數需要兩個參數:短代碼的名稱(別人要輸入的文字),以及一個回呼函數( जब這個短代碼被觸發時要執行的 PHP 函數)。
在你的主 PHP 檔案中,加入以下程式碼:
function roamer_tech_announcement_shortcode( $atts, $content = null ) {
// 短代碼的邏輯會寫在這裡
return '<div class="roamer-announcement">' . esc_html( $content ) . '</div>';
}
add_shortcode( 'my_announcement', 'roamer_tech_announcement_shortcode' );
看到了嗎?我把函數命名為 roamer_tech_announcement_shortcode。這就是我前面提到的「前綴」(Prefixing)。在 WordPress 的世界裡,所有的外掛和主題的函數都活在同一個全域命名空間中。如果你把函數取名為 announcement_shortcode(),萬一有另一個外掛也用了同樣的名稱,網站就直接白畫面給你看。所以,養成幫所有自訂函數、類別、常數加上獨特前綴的習慣,是避免衝突的救命丹。
在上面的程式碼中,我們的函數接收了兩個參數:$atts (Attributes,屬性) 和 $content(內容)。$content 就是使用者包在 [my_announcement] 和 [/my_announcement] 之間的文字。我們用 esc_html() 把它包起來,這又是一個重要的安全習慣,確保輸出的內容是乾淨的,避免潛在的 XSS 攻擊。
步驟二:讓短代碼更靈活 – 加入屬性 (Attributes)
現在我們的短代碼只能顯示一種樣式。如果我們想讓使用者可以自訂公告的類型(例如:資訊、警告、成功)呢?這時候就要用到 $atts 了。
我們來修改一下函數,讓它可以接收一個 type 屬性,例如 [my_announcement type="warning"]警告訊息[/my_announcement]。
function roamer_tech_announcement_shortcode( $atts, $content = null ) {
// 1. 設定預設屬性值
$attributes = shortcode_atts(
array(
'type' => 'info', // 預設是 'info' 類型
),
$atts
);
// 2. 根據屬性決定 CSS class
$class = 'roamer-announcement ' . 'roamer-announcement-' . sanitize_html_class( $attributes['type'] );
// 3. 組合並回傳 HTML
if ( ! empty( $content ) ) {
return '<div class="' . esc_attr( $class ) . '">' . esc_html( $content ) . '</div>';
}
return ''; // 如果沒有內容,就回傳空字串
}
add_shortcode( 'my_announcement', 'roamer_tech_announcement_shortcode' );
這裡多了幾個新東西:
shortcode_atts(): 這是 WordPress 的一個超實用函數。它會幫你合併使用者傳入的屬性 ($atts) 和你設定的預設值。如果使用者沒有提供type屬性,它就會自動使用預設的'info'。sanitize_html_class(): 另一個安全函數。它會確保從屬性拿到的值是合法的 CSS class 名稱,過濾掉不安全的字元。esc_attr(): 用來淨化要放在 HTML 屬性裡的內容(例如class="...")。
你看,一個看似簡單的功能,背後卻隱含了許多關於預設值處理、安全性、程式碼健壯性的思考。這就是工程師的日常。
步驟三:加上一點樣式
只有 HTML 是不夠的,我們需要一點 CSS 讓它看起來更專業。我們需要一個方法把 CSS 檔案「注入」到網站前端。最好的方法就是使用 WordPress 的鉤點 (Hook)。
我們使用 wp_enqueue_scripts 這個 Action Hook 來載入我們的 CSS。
// 將 CSS 檔案排入佇列
function roamer_tech_enqueue_styles() {
// 註冊並載入 CSS
wp_enqueue_style(
'roamer-plugin-styles', // 給這個樣式一個獨特的 handle (名稱)
plugin_dir_url( __FILE__ ) . 'assets/css/style.css', // CSS 檔案的路徑
array(), // 這個 CSS 依賴的其他樣式 handle,這裡沒有
'1.0.0' // 版本號
);
}
add_action( 'wp_enqueue_scripts', 'roamer_tech_enqueue_styles' );
這段程式碼做了幾件事:
- 我們定義了一個函數
roamer_tech_enqueue_styles。 - 在函數裡,我們使用
wp_enqueue_style()來告訴 WordPress:「嘿,幫我把這個 CSS 檔案加到網頁的<head>裡」。 plugin_dir_url( __FILE__ )是一個魔法函數,它會自動取得你外掛資料夾的 URL 路徑,確保路徑永遠是正確的。- 最後,我們用
add_action()把我們的函數「掛」到wp_enqueue_scripts這個鉤點上。這表示當 WordPress 準備要輸出前端的 scripts 和 styles 時,就會執行我們的函數。
現在,你需要在你的外掛資料夾裡建立一個 assets/css/ 的路徑,然後在裡面放一個 style.css 檔案。內容大概像這樣:
/* My First Useful Plugin Styles */
.roamer-announcement {
padding: 15px 20px;
margin: 20px 0;
border-left: 5px solid #0073aa;
background-color: #f7f7f7;
border-radius: 4px;
}
.roamer-announcement-info {
border-left-color: #0073aa; /* 藍色 */
}
.roamer-announcement-warning {
border-left-color: #ffb900; /* 黃色 */
background-color: #fff8e5;
}
.roamer-announcement-success {
border-left-color: #46b450; /* 綠色 */
background-color: #f0f8f2;
}
到這裡,把你的外掛打包成 .zip 上傳到 WordPress 後台,啟用它。然後到任何一篇文章或頁面,用文字編輯器輸入:
[my_announcement type="warning"]這是一則警告訊息![/my_announcement]
[my_announcement type="success"]操作成功![/my_announcement]
你應該就能看到我們精心設計的公告框了!
總結:從「Hello World」到解決問題
恭喜你!你已經完成了你的第一個「真正有用」的 WordPress 外掛。我們從最基本的檔案結構和標頭開始,學習了如何用 add_shortcode 建立一個可擴展的功能,並透過 add_action 和 wp_enqueue_style 掌握了載入資源的正確方式。更重要的是,我們在過程中不斷強調了前綴、程式碼安全這些專業開發中不可或缺的好習慣。
這只是一個開始。WordPress 外掛開發的世界非常廣闊,還有 Settings API、Custom Post Types、REST API 等著你去探索。但今天你所學到的,是通往那片廣闊天地的堅實基礎。記住,寫程式不只是為了讓電腦執行指令,更是為了解決實際問題。從今天起,試著去想:「有什麼重複性的工作,可以寫個小外掛來自動化?」當你開始用這種思維模式看待 WordPress,你的開發功力將會突飛猛進。
延伸閱讀
- 解鎖 WordPress 的任督二脈:搞懂 Action & Filter Hooks,你的客製化功力瞬間爆發!
- 解鎖 WordPress 的隱藏力量:functions.php 終極實戰指南,讓你的網站秒變客製化神器!
- 告別短代碼地獄!資深工程師手把手教你打造 Gutenberg 自訂區塊,釋放 WordPress 編輯器的真正潛力
如果你在開發路上遇到了任何瓶頸,或是你的企業有更複雜的 WordPress 客製化需求,別忘了浪花科技的團隊隨時都在這裡。我們不只寫程式,我們打造解決方案。
常見問題 (FAQ)
Q1: 為什麼一定要幫我的 PHP 函數加上「前綴」(Prefix)?
A1: 因為 WordPress 的所有外掛和主題的程式碼都運行在同一個「全域命名空間」下。如果你定義了一個很通用的函數名稱,例如 get_posts(),非常有可能會和 WordPress 核心或其他外掛的函數名稱衝突,導致 PHP 致命錯誤 (Fatal Error),也就是俗稱的「死亡白畫面」。加上一個獨一無二的前綴(例如你的公司或外掛縮寫)是避免這種災難最簡單也最有效的方法。
Q2: 除了短代碼 (Shortcode),還有其他在文章中插入動態內容的方法嗎?
A2: 有的!隨著 WordPress 區塊編輯器 (Gutenberg) 的普及,現在更推薦的方法是開發「自訂區塊」(Custom Block)。自訂區塊提供了更佳的使用者體驗,使用者可以直接在編輯器中看到預覽效果,並透過側邊欄的選項來設定,比記憶短代碼的屬性要直觀得多。我們在延伸閱讀中有提供相關教學,建議在熟悉短代碼後可以深入研究。
Q3: `add_action` 和 `add_filter` 到底有什麼不一樣?
A3: 這是個好問題!簡單來說,add_action 是用來在 WordPress 運行的特定時間點「執行某個動作」,例如我們用它來載入 CSS 檔案。它通常不期望你回傳任何東西。而 add_filter 則是用來「修改」資料的,它會接收一個值,讓你對它進行處理後,再把修改後的值「回傳」回去。例如,你可以用 filter 來修改文章標題的顯示方式。可以參考我們關於 Hooks 的深度文章來了解更多細節。






