WordPress 結合 MemberPress 與 ACF 自動更新文章存取權限狀態

前言

在使用 WordPress 搭配會員管理外掛 MemberPress 時,常見需求是判斷文章是否有設定存取權限,並將此狀態同步到自訂欄位(ACF)中,方便前端或查詢邏輯使用。這段程式碼示範如何在文章儲存時自動檢查 MemberPress 的存取規則,並更新 ACF 的 True/False 欄位,適合熟悉 WordPress 開發並使用 MemberPress 與 ACF 的工程師。

文章儲存時自動同步存取權限

透過 save_post 鉤子,在文章儲存或更新時觸發檢查。程式碼會先排除自動儲存與修訂版本,避免重複執行。接著確認文章類型是否為支援的 postpage,並檢查 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
}