編輯在區塊編輯器裡反覆貼同一段 CSS、或乾脆開一個新的自訂區塊,只為了讓某張圖片有圓角、某個按鈕變成外框樣式,這是很多 WordPress 網站長期累積技術債的起點。其實核心區塊本身就支援「樣式切換」,你只要用 register_block_style 把樣式註冊進選單,編輯就能在側邊欄一鍵套用,不必碰任何程式碼。
自訂區塊樣式(block styles)是把一段視覺處理包成可重複使用的選項,掛在現有區塊上。它背後的機制單純到出乎意料:WordPress 只是在區塊的外層元素加上一個 .is-style-{名稱} 的 CSS class,剩下的全靠你寫的 CSS 或 theme.json 設定接手。這篇會把 PHP、theme.json v3、JavaScript 三種註冊路徑講清楚,告訴你各自適合什麼情境,並補上多數教學跳過的兩塊:樣式註冊了卻不出現時怎麼排查,以及如何反向移除核心預設樣式來收斂編輯體驗。
自訂區塊樣式到底是什麼,跟區塊變體有何不同
自訂區塊樣式是替「現有區塊」準備的替代外觀選項,註冊後會出現在區塊側邊欄的「樣式」面板,讓編輯在預設樣式與你的版本之間切換。使用者一次只能套一種樣式,不能疊加。
運作原理只有一句話:被選取的樣式會在區塊外層元素掛上 .is-style-{name} 這個 class。例如你註冊一個叫 hand-drawn 的圖片樣式,套用後 HTML 就會多出 is-style-hand-drawn,接著由你提供的 CSS 針對 .wp-block-image.is-style-hand-drawn 去改外觀。理解這點很重要,因為之後排查問題、寫 CSS 選擇器,全都繞著這個 class 名稱打轉。
WordPress 生態裡有好幾個名字裡都帶「variation」的功能,很容易混淆,先分清楚:
- 區塊樣式(block style variation):本文主題,替單一區塊加替代外觀,掛
.is-style-class。 - 區塊變體(block variation):同一個區塊的不同預設組態,例如核心嵌入區塊底下的 YouTube、Twitter 其實是同一個 Embed 區塊的不同變體,差在預設屬性,不是換外觀。
- 全域樣式變體(global style variation):整站層級的配色與排版方案,放在主題
/styles資料夾,影響的是全站不是單一區塊。
三者各管各的,名字像但用途完全不同。本文只談第一種。
三種註冊方式怎麼選,先看這張對照表
註冊自訂區塊樣式有三條路:PHP 的 register_block_style()、theme.json v3 的 JSON 檔,以及 JavaScript 的 registerBlockStyle()。沒有哪一條絕對最好,取決於你在做主題還是外掛、要不要讓使用者用全域樣式介面再微調、以及目標 WordPress 版本。
| 方式 | 適合情境 | 需要的版本 | 使用者可在全域樣式再改 |
|---|---|---|---|
PHP register_block_style() + inline CSS |
外掛、或想把樣式邏輯集中在 PHP | WordPress 5.0+ | 否(純 inline CSS) |
PHP + style_data 參數 |
想用 theme.json 式寫法、又走 PHP | WordPress 6.6+ | 是 |
theme.json v3 的 /styles JSON 檔 |
區塊主題、想全部走標準化設定 | WordPress 6.6+ | 是 |
JavaScript registerBlockStyle() |
只想動編輯器選單、CSS 另外管 | WordPress 5.0+ | 否 |
簡單的判斷邏輯是這樣:如果你在做區塊主題、而且能要求 WordPress 6.6 以上,優先用 theme.json v3 的 JSON 檔,因為它最標準化,使用者還能在「外觀 → 編輯器 → 樣式」裡自行調整。如果你在做外掛、或必須相容舊版 WordPress,就用 PHP 的 register_block_style() 搭 inline_style。JavaScript 路徑現在主要用在「只想增減編輯器選單項目」的場景,因為它無法附帶伺服器端 CSS,樣式得另外想辦法載入。
用 register_block_style 在 PHP 裡註冊樣式
PHP 是最多主題作者採用的方式。register_block_style() 接收兩個參數:區塊名稱(含命名空間與 slug,例如 core/image)與一個描述樣式屬性的陣列,回傳布林值表示是否註冊成功。函式必須掛在 init hook 上。
屬性陣列裡 name 與 label 是必填,其餘可選:
name:樣式的唯一識別字,會拿去組成is-style-{name}這個 class。label:給人看的標籤,會顯示在編輯器選單,可翻譯。inline_style:直接寫進去的 CSS,樣式被使用時才輸出。style_handle:指向一個已用wp_register_style()註冊好的樣式表 handle。style_data:WordPress 6.6 新增,用 theme.json 式的陣列寫樣式。is_default:設true可把這個樣式設為該區塊的預設,預設值是false。
下面這段替圖片區塊加一個「手繪感」樣式,把它寫進主題的 functions.php:
add_action( 'init', 'ezwps_register_block_styles' );
function ezwps_register_block_styles() {
register_block_style( 'core/image', array(
'name' => 'hand-drawn',
'label' => __( '手繪感', 'ezwps' ),
'inline_style' => '.wp-block-image.is-style-hand-drawn img {
border: 2px solid currentColor;
box-shadow: 0 4px 10px 0 rgba( 0, 0, 0, 0.3 );
border-radius: 255px 15px 225px 15px/15px 225px 15px 255px;
}',
) );
}
存檔後進編輯器點一張圖片,側邊欄的「樣式」面板就會多出「手繪感」選項。inline_style 的好處是樣式只在這個區塊樣式被用到時才印出來,不會無謂地拖慢沒用到的頁面。但如果你的 CSS 超過幾行,塞在 PHP 字串裡會很難維護,這時改用 style_handle 指向一支獨立樣式表,或改走 theme.json 會清爽很多。
用 style_data 參數改用 theme.json 式寫法
style_data 是 WordPress 6.6 加進來的參數,讓你在 PHP 裡用「類 theme.json」的陣列結構描述樣式,而不必手寫 CSS 字串。它最大的附加價值是:用這個方式註冊的樣式,使用者能在「編輯器 → 樣式 → 區塊」介面裡自行調整,等於把調色權交還給網站經營者。
register_block_style(
array( 'core/image' ),
array(
'name' => 'orange-border',
'label' => __( '橘色外框', 'ezwps' ),
'style_data' => array(
'border' => array(
'color' => '#f5bc42',
'style' => 'solid',
'width' => '4px',
'radius' => '15px',
),
),
)
);
注意第一個參數現在也接受陣列,代表你可以一次把同一個樣式註冊給多個區塊,例如同時掛在 core/group 與 core/columns 上,這正是區段樣式(section styles)的基礎。
在區塊主題裡用 theme.json v3 的 JSON 檔註冊
對區塊主題開發者來說,最簡潔的做法是在主題的 /styles 資料夾新增一個 JSON 檔。這需要把 theme.json schema 升到 v3,而 v3 只有 WordPress 6.6 以上支援,所以你得把主題的最低版本需求訂在 6.6,或要求使用者裝 Gutenberg 外掛。
假設要給圖片區塊加一個藍色外框,建立 styles/blocks/image-blue-border.json:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "藍色外框",
"slug": "blue-border",
"blockTypes": [ "core/image" ],
"styles": {
"border": {
"color": "#00f9ff",
"style": "solid",
"width": "4px",
"radius": "15px"
},
"shadow": "var(--wp--preset--shadow--natural)"
}
}
這個檔案裡幾個關鍵欄位,對應的正是 PHP 版的參數:
title:等同 PHP 的label,會顯示給螢幕報讀器,也用來在沒給 slug 時自動推算識別字。slug:等同 PHP 的name,組成is-style-{slug}class,可含英數字、連字號、底線。blockTypes:一個陣列,指定這個樣式要套到哪些區塊,可填多個,不再限定單一區塊。
存檔後 WordPress 會自動把這個樣式註冊進區塊樣式登記表,選單立刻出現該選項,前後台都套用,而且能在「外觀 → 編輯器 → 樣式 → 區塊」裡再被使用者調整。把這類檔案集中放在 /styles/blocks 子資料夾,WordPress 會自動往子資料夾找,主題作者實測這樣能讓 functions.php 大幅瘦身。
區段樣式與巢狀元素讓 theme.json 接管更多
WordPress 6.6 還開放了一個更強的能力:替「巢狀在區塊內的元素與子區塊」設樣式。換句話說,一個區塊樣式不再只能改外層那一層,連裡面的連結、標題、段落都能一起設計。這就是常被稱作「區段樣式」的概念,本質仍是區塊樣式,只是把目標放到容器型區塊(Group、Columns、Cover)上,並深入它的內部元素。
實務上你可以在 theme.json 的 styles.blocks.區塊名.variations.樣式名 底下,再往下用 elements.link、blocks.子區塊名 去設巢狀樣式,甚至直接寫一個 css 屬性塞自訂 CSS。這對需要「整段切換配色、又要連內部標題段落一起變」的客戶網站特別好用,等於替特定區段建一套可更新的設計系統,改版時只動 theme.json 一處。
用 JavaScript 註冊與移除樣式,以及那個惱人的競態問題
JavaScript 路徑用的是 wp.blocks.registerBlockStyle(),語法和 PHP 版幾乎一樣,差在它只動編輯器選單、不帶伺服器端 CSS。要用它得先在 enqueue_block_editor_assets hook 上掛一支腳本:
add_action( 'enqueue_block_editor_assets', 'ezwps_block_editor_assets' );
function ezwps_block_editor_assets() {
wp_enqueue_script(
'ezwps-block-editor',
get_theme_file_uri( 'assets/js/block-editor.js' ),
array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' )
);
}
接著在 block-editor.js 裡註冊:
wp.blocks.registerBlockStyle( 'core/quote', {
name: 'fancy-quote',
label: 'Fancy Quote',
} );
由於 JavaScript 不負責輸出樣式,對應的 CSS 你得另外用區塊樣式表或主題樣式載入,針對 .is-style-fancy-quote 去寫。
移除樣式有個容易踩的坑,值得單獨講。要拿掉一個樣式用 wp.blocks.unregisterBlockStyle(),但問題在於「先註冊還是先反註冊」會有競態:如果你的反註冊程式碼比註冊程式碼早跑,等於沒作用。正解是把反註冊包進 wp.domReady(),並在 enqueue 時把 wp-edit-post 列為相依,確保你的程式碼在樣式註冊完、DOM 載入後才執行:
wp.domReady( function () {
wp.blocks.unregisterBlockStyle( 'core/quote', 'large' );
} );
這裡有一條鐵則:樣式用哪種語言註冊,就只能用哪種語言反註冊。PHP 註冊的樣式用 unregister_block_style() 移除,且要把 action 的優先序設高一點(例如 99)讓它在預設優先序 10 的註冊函式之後才跑;JavaScript 註冊的就得用 JavaScript 移除。兩者不能互換。
樣式註冊了卻不出現,照這幾點排查
註冊程式寫對了、選單卻沒反應,是上手階段最常見的卡關,多數教學偏偏跳過。遇到時依序檢查下面幾項,通常逃不出這幾種原因。
- 區塊名稱打錯:第一個參數必須是完整名稱含命名空間,例如
core/image不是image、core/quote不是quote。少了core/樣式會掛不上去也不報錯。 - 沒掛在 init hook 上:
register_block_style()一定要在init才呼叫,太早呼叫時區塊登記表還沒準備好。 - 快取沒清:站台若有頁面快取或物件快取,前台可能還在吃舊版。編輯器端則清瀏覽器快取、重整一次。ezwps 這類有裝快取外掛的站,改完務必把快取整批清掉再驗證。
- CSS 選擇器特定度不夠:樣式選單出現、卻看不出外觀變化,多半是你的
.is-style-xxx規則被核心或主題的既有 CSS 蓋過。先用瀏覽器開發者工具看 class 有沒有正確掛上,再視情況提高選擇器特定度,謹慎使用!important。 - 用 theme.json v3 卻沒升 schema:JSON 檔開頭的
"version"要是3,且站台需 WordPress 6.6 以上,版本不符時整個/styles檔會被忽略。 - 古典主題與區塊主題的差異:theme.json 的全域樣式介面調整能力,在古典主題上支援有限,這條路徑以區塊主題為前提。
把這幾點掃過一輪,九成的「樣式不出現」都能定位。剩下的少數情況,多半是和其他外掛搶註冊同名樣式,這時換一個夠獨特的 name 就能避開。
移除核心預設樣式,收斂編輯者的選擇
有時問題不是樣式太少,而是太多。核心區塊自帶的某些樣式(例如引言區塊的某些變體)若不符合品牌規範,留著只會讓編輯誤用。移除的原則前面提過:用什麼語言註冊就用什麼語言移除。
核心區塊的預設樣式多半是伺服器端註冊的,理論上用 unregister_block_style() 即可,但實務上要留意有些核心樣式是在客戶端(JavaScript)註冊的,那就得改用 unregisterBlockStyle() 搭 wp.domReady() 移除。判斷不出來時,兩種都試一次最快。移除後重整編輯器,原本的選項就會從面板消失,編輯能挑的範圍變得乾淨可控。
對需要維持視覺一致性的商業網站來說,這一步常被低估。與其事後一頁頁糾正編輯亂套的樣式,不如一開始就把不該用的選項拿掉,只留下符合品牌的幾個自訂樣式,從源頭降低出錯空間。
從一鍵套用到全站一致,自訂區塊樣式該怎麼落地
自訂區塊樣式的價值,在於把「設計決策」從每篇文章手動貼 CSS,收斂成一份可重複套用、可集中維護的選單。決定走哪條路前,先問自己三個問題:你在做主題還是外掛、能不能要求 WordPress 6.6 以上、要不要讓網站經營者在全域樣式介面再微調。答案會直接把你導向 theme.json v3、register_block_style() 加 style_data,或最傳統的 PHP 加 inline_style。
如果你正在整理一個 WooCommerce 商店的版面,會更有感:把品牌的按鈕外框、提示框、商品卡片邊框各做成一個區塊樣式,編輯上架商品時直接套,不必每次重調,全站風格也不會走樣。動手時記住那條 .is-style-{name} 的主軸,註冊完先用開發者工具確認 class 有沒有掛上、再回頭看 CSS 特定度,遇到選單沒反應就照上面那份排查清單跑一遍。先用核心圖片或引言區塊做一個最小範例驗證流程,再擴大到整套品牌樣式,是最穩的起手式。