
做會員網站、內部資料區或線上課程時,常會有這些需求:
- 文章前半段大家都能看,後半段只給登入的會員
- 下載連結只給特定角色(例如「經銷商」)
- 同一個位置,訪客看到「請先登入」,會員看到正式內容
裝會員外掛當然可以,但如果只是這種簡單的需求,自己寫一個短代碼就夠了。這篇整理三種寫法,從簡單到彈性。(原本另外兩篇〈用代碼讓 WordPress 的某部分內容只有註冊/登入的人才可以看到〉與〈用代碼使 WordPress 依照會員等級顯示不同的文章內容〉的內容已經整合到這裡。)
開始之前
- 程式碼放在子主題的
functions.php,或用 Code Snippets 外掛新增。不要直接改主題本身的檔案,主題一更新就會被覆蓋。 - 動手前先備份網站。
- 角色與權限的觀念,可以先看WordPress 使用者角色與權限完整指南。
寫法一:只有登入的人看得到
最常見的需求:登入的人看得到內容,沒登入的人看到一段提示和登入連結。
add_shortcode( 'members', 'ahwei_members_shortcode' );
function ahwei_members_shortcode( $atts, $content = null ) {
if ( null === $content || is_feed() ) {
return '';
}
if ( is_user_logged_in() ) {
return do_shortcode( $content );
}
return sprintf(
'<p class="members-only">這段內容僅限會員閱讀,請先<a href="%s">登入</a>。</p>',
esc_url( wp_login_url( get_permalink() ) )
);
}使用方式:在文章裡加入「短代碼」區塊(直接打在段落裡也可以),把會員內容包起來:
[members]這段只有登入的會員看得到。[/members]程式碼裡用到的函式:
is_user_logged_in():判斷目前的訪客有沒有登入。wp_login_url( get_permalink() ):登入頁的網址,登入後會自動回到這篇文章。is_feed():RSS 裡一律不輸出,避免會員內容被 RSS 閱讀器抓走。
舊版的寫法在沒登入時什麼都不顯示,訪客根本不知道這裡有內容。加上提示和登入連結,會員才知道要做什麼。如果你希望完全不顯示,把最後的 return sprintf( ... ); 整段換成 return ''; 就好。
會員內容有好幾個區塊怎麼辦?
會員內容裡有圖片、清單等好幾個區塊時,可以把 [members] 放在一個短代碼區塊、[/members] 放在另一個短代碼區塊,中間夾著一般的區塊。WordPress 是先把整篇文章組好才處理短代碼,所以中間的內容會被一起包住。
寫法二:依角色、權限、帳號決定誰看得到
需要更細的條件時,用下面這個比較完整的 [eyesonly] 短代碼。舊版文章用的也是這個名稱與參數,如果你的網站以前用過,換上新的程式碼之後,舊文章裡的短代碼可以照常使用。
add_shortcode( 'eyesonly', 'ahwei_eyesonly_shortcode' );
function ahwei_eyesonly_shortcode( $atts, $content = null ) {
$atts = shortcode_atts(
array(
'logged' => '',
'level' => '',
'username' => '',
'hide' => '',
),
$atts,
'eyesonly'
);
if ( null === $content || is_feed() ) {
return '';
}
$user = wp_get_current_user();
$matched = false;
// 條件一:登入狀態
if ( 'in' === $atts['logged'] && is_user_logged_in() ) {
$matched = true;
}
if ( 'out' === $atts['logged'] && ! is_user_logged_in() ) {
$matched = true;
}
// 條件二:角色或權限(可填多個,用逗號或空格分開)
$levels = preg_split( '/[\s,]+/', $atts['level'], -1, PREG_SPLIT_NO_EMPTY );
foreach ( $levels as $level ) {
if ( in_array( $level, (array) $user->roles, true ) || current_user_can( $level ) ) {
$matched = true;
}
}
// 條件三:指定帳號(可填多個)
$names = preg_split( '/[\s,]+/', $atts['username'], -1, PREG_SPLIT_NO_EMPTY );
if ( $user->exists() && in_array( $user->user_login, $names, true ) ) {
$matched = true;
}
// hide="yes" 時規則反過來:符合條件的人看不到
$hide = in_array( strtolower( $atts['hide'] ), array( 'yes', 'true', '1' ), true );
$show = $hide ? ! $matched : $matched;
return $show ? do_shortcode( $content ) : '';
}四個參數:
logged:填in代表已登入的人,填out代表沒登入的訪客。level:角色代稱或權限名稱,可以填多個,用逗號或空格分開,例如administrator, editor,或自訂角色c_business。username:指定帳號(登入用的帳號名稱),可以填多個。hide:填yes時規則反過來,符合條件的人看不到,其他人看得到。
logged、level、username 至少要填一個,可以混著用,符合其中任何一個條件就算符合。
舊版文章在網站搬家後,程式碼裡的分隔規則少了反斜線,變成 /[s,]+/。照著複製的話會變成用字母 s 來切割,名稱裡有 s 的角色(例如 subscriber)就會判斷錯誤。上面的程式碼是正確的 /[\s,]+/。
使用範例
只有管理員、自訂角色 c_business,以及有審核留言權限的人看得到:
[eyesonly level="administrator, c_business, moderate_comments"]內容[/eyesonly]沒登入的訪客、訂閱者都看不到,其他登入的人看得到:
[eyesonly hide="yes" logged="out" level="subscriber"]內容[/eyesonly]管理員,以及帳號 joebob、billyjean 看得到(不一定要是管理員):
[eyesonly username="joebob, billyjean" level="administrator"]內容[/eyesonly]同一個位置,登入和沒登入的人看到不同內容:
[eyesonly logged="in"]歡迎回來,這是會員專屬內容。[/eyesonly]
[eyesonly logged="out"]登入會員即可閱讀完整內容。[/eyesonly]寫法三:在主題範本裡依角色顯示不同內容
如果不是單篇文章,而是網站的某個固定位置(例如側邊欄、頁尾、文章範本)要依會員身分顯示不同內容,可以直接寫在子主題的範本檔案裡:
<?php if ( current_user_can( 'manage_options' ) ) : ?>
<p>管理員看到的內容</p>
<?php elseif ( current_user_can( 'edit_others_posts' ) ) : ?>
<p>編輯看到的內容</p>
<?php elseif ( current_user_can( 'publish_posts' ) ) : ?>
<p>作者看到的內容</p>
<?php elseif ( current_user_can( 'edit_posts' ) ) : ?>
<p>投稿者看到的內容</p>
<?php elseif ( is_user_logged_in() ) : ?>
<p>訂閱者(一般會員)看到的內容</p>
<?php else : ?>
<p>沒登入的訪客看到的內容</p>
<?php endif; ?>判斷要從權限最高的開始:管理員也擁有「編輯文章」的權限,如果先判斷 edit_posts,管理員就會先被當成投稿者。
舊版文章用的是 current_user_can( 'level_10' )、level_7 這類「使用者等級」寫法,那是 WordPress 早期的機制,已經淘汰多年,請改用上面的權限名稱。
要判斷自訂角色,檢查使用者的角色清單:
$user = wp_get_current_user();
if ( in_array( 'c_business', (array) $user->roles, true ) ) {
// 目前的使用者是「企業主」角色
}區塊主題沒有 PHP 範本檔可以改,在「外觀 → 編輯器」的範本裡加入「短代碼」區塊,使用寫法一或寫法二的短代碼就可以。
一定要知道的限制
被隱藏的內容,搜尋引擎看不到
Google 的爬蟲不會登入你的網站,所以用短代碼包起來的內容,對搜尋引擎來說等於不存在,不會被收錄,也不會替文章加分。
- 文章公開的部分要寫得完整、有內容,讓沒登入的讀者(和搜尋引擎)也知道這篇在講什麼。
- 不要反過來判斷「是 Google 爬蟲就顯示全文」。給搜尋引擎和使用者看不同的內容屬於「偽裝(cloaking)」,違反 Google 的搜尋規範,網站可能被降低排名甚至移除。
- 經營付費訂閱內容、又希望被搜尋引擎收錄的網站,Google 另外有「付費內容」的結構化資料規範,要照規範處理。
隱藏內容不等於保護檔案
短代碼只是「不把這段內容輸出到網頁上」。如果藏起來的是一個 PDF 下載連結,檔案本身還是放在 wp-content/uploads/ 裡,知道網址的人不用登入也能直接下載。真正需要保護的檔案,要用會員外掛或主機端的下載控管。
快取外掛的設定
快取外掛通常不會替登入的使用者產生快取頁面,所以這些寫法大多可以正常運作。但如果你在快取外掛裡開啟了「替登入使用者快取」之類的選項,不同角色可能會拿到同一份快取頁面,會員內容就可能被別人看到。使用這些寫法時,請確認這類選項是關閉的。
需求再複雜,就交給會員外掛
如果要做付費會員、訂閱到期、分級收費、會員專屬檔案下載,自己寫的程式會越來越難維護,這時候改用成熟的會員外掛比較省事,也比較安全。
延伸閱讀
- WordPress 使用者角色與權限完整指南:預設角色、檢查權限、建立自訂角色
- WordPress 會員註冊後自動登入、跳轉到指定頁面(PHP 8 安全寫法)
- WordPress 禁止非管理員進入後台:訂閱者、會員登入後自動導回首頁
會員網站哪些內容要公開、哪些只給會員,最好在規劃時就想清楚,才不會跟搜尋排名互相衝突。正威網路行銷是 25 年經驗的基隆網頁設計工作室,提供客製化網頁設計與 SEO 搜尋引擎優化,歡迎來聊聊。







發表留言
還沒有人留言,歡迎第一個分享你的想法或問題。留言經審核後才會顯示,Email 不會公開。