先釐清需求:你需要的是換選單,還是做會員權限?
要讓 WordPress 根據登入狀態顯示不同選單,核心做法是在子主題的 functions.php 裡用一段簡短的程式碼,透過 wp_nav_menu_args filter 搭…
要讓 WordPress 根據登入狀態顯示不同選單,核心做法是在子主題的 functions.php 裡用一段簡短的程式碼,透過 wp_nav_menu_args filter 搭配 is_user_logged_in(),在伺服器端把主選單位置自動指向 logged-in 或 logged-out 兩組選單。整段邏輯只靠 WordPress 原生條件標籤完成,不必安裝 Ultimate Member 這類會員外掛,也不必動到佈景主題的 header.php [來源:〈WordPress Code Reference — wp_nav_menu_args Hook〉〈https://developer.wordpress.org/reference/hooks/wp_nav_menu_args/〉〈2026〉]。
WordPress 目前驅動了全球 41.5% 的網站,在已知的內容管理系統裡更佔了 59.2% [來源:〈W3Techs — Usage Statistics and Market Share of WordPress〉〈https://w3techs.com/technologies/details/cm-wordpress〉〈2026-06-29〉]。這意味著你寫的這段條件判斷,幾乎可以套用到任何一台 WordPress 站,從個人部落格到大型電商都通用,長期維護成本低、跨主題可攜性高。
重點先看:條件式選單的關鍵是用
wp_nav_menu_argsfilter 在伺服器輸出階段決定只送哪一組選單,CSSdisplay:none隱藏那種偷懶寫法務必避開;只要寫對 filter 名稱與選單 slug,一段約 10 來行程式碼就能讓訪客看登入註冊、會員看我的帳戶 [來源:〈WordPress Code Reference — wp_nav_menu_args Hook〉〈https://developer.wordpress.org/reference/hooks/wp_nav_menu_args/〉〈2026〉]。
先釐清需求:你需要的是換選單,還是做會員權限?
條件式選單指的是 WordPress 依使用者的登入狀態或角色,在主選單位置自動輸出不同的導覽內容。它的本質是顯示層的切換,完全不碰內容權限,所以只要你的需求是「訪客看一組、會員看另一組」,就值得用原生條件標籤完成,不必把整套會員外掛搬進來。問題是,很多人一聽到「依身份顯示選單」就直覺聯想到 Ultimate Member 會員登入註冊表單設計,結果為了一個選單需求,背了一整套會員系統的維護成本。
先問自己一個問題:你到底要什麼?這聽起來像廢話,但我看過太多站長在這裡走偏。需求其實分成三個層級,搞清楚落在哪一層,才知道要不要寫程式、要不要裝外掛。
- 只換選單:訪客看到登入註冊,會員看到我的帳戶與登出。這是最常見的需求,用一段程式碼最快。
- 要會員分級瀏覽權限:付費會員才看得到某些頁面或文章,訪客連網址都打不開。這需要 Ultimate Member 依角色管理會員瀏覽權限 或 Paid Memberships Pro 這類權限外掛。
- 要完整會員社群:會員資料欄位、前後台個人資料頁、會員目錄、私信。這才值得導入整套會員系統。
第一層的需求,用原生條件標籤的程式碼做法最輕;後兩層才需要外掛。把順序顛倒,就是把簡單事做複雜的開始。一個常見的判斷方式是反問自己:如果今天把這個功能拿掉,會員連得到他要的頁面嗎?如果答案是「連得到,只是少了一個按鈕」,那你需要的就只是選單切換;如果答案是「連不到,整頁都打不開」,那才輪到權限外掛上場。
這裡有個關鍵觀念得先講清楚,否則後面會踩雷。條件判斷發生在 wp_nav_menu 輸出階段,伺服器只把該狀態該看的那組選單送出去。千萬不要用「兩組選單都輸出,再用 CSS display:none 隱藏」的偷懶寫法。那種做法會讓未登入訪客在檢視原始碼時,直接看到會員專區的網址,保護形同虛設。我之後在資安章節會再強調一次,因為這是條件式選單最容易出包的地方。
把這兩種做法放在一起對照,差異就一目瞭然。CSS 隱藏是「全部輸出,瀏覽器層挑著顯示」,原始碼裡兩組選單都在;filter 切換是「伺服器層就決定只輸出哪一組」,原始碼裡根本不存在另一組。前者省的是寫程式的工,付的代價是資安破口與搜尋引擎誤索引;後者多寫 10 行程式碼,換來的是真正乾淨的狀態隔離。對任何有會員機制的站,這 10 行的成本遠低於事後補救。
| 需求層級 | 範例情境 | 建議做法 | 要裝外掛嗎 |
|---|---|---|---|
| 只換選單 | 購物網站登入後秀我的帳戶 | 原生條件標籤程式碼 | 不用 |
| 分級瀏覽權限 | 付費會員才能看課程頁 | 權限外掛 | 要 |
| 完整會員社群 | 會員目錄、個人資料頁 | 會員系統外掛 | 要 |
判斷依據可以是登入狀態 is_user_logged_in(),也能細到使用者角色,例如 current_user_can('edit_posts') 用來區分後台能寫文的人。後者在做付費會員等級分眾時特別有用,進階章節會展開講。先記住一個原則:能解決問題的最輕做法,就是最好的做法。
後台準備:新增 logged-in 與 logged-out 兩組選單
動程式碼之前,先把後台的選單準備好。到「外觀 > 選單」新增兩組選單:一組命名 logged-out(給訪客,放登入、註冊),另一組命名 logged-in(給會員,放我的帳戶、登出)。名稱強烈建議用英文,而且要跟程式碼裡的 menu slug 完全對應,中文命名會讓判斷找不到對應選單而失效。
為什麼非得用英文不可?因為 WordPress 內部比對選單時,用的是 slug(系統內部識別名),中文選單名稱會被轉成一串不好預測的 slug,程式碼裡要對應得很痛苦。事後除錯往往比一開始就命名好更費時,所以建議直接用 logged-in、logged-out 這種一看就懂的英文命名。如果你還不熟悉後台操作,先翻一下 WordPress 後台從登入到設定全指南 會比較踏實。
- 後台左側選「外觀 > 選單」,點「建立新選單」。
- 選單名稱填
logged-out,按「建立選單」。 - 從左側把「登入」「註冊」頁面加入這組選單(沒有這些頁面就先 用區塊編輯器建一頁)。
- 顯示位置先勾 PrimaryMenu(主選單),方便預覽成果。
- 按「儲存選單」。
- 重複上述流程建立第二組,名稱填
logged-in,加入「我的帳戶」「登出」「會員專區」等項目,顯示位置這次先不勾。
第二組選單的顯示位置為什麼不勾?因為接著要用程式碼接管主選單位置的輸出,手動勾選反而會造成衝突。把控制權統一交給程式碼,日後維護才不會兩頭跑。順帶一提,如果你連主選單位置都還沒搞懂,可以看 WordPress 選單設定打造網站導覽 把基礎打好。
兩組選單其實可以共用部分項目,例如首頁、關於我們、聯絡我們這些大家都要看的連結,兩組都放一份就好,只在登入相關項目差異化。這樣能降低維護成本,日後改首頁連結時不用兩邊都改。如果你的站還沒有清楚的頁面分類,先參考 WordPress 文章與頁面的差異 釐清架構,選單做起來才不會亂。
這裡誠實說一個限制:不同主題的「顯示位置」名稱不一樣。Astra 主題叫 primary,有些主題叫 main-menu 或 primary-menu,還有些主題會額外拆出手機版選單位置。所以底下程式碼要針對你實際用的主題調整 location 名稱,照搬不一定能用。第一次做建議先用 Astra 免費主題新手架站教學 這類文件確認你的主題位置名稱。
要查自己主題到底定義了哪些 menu location,最快的辦法是到後台「外觀 > 選單」的「管理位置」分頁,那裡會列出主題提供的所有顯示位置與其內部名稱。另一個更精確的方式是到佈景主題資料夾找 functions.php 或 register_nav_menus() 的呼叫,裡面寫的就是 location 的 slug,例如 Astra 常見的是 primary。把這個 slug 抄下來,待會寫進 filter 的條件判斷裡,整個機制才接得起來。
複製貼上程式碼:用 is_user_logged_in 在 functions.php 切換選單
實際要貼的程式碼很短,掛載點是 wp_nav_menu_args filter,能在選單輸出前修改要顯示哪組 menu。判斷函數用 is_user_logged_in() 檢查登入狀態,再把主選單位置指向 logged-in 或 logged-out。整段程式碼貼進子主題的 functions.php,儲存即生效 [來源:〈WordPress Code Reference — is_user_logged_in()〉〈https://developer.wordpress.org/reference/functions/is_user_logged_in/〉〈2026〉]。
先給可以複製貼上的範例。這段假設你的主題主選單位置叫 primary,兩組選單的 slug 分別是 logged-in 與 logged-out。把它貼進子主題的 functions.php 最下方即可。
add_filter( 'wp_nav_menu_args', 'fk_switch_menu_by_login' );
function fk_switch_menu_by_login( $args ) {
if ( 'primary' === $args['theme_location'] ) {
if ( is_user_logged_in() ) {
$args['menu'] = 'logged-in';
} else {
$args['menu'] = 'logged-out';
}
}
return $args;
}
逐行解釋這段在做什麼,免得貼了卻不知道怎麼改。第一行用 add_filter 把自訂函數掛上 wp_nav_menu_args 這個 filter,WordPress 每次要輸出選單前都會經過它。if ( 'primary' === $args['theme_location'] ) 這層判斷很重要,它確保我們只改主選單位置,不會把頁尾選單、側邊欄選單也一起換掉。最內層的 is_user_logged_in() 就是分岔點:已登入回傳 logged-in 那組,未登入回傳 logged-out 那組,最後把修改過的 $args 還給 WordPress。
有一個常被忽略的細節:$args['menu'] 可以吃 slug、名稱或 menu ID 三種值,但建議固定用 slug。原因是一旦你用名稱,日後有人在後台把選單改名(例如把 logged-in 改成「會員選單」),程式碼裡的字串就對不上而悄悄失效,而且不會報錯,只會默默顯示空白或 fallback 到預設選單。用 slug 則不受改名影響,是三者裡最穩定的選擇。
為什麼不要直接改 header.php?因為 header.php 是佈景主題的範本檔案,改了之後下次更新主題就會被覆蓋掉,等於白做工。用 filter 的好處是邏輯集中、不碰範本、更新主題也不會掉。這也是 WordPress 官方推薦的延伸方式 [來源:〈WordPress Code Reference — wp_nav_menu()〉〈https://developer.wordpress.org/reference/functions/wp_nav_menu/〉〈2026〉]。
判斷函數怎麼選?只分登入與未登入,用 is_user_logged_in() 最直接;如果要分角色,例如只有管理員看到後台連結,就改用 current_user_can('edit_posts'),或用 in_array($role, wp_get_current_user()->roles) 比對角色陣列。後面進階章節會給完整範例。
這裡有四個最常見的失效原因,照著檢查就能排除絕大多數問題:選單英文 slug 拼錯(logged-in 打成 login-in)、filter 名稱打錯、theme_location 名稱跟主題定義不符、沒有子主題直接改母主題被覆蓋。其中第三點最陰險,Astra 是 primary,但換個主題可能就變了。
- 掛載點用
wp_nav_menu_argsfilter,不要改 header.php。 - 用
theme_location鎖定只改主選單,避免誤改其他位置的選單。 - 判斷函數:分登入狀態用
is_user_logged_in(),分角色用current_user_can()。 - 務必貼進 子主題 的 functions.php,否則更新主題程式碼會被洗掉。
講了這麼多,你或許會問:functions.php 到底是什麼、為什麼一定要子主題?簡單講,functions.php 是主題的「功能擴充檔」,WordPress 載入主題時會自動執行裡面的程式碼。但母主題更新時這個檔案會被新版覆蓋,所以才要建立子主題,把自訂程式碼放在子主題的 functions.php,既保留功能又不被更新吃掉。沒有子主題的話,先建一個再動手,否則更新主題一次,你寫的程式碼就全沒了。
如果你真的不想碰 functions.php,還有一條退路:用 Code Snippets 這類獨立外掛,把上面那段 filter 當成一則 snippet 來管理。效果一樣,好處是它獨立於主題之外,換主題或更新主題都不會被清掉,而且啟用停用都在後台圖形介面完成,對不熟 PHP 的站長是比較友善的折衷。不管走哪條路,程式碼裡的 logged-in、logged-out、primary 這幾個字串,都必須跟你後台實際的選單名稱與選單位置 slug 完全相符,差一個字就切換不了。
有些站長會把這段 filter 跟其他客製邏輯一起塞進一個自製外掛(所謂 site-specific plugin),而非子主題。這條路其實比子主題更穩,因為外掛完全不受主題切換影響,連換主題都不會掉程式碼。如果你預期未來可能換主題,或網站同時裝了好幾套主題輪流測試,把條件判斷收進自製外掛會比放在子主題更安全。簡單的外掛只需一個資料夾加一個主檔,標頭寫好 Plugin Name 註解就能在後台啟用,門檻比想像中低。
測試與驗證:用無痕視窗分別檢查訪客與會員畫面
程式碼貼完、儲存之後,要分別用訪客與會員兩種狀態驗證。最準的做法是開瀏覽器無痕視窗模擬訪客,確認只看到登入與註冊;再用已登入的分頁檢查是否切換成我的帳戶與登出。兩種狀態都要測,因為登入 session 會影響判斷結果,用同一個瀏覽器分頁容易看到快取住的舊選單。
為什麼非用無痕視窗不可?因為一般瀏覽器分頁會帶著你的登入 cookie,就算你以為已經登出,cookie 可能還殘留,導致判斷結果跟你預期的不一樣。無痕視窗不帶任何 cookie,等於一台全新的機器第一次造訪,測出來的訪客狀態最乾淨。這個小習慣能幫你省下好幾個小時的除錯時間。
- 開無痕視窗,造訪網站首頁,檢查主選單是否只剩登入、註冊。
- 在無痕視窗完成登入,重新整理,確認選單切換成我的帳戶、登出。
- 按右鍵檢視原始碼,確認頁面只輸出一組選單,不是兩組用 CSS 隱藏。
- 換手機檢視,測行動版漢堡選單是否也套用同一條件判斷。
- 若有裝快取外掛,登入相關頁面要排除快取,或開啟依使用者快取。
第三步驟的原始碼檢查不能省。在原始碼裡搜尋會員專區的網址,如果訪客狀態下還搜得到,就代表你的做法是 CSS 隱藏而非伺服器端切換,這時候要回頭檢查程式碼是不是真的用了 filter。這點對安全與 SEO 都重要,搜尋引擎與爬蟲也會讀原始碼,不要讓它們索引到不該出現的連結。
行動版選單是最容易被漏掉的環節。部分主題手機版的漢堡選單走另一組 menu location,例如 mobile_menu,跟桌機的 primary 是分開的。如果你只判斷 primary,手機版可能還是顯示舊選單。解法是在程式碼裡把行動版 location 也加進條件判斷,例如 if ( in_array( $args['theme_location'], array('primary','mobile_menu') ) )。
這一步之所以重要,是因為行動流量早已超過桌機。2026 年第一季,行動裝置(不含平板)就佔了全球網站流量的 52.27% [來源:〈Statista — Share of mobile web traffic worldwide quarterly 2015-2026〉〈https://www.statista.com/statistics/277125/share-of-website-traffic-coming-from-mobile-devices/〉〈2026-04-28〉]。也就是說,如果你的條件判斷只覆蓋桌機選單位置,等於對過半的訪客放任舊選單繼續顯示,等於這套機制做半套。測試時務必把手機版納入,否則上線後會員反映「手機登入後還看到登入鈕」時,你才發現漏了一整個 location。
如果你用了 快取外掛 例如 WP Rocket 或 LiteSpeed Cache,這裡要特別小心。頁面快取會把第一個造訪者的選單快取下來,之後所有人都看到那一份,結果是訪客看到上一個會員的「我的帳戶」,會員看到訪客的「登入」。解法是把含條件選單的頁面排除快取,或啟用外掛的「依使用者快取」功能,讓不同登入狀態各有獨立快取版本 [來源:〈WP Rocket — User Cache / Logged-in User Caching〉〈https://docs.wp-rocket.me/article/134-user-cache/〉〈2026〉]。想知道快取整體怎麼運作,先看過 快取 Cache 完整指南:加速網站速度與避免更新問題 會更清楚為什麼這一步躲不掉。
說到底,測試這一步考的不是技術,而是耐心。很多站長程式碼貼對了,卻因為沒徹底測兩種狀態,上線後才被會員反映「我怎麼還看到登入按鈕」。把上面五個步驟走完,八成以上的問題會在正式上線前被抓出來。
依使用者角色分級顯示選單(VIP、批發客戶、管理員)
如果想給特定角色看到專屬選單,例如付費會員、批發客戶、管理員各看一組,只要把判斷條件從 is_user_logged_in() 換成檢查使用者角色就行。用 current_user_can() 或比對 wp_get_current_user()->roles 陣列,就能讓訂閱者、客戶、管理員或自訂角色各看到一組選單。這是條件式選單從兩組擴充到多組的關鍵做法。
先看一個依角色切換三組選單的範例。假設你有三組選單:menu-wholesale 給批發客戶、menu-vip 給 VIP 會員、menu-default 給一般會員與訪客。判斷邏輯用 if-elseif 鏈收在一個函數裡,避免重複掛多個 filter 造成難以維護。
add_filter( 'wp_nav_menu_args', 'fk_switch_menu_by_role' );
function fk_switch_menu_by_role( $args ) {
if ( 'primary' !== $args['theme_location'] ) {
return $args;
}
$roles = wp_get_current_user()->roles;
if ( in_array( 'wholesale_customer', $roles ) ) {
$args['menu'] = 'menu-wholesale';
} elseif ( in_array( 'vip', $roles ) ) {
$args['menu'] = 'menu-vip';
} else {
$args['menu'] = 'menu-default';
}
return $args;
}
if-elseif 鏈的順序不是隨便排的,而是依「優先級從嚴到寬」的原則排列。上面範例把批發客戶放在最前面,是因為一個批發客戶可能同時被某些外掛誤授與 vip 角色,把從嚴的條件放前面,才能確保高權限身份拿到對應的專屬選單,不被後面的寬鬆條件攔截。實作多角色時請記得這條排序規則,否則容易出現「明明是 VIP 卻看到一般選單」的詭異狀況。
角色哪裡來?如果是自訂角色,例如 wholesale_customer 或 vip,得先用 User Role Editor 管控後台角色權限 或 Members 外掛把角色建出來。WordPress 預設只有訂閱者、投稿者、作者、編輯、管理員這幾種,要做批發、VIP 這類分眾,就得自己加角色與能力(capability)。
WooCommerce 的情境更簡單。顧客在 WooCommerce 完成註冊購物後,系統會自動產生 customer 這個角色,所以你不必手動建角色,直接用 in_array('customer', $roles) 就能區分「下過單的會員」與「還沒下單的訪客」[來源:〈WooCommerce Documentation — Customer Management & Roles〉〈https://woocommerce.com/document/woocommerce-orders/〉〈2026〉]。這對 購物網站架設 的站長特別實用,可以讓客戶登入後直接看到我的帳戶與訂單追蹤。
| 角色 | 產生方式 | 判斷寫法 | 適用情境 |
|---|---|---|---|
| customer | WooCommerce 註冊後自動 | in_array('customer', $roles) | 區分下單與未下單 |
| vip(自訂) | User Role Editor 建立 | in_array('vip', $roles) | 付費 VIP 專屬選單 |
| wholesale_customer | 批發外掛或手動建立 | in_array('wholesale_customer', $roles) | 批發客戶看到批發價選單 |
| administrator | WordPress 內建 | current_user_can('manage_options') | 管理員看到後台入口 |
角色判斷會跟會員外掛的自訂角色疊加。如果你同時用了 線上課程 LMS 外掛 或 Paid Memberships Pro,它們也會建立自己的角色,這時候要確認角色 slug 命名一致,否則兩套系統各玩各的,判斷邏輯會打架。建議把所有角色判斷集中收在單一函數裡,用 switch 或 if-elseif 鏈一次處理,這樣日後要加新角色,只要在鏈上多一條分支就好。
這裡也順帶提一個實用搭配。如果你想在會員登入後,把選單的「我的帳戶」直接連到個人專屬頁面,可以搭配 WooCommerce 結帳表單客製化 或 會員購物金與等級制度 一起設計,讓選單不只切換,還能引導會員走完你設定的動線。
不寫程式的替代方案:Ultimate Member 與頁面編輯器條件功能
如果真的不想碰程式碼,市面上有幾種外掛與主題功能能做到類似效果。Ultimate Member 內建依使用者角色顯示選單的功能,Elementor Pro 的 Theme Builder 與 Astra Pro 的 Header Builder 也都能用條件判斷切換頁首選單。但選之前先評估:你是真的需要完整會員系統,還是只為了換選單而背一整套外掛的維護成本?
先把三種主流替代方案的定位講清楚,你才知道該選哪個。
- Ultimate Member:免費版就能依角色限制選單與頁面瀏覽,適合要做會員註冊流程、會員資料欄位的站。純粹換選單略嫌過重,因為它本質是一套會員系統,不是選單工具 [來源:〈Ultimate Member — WordPress Plugin Directory〉〈https://wordpress.org/plugins/ultimate-member/〉〈2026〉]。
- Elementor Pro Theme Builder:可建立多組 Header Template,用 Display Conditions 設定登入者與未登入者顯示不同頁首,全程視覺化操作不用程式碼 [來源:〈Elementor Documentation — Theme Builder Display Conditions〉〈https://elementor.com/help/theme-builder-display-conditions/〉〈2026〉]。
- Astra Pro Header Builder:同樣支援依登入狀態切換頁首元素,與 Astra 主題生態圈一致,已經在用 Astra Pro 的人幾乎不用學新東西。
選擇原則很單純:只要換選單用程式碼;要做會員註冊與分級用 Ultimate Member;已經用 Elementor 或 Astra 就用它們內建的條件功能,避免裝太多外掛拖慢速度。我個人在做 Astra Pro 搭配 WooCommerce 購物網站 時,多半直接用 Astra 的 Header Builder 處理選單切換,因為跟主題生態一致,出問題也好查。
這裡要提醒一個常見誤區。很多人以為裝了 Ultimate Member 就「自動」解決選單問題,其實它的選單限制功能要另外設定,而且設定介面每隔幾版就會調整,學習成本不低。如果你的需求真的只是訪客看 A、會員看 B,花一個下午學會那段 10 來行程式碼,長期來說比依賴外掛更省事,也更好維護。
如果你的會員系統已經由 WooCommerce 或某個 LMS 外掛撐起來,只差一個「會員看 A、訪客看 B」的選單控制,這時候再裝一整套 Ultimate Member 就太重了。這種情境可以選 Menu Roles 或 If Menu 這類輕量外掛:它們只在每個選單項目上加一個「誰看得到」的勾選,不碰會員註冊系統,設定直覺、交接給非技術人員也不容易出錯。判斷標準很實際:你是不是同時還需要會員註冊機制。需要就選 Ultimate Member,只想控選單可見性就選 Menu Roles,不要為了一個選單去背一整套會員系統。
| 方案 | 要不要寫程式 | 適合需求 | 額外負擔 |
|---|---|---|---|
| 原生條件標籤程式碼 | 要 | 只換選單 | 幾乎沒有 |
| Ultimate Member | 不用 | 會員註冊+分級權限 | 整套會員系統 |
| Elementor Pro Theme Builder | 不用 | 已用 Elementor 想視覺化操作 | Elementor Pro 授權費 |
| Astra Pro Header Builder | 不用 | 已用 Astra 想用主題原生功能 | Astra Pro 授權費 |
兩個問題決定走哪條路:選單決策十字線
上表列了四種方案,但真正能幫你快速拍板的,是把需求拆成兩個獨立的問題,各回答「是/否」,就能對到唯一解。第一個問題是:這個站需不需要會員註冊流程?第二個問題是:選單差異是「整組換」還是「只差一兩個項目」?把這兩個答案交叉,會落在四個象限之一,每個象限對應一種最省事的做法。
| 選單整組換 | 只差一兩個項目 | |
|---|---|---|
| 需要會員註冊 | Ultimate Member 或會員系統外掛(順便用它的選單限制) | 會員系統外掛+Menu Roles 逐項控可見性 |
| 不需要會員註冊 | 原生 wp_nav_menu_args filter 程式碼 | Menu Roles / If Menu 輕量外掛,或一段只加減單一項目的 filter |
這張十字線的好處是它強迫你先回答「會員註冊」這題,而這正是最多人搞錯的地方。很多人明明只是想讓 WooCommerce 顧客登入後多一個「我的帳戶」,卻去裝 Ultimate Member,等於在已經能註冊會員的站上,再疊一套會員系統,角色 slug 兩邊打架、資料表重複,後續每改一次都要查到底哪套系統在講話。回答完這兩題,選錯方案的機率會大幅下降。
用一個具體情境走一遍這條決策線,會更具體。假設你經營一個內容站,每天約幾千次工作階段,會員來自 WooCommerce 註冊(角色是 customer),需求只是讓登入顧客在主選單看到「我的帳戶」「登出」,訪客看到「登入」「註冊」。對應十字線:已經有會員註冊流程(WooCommerce 自帶),選單是整組換,所以落在「需要會員註冊+整組換」象限。但這裡有個關鍵判斷:Ultimate Member 在這個情境其實是過度配置,因為 WooCommerce 已經把會員系統這題答完了,你缺的只是選單切換。所以正解是走「不需要額外會員系統」那一欄的濾器做法,用 in_array('customer', wp_get_current_user()->roles) 當判斷條件,一段 10 來行程式碼就完工,不必再裝任何外掛。這個例子要帶出的觀念是:十字線的第一題問的是「還缺不缺會員系統」,有別於「站上有沒有會員」這個表面問題,把兩者分清楚,才能避免重複投資。
如果你已經在用 Elementor 頁面編輯器 或 Elementor Pro 頁首頁尾與導航設計,那 Theme Builder 的 Display Conditions 是最直覺的選擇,不必碰任何程式碼,用拖拉就能設好登入前後兩組頁首。但如果你只是想要「會員登入後多一個我的帳戶連結」,卻為此買整套 Elementor Pro,那就本末倒置了。
說實在的,外掛沒有絕對的好壞,只有適不適合。重點是先釐清需求再選工具,不要被「裝一套就搞定」這種話術帶著走。一個 10 行程式碼能解的事,硬要用一套會員系統去包,最後維護起來反而更累。
什麼情況不該用條件式選單
條件式選單不是萬靈丹,有些情境硬套上去反而製造麻煩。第一種不該用的情況,是你其實想做的是內容權限控制。如果某個頁面連訪客直接輸入網址都不該看得到,那把它的連結從選單拿掉只是做半套,訪客照樣能透過書籤、分享連結或搜尋結果索引闖進去。這種需求要的是權限外掛在伺服器端擋下未授權請求,選單隱藏在這裡幫不上忙。
第二種情況,是你的選單項目只有一兩個會隨登入狀態變動,其他八九成都不變。這時為了一兩個項目維護兩整套選單,日後每改一次共用項目就要兩邊都改,維護成本反而比用程式碼單獨控制那幾個項目高。這種情境比較適合用 Menu Roles、If Menu 這類「逐項控可見性」的輕量外掛,或乾脆用一段更短的 filter 只在選單輸出時動態加減項目,而不是整組切換。
第三種情況,是你的站根本還沒有會員機制。有些站長聽了條件式選單的好處,就為了「未來可能會用」先把兩組選單建好、filter 寫好,結果會員系統一直沒上線,那組 logged-in 選單變成永遠不會被觸發的死碼。建議等你真的有會員登入流程、有需要區分的內容時,再回頭做這套機制,才不會維護了一個永遠派不上用場的選單。
- 需求其實是擋頁面存取:用權限外掛,不要靠選單隱藏。
- 只有一兩個項目變動:用逐項控制,避免維護兩整套選單。
- 還沒有會員機制:等會員流程上線再做,別預先寫死碼。
- 全站都公開、沒登入差異:根本不需要條件判斷,省下這層複雜度。
白畫面、選單沒切換、會員連結外洩怎麼辦?
條件式選單最常出包的有三類。第一是 functions.php 貼錯導致整站白畫面,第二是選單英文 slug 與程式碼不符造成判斷失效,第三是用 CSS 隱藏選單而非伺服器端切換,導致會員連結在原始碼外洩。用子主題、確認 slug、堅持用 wp_nav_menu_args filter 做伺服器端切換,就能避開這三類問題。
白畫面是新手最怕的噩夢,畫面全白、連後台都進不去。其實救援不難,關鍵是不要慌。functions.php 裡常見的錯誤有兩種:PHP 標籤沒包好(例如多了一個 ?> 或少了一個 <?php),或是複製貼上時帶進了不可見字元。救援流程是用 FTP 或主機後台的檔案管理員,進到子主題目錄打開 functions.php,把剛貼的程式碼整段刪掉或用正確的 PHP 標籤包好,存檔後網站立刻恢復。如果你還不熟 FTP 操作,先看過 WordPress FTP 檔案上傳與修復 會比較安心。
第二類「選單沒切換」多半是 slug 拼錯或 theme location 名稱不符。快速除錯的方法是在程式碼裡暫時加一行 var_dump(wp_get_nav_menus());,重新整理頁面,就會看到 WordPress 實際認得的選單 id 與 slug,拿它跟程式碼裡的字串比對,通常一眼就看出哪裡拼錯。除錯完記得把這行刪掉,不要留在正式環境。
第三類資安風險最嚴重,卻也最容易被忽略。絕對不要兩組選單都輸出再用 display:none 隱藏。那種做法在伺服器端其實把會員專區的網址都送出去了,只是瀏覽器不顯示而已。任何訪客按右鍵檢視原始碼,就能看到會員專區的完整網址,再點幾下就能進去。正確做法是伺服器端只輸出該狀態該看的那組選單,這正是 wp_nav_menu_args filter 的價值所在 [來源:〈WordPress Code Reference — wp_nav_menu_args Hook〉〈https://developer.wordpress.org/reference/hooks/wp_nav_menu_args/〉〈2026〉]。
- 白畫面:用 FTP 進子主題 functions.php,刪掉貼錯的程式碼或修正 PHP 標籤。
- 選單沒切換:slug 拼錯或 location 不符,用 var_dump 確認實際選單 id。
- 會員連結外洩:改用 filter 伺服器端切換,不要用 CSS 隱藏兩組選單。
- 快取衝突:把含條件選單的頁面排除快取,或啟用依使用者分別快取。
快取衝突是條件式選單最容易被忽略的失效原因,值得再強調一次。當你啟用了 快取外掛,它會把頁面輸出快取成靜態檔案。如果第一個造訪的是已登入會員,那一份帶著「我的帳戶」的選單就被快取住,接下來幾個小時內所有訪客都看到那組選單,點下去才發現要登入,體驗很差,還可能讓訪客誤以為網站壞了。解法是把首頁等含條件選單的頁面排除快取,或開啟 WP Rocket、LiteSpeed Cache 的依使用者快取功能 [來源:〈WP Rocket — User Cache / Logged-in User Caching〉〈https://docs.wp-rocket.me/article/134-user-cache/〉〈2026〉]。WP Rocket 的具體參數怎麼調,可對照 WP Rocket 完整設定教學:網站速度優化的最佳快取外掛。
另外兩個小提醒。如果你想把會員專區的連結做到選單裡,但又怕訪客直接輸入網址闖進來,那就要搭配權限控制,而不是只靠選單隱藏,這部分可以看 WordPress 使用者角色權限設定教學。如果你想在結帳前強制登入,可以參考 結帳前強制導向會員登入頁面 的做法,把選單切換跟強制登入串成一套會員動線。
還有一個跟選單無關但常被一起問的問題:登入頁面本身的美觀與安全。預設的 wp-login.php 陽春又顯眼,駭客很愛掃這個網址。如果你在意這點,可以先用 LoginPress 美化 WordPress 登入頁面 把登入頁改好看,再用 WPS Hide Login 隱藏後台登入網址 把 wp-login.php 換成自訂網址,雙重防護。選單切換隻是會員體驗的一環,登入頁這塊也別漏掉。
退一步看,條件式選單的錯誤大多集中在「設定不對」與「快取干擾」這兩端。前者靠 slug 與 location 的仔細比對就能解決,後者靠正確的快取設定排除。把這兩件事顧好,剩下的幾乎不會出大問題。
把條件式選單串進你的會員動線
回顧一下整個流程。先釐清你只是要換選單、還是要做會員分級權限,前者用原生條件標籤最快。接著在後台建好 logged-out 與 logged-in 兩組選單,名稱用英文 slug。然後把那段 10 來行的 wp_nav_menu_args filter 程式碼貼進子主題的 functions.php,儲存後用無痕視窗測訪客與會員兩種狀態。最後把快取與行動版選單位置這兩個細節顧好,整套機制就能穩定運作。
幾個重點再收攏一次。條件判斷只發生在 wp_nav_menu 輸出階段,不是兩組選單用 CSS 隱藏,這點同時決定了功能正確性與資安。程式碼務必放子主題,母主題更新才不會洗掉你的設定。要擴充到多角色分級,把判斷函數從 is_user_logged_in() 換成 current_user_can() 或比對 roles 陣列即可。要是你評估後發現需求其實更重,需要完整會員註冊流程,再回頭考慮 Ultimate Member 或權限外掛,不要為了一個選單背一整套系統。
如果你的站正在用 Astra 主題打造品牌形象網站 或 Astra 與 Spectra 打造品牌官網,條件式選單能無縫接上主題既有的 Header Builder,幾乎不用額外調整。若是購物網站,搭配 WooCommerce 電商架站全流程教學 與 WooCommerce 必裝外掛清單,會員登入後直接看到我的帳戶與訂單,轉換動線會順很多。
還在猶豫要不要動程式碼的人,我的建議是先動手再說:用子主題把那段 filter 貼上去,開無痕視窗測一遍。貼錯了頂多白畫面,FTP 進去刪掉那幾行就回來,成本很低。多數人測過一次就會發現,這比為了一個選單去裝一套會員外掛合理得多。同一套 filter 思路,之後做 部落格架站、線上課程網站 或 社群登入 的會員動線時也能直接套用。
搭配 外掛安裝、佈景主題安裝、SEO 優化、永久連結 SEO 結構設定、備份外掛、表單外掛、側邊欄小工具、固定吸睛小工具、分類排序、LINE 登入、登入促銷彈窗、會員註冊表單、Elementor 外掛推薦、Ultimate Addons for Elementor、Elementor Pro 功能指南、Astra Pro 評測、Divi 頁首套版、線上課程平台比較、WordPress.com 搬家、自架網站費用,條件式選單只是整站會員體驗的一塊拼圖,把它擺對位置,其他功能接起來才會順。
常見問題
WordPress 怎麼讓未登入訪客看到登入註冊、已登入會員看到我的帳戶登出?
在子主題 functions.php 用 wp_nav_menu_args filter,以 is_user_logged_in() 做判斷,把主選單位置分別指向兩組預先建好的選單即可,全程伺服器端切換,不必靠 CSS 隱藏。
條件式選單一定要寫程式碼嗎?
不一定。只想切換選單可用程式碼,也可改用 Elementor Pro Theme Builder 的 Display Conditions 或 Astra Pro Header Builder,以視覺化方式設定登入前後不同頁首,完全不必碰 PHP。
is_user_logged_in() 跟 current_user_can 哪個適合切換選單?
只區分登入與未登入,用 is_user_logged_in() 最輕量;要依使用者角色(例如 VIP、批發客戶)分組,則改用 current_user_can() 或比對 roles 陣列。
為什麼條件選單程式碼貼上去沒生效?
最常見是選單 slug 拼錯、theme_location 名稱與主題不符,或程式碼貼進母主題而被更新覆蓋。用 var_dump(wp_get_nav_menus()) 確認實際 slug,並改貼進子主題即可排除。
條件選單程式碼要放 functions.php 還是子主題?
務必放子主題的 functions.php。母主題更新時,functions.php 會被新版覆蓋,貼在母主題等於白做工;子主題能保留你的自訂邏輯不受更新影響。
條件選單會影響 SEO 或快取嗎?
頁面快取會把第一個造訪者的選單快取住,導致後續訪客看到錯誤狀態的選單。解法是把含條件選單的頁面排除快取,或啟用 WP Rocket、LiteSpeed Cache 的依使用者快取功能。
不裝 Ultimate Member 也能做條件式選單嗎?
可以。只要需求是單純切換選單,用 WordPress 原生的 wp_nav_menu_args filter 搭配條件標籤就能完成;Ultimate Member 適合需要完整會員註冊流程與分級權限的情境。
主題更新後選單判斷失效怎麼辦?
九成是程式碼貼在母主題被更新洗掉。改貼進子主題的 functions.php 重新整理即可;若已用子主題卻仍失效,檢查 theme_location 是否在新版主題被改名。
行動版漢堡選單為什麼沒跟著切換?
很多主題把行動版選單拆成獨立的 menu location(例如 mobile_menu),跟桌機的 primary 分開。只判斷 primary 就會漏掉手機版。把行動版 location 一併寫進條件判斷,用 in_array($args['theme_location'], array('primary','mobile_menu')) 同時覆蓋即可。
條件選單能把會員專區頁面完全保護住嗎?
不能。條件選單只控制連結是否出現在選單,無法阻止使用者直接輸入網址或點書籤進入。要真正擋下未授權存取,必須搭配權限外掛或 current_user_can() 在頁面層做伺服器端檢查,選單隱藏只是第一層導引,不是權限邊界。