前言
在使用 WordPress 搭配會員管理外掛 MemberPress 時,常見需求是判斷文章是否有設定存取權限,並將此狀態同步到自訂欄位(ACF)中,方便前端或查詢邏輯使用。這段程式碼示範如何在文章儲存時自動檢查 MemberPress 的存取規則,並更新 ACF 的 True/False 欄位,適合熟悉 WordPress 開發並使用 MemberPress 與 ACF 的工程師。
文章儲存時自動同步存取權限
透過 save_post 鉤子,在文章儲存或更新時觸發檢查。程式碼會先排除自動儲存與修訂版本,避免重複執行。接著確認文章類型是否為支援的 post 或 page,並檢查 MemberPress 與 ACF 是否存在。
重要程式碼片段
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
$post_type = get_post_type($post_id);
if (!in_array($post_type, array('post', 'page'))) {
return;
}
if (!class_exists('MeprRule') || !function_exists('update_field')) {
return;
}
接著使用 MeprRule::get_rules($post) 取得該文章的 MemberPress 存取規則,判斷是否有規則存在,並更新 ACF 的 ks_post_access 欄位。
$rules = MeprRule::get_rules($post);
$has_rule = !empty($rules);
update_field('ks_post_access', $has_rule, $post_id);
當 MemberPress 規則變更時批次更新所有文章
除了單篇文章儲存時更新,也會在 MemberPress 規則新增、修改或刪除時觸發批次更新所有文章的存取狀態,確保資料一致。
function ks_update_all_posts_access_status() {
if (!function_exists('update_field')) {
return;
}
$posts = get_posts(array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1,
'fields' => 'ids'
));
foreach ($posts as $post_id) {
$post = get_post($post_id);
$rules = MeprRule::get_rules($post);
$has_rule = !empty($rules);
update_field('ks_post_access', $has_rule, $post_id);
}
}
後台介面批次更新功能
為方便管理,新增 WordPress 後台子選單,讓管理者可以手動觸發更新所有文章的存取權限狀態,並提供操作說明。
function ks_add_bulk_update_access_status() {
add_submenu_page(
'edit.php',
'Update Access Status',
'Update Access Status',
'manage_options',
'ks-bulk-update-access-status',
'ks_bulk_update_access_status_page'
);
}
add_action('admin_menu', 'ks_add_bulk_update_access_status');
介面中包含按鈕與確認提示,確保操作安全。
實務應用與延伸
- 透過 ACF 的
ks_post_access欄位,前端查詢可以輕鬆過濾有存取限制的文章。 - 可結合 GreenShift Query Loop 或其他查詢工具,提升前端顯示效率。
- 若會員規則較複雜,建議優化批次更新邏輯,避免效能瓶頸。
- 可加入快取機制或非同步處理,減少儲存時的阻塞。
常見問題與注意事項
- 請確保已建立名為
ks_post_access的 True/False ACF 欄位,且欄位名稱與程式碼一致。 - 若 MemberPress 或 ACF 外掛未啟用,程式會自動跳過,避免錯誤。
- 批次更新文章時,若文章數量龐大,可能會耗時較久,建議在低流量時段執行。
完整程式碼
<?php
// 在文章儲存/更新時自動檢查並更新 ACF 欄位
function ks_update_mepr_access_status($post_id) {
// 避免自動儲存時執行
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
// 檢查是否為支援的文章類型
$post_type = get_post_type($post_id);
if (!in_array($post_type, array('post', 'page'))) {
return;
}
// 檢查是否有 MemberPress 和 ACF
if (!class_exists('MeprRule') || !function_exists('update_field')) {
return;
}
$post = get_post($post_id);
if (!$post) {
return;
}
// 檢查該文章是否有 MemberPress 規則
$rules = MeprRule::get_rules($post);
$has_rule = !empty($rules);
// 更新 ACF 欄位
update_field('ks_post_access', $has_rule, $post_id);
// 可選:記錄 log 用於除錯
error_log("KS Post ID: $post_id - Access Rule Status: " . ($has_rule ? 'Yes' : 'No'));
}
// 掛載到文章儲存的 hook
add_action('save_post', 'ks_update_mepr_access_status', 20, 1);
// 也可以掛載到 MemberPress 規則更新時
add_action('mepr-rule-saved', 'ks_update_all_posts_access_status');
add_action('mepr-rule-deleted', 'ks_update_all_posts_access_status');
// 當 MemberPress 規則變更時,更新所有相關文章
function ks_update_all_posts_access_status() {
if (!function_exists('update_field')) {
return;
}
$posts = get_posts(array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1,
'fields' => 'ids'
));
foreach ($posts as $post_id) {
$post = get_post($post_id);
$rules = MeprRule::get_rules($post);
$has_rule = !empty($rules);
update_field('ks_post_access', $has_rule, $post_id);
}
}
// 管理後台增加批量更新功能
function ks_add_bulk_update_access_status() {
add_submenu_page(
'edit.php',
'Update Access Status',
'Update Access Status',
'manage_options',
'ks-bulk-update-access-status',
'ks_bulk_update_access_status_page'
);
}
add_action('admin_menu', 'ks_add_bulk_update_access_status');
function ks_bulk_update_access_status_page() {
if (isset($_POST['ks_update_all'])) {
ks_update_all_posts_access_status();
echo '<div class="notice notice-success"><p>所有文章的存取權限狀態已更新完成!</p></div>';
}
?>
<div class="wrap">
<h1>KS 更新文章存取權限狀態</h1>
<p>此功能會檢查所有文章的 MemberPress 存取權限設定,並更新對應的 ACF 欄位。</p>
<form method="post">
<input type="submit" name="ks_update_all" class="button-primary" value="更新所有文章狀態"
onclick="return confirm('確定要更新所有文章的存取權限狀態嗎?');">
</form>
</div>
<?php
}