問題描述

我的 Wordpress 網站有幾個未發佈的帖子,我正在嘗試使用正常的帖子 (site.com/post-here) 可以訪問正常用户 (誰沒有登錄) 。我知道這可能不是最好的做法,但是為了我的特殊目的,這需要做。

我已經嘗試將以下代碼片段添加到我的 functions.php 文件中:

function enable_view_drafts() {
$role = get_role( 'subscriber' );
$role->add_cap( 'read_private_posts' );
$role->add_cap( 'edit_posts' );
}
add_action( 'after_setup_theme', 'enable_view_drafts');

我也試過 init 鈎而不是 after_setup_theme 。沒有運氣。

我的理解是,對角色的更改將保存到數據庫,因此只需要執行一次。這就是為什麼我使用 after_setup_theme 鈎子來調用這個函數。

但是當我嘗試以正常用户身份訪問該頁面時,我會顯示一個 404 頁面,而不是顯示該帖子內容。我也嘗試加載預覽網址 (site.com/?p=212&preview=true),但也沒有。

這些是我的猜測:

  • 普通用户沒有足夠的 caps 來閲讀發佈的草稿。

  • 對於任何用户 (包括管理員),都不可能對 front-end 進行測試和查看草稿。

為了完成我要做的工作,我必須做些什麼改變?如果不可能,你建議什麼替代解決方案?

注意:我不是在尋找 plugin-based 解決方案。

最佳解決方案

您不能向未知用户分配功能。如果您想為每個人顯示一個帖子,請為這些帖子創建一個單獨的 URL,並將一個控制元素添加到帖子編輯器中,以便僅在選定的帖子上啓用預覽。調用這樣的 URL 時,請檢查是否允許該帖子預覽,以及該帖子是否尚未被髮布。還要確保搜索引擎忽略此 URL 。

對於 URL,我將使用 endpoint

add_rewrite_endpoint( 'post-preview', EP_ROOT );

現在您可以創建…

http://example.com/post-preview/123

123 是帖子 ID 。

然後使用回調處理程序來檢查帖子 ID,檢查它是否有效並覆蓋主查詢。這可能是 query_posts()唯一可接受的用例。 🙂

假設端點是一個類 T5_Endpoint(一個模型),並且輸出處理程序是一個類 T5_Render_Endpoint(一個視圖),它獲取了較早傳遞的模型。那麼在 template_redirect 上調用 render()可能有一個方法:

public function render()
{
    $post_id = $this->endpoint->get_value();

    if ( ! $post_id )
        return;

    if ( 1 !== $this->meta->get_value( $post_id )
        or 'publish' === get_post_status( $post_id )
        )
    {
        wp_redirect( get_permalink( $post_id ) );
        exit;
    }

    $query = array (
        'suppress_filters' => TRUE,
        'p'                => $post_id,
        'post_type'        => 'any'
    );

    query_posts( $query );

    add_action( 'wp_head', 'wp_no_robots' );
}

$this->meta 是用於控制是否允許預覽的後期元值的另一個模型 (類 T5_Post_Meta) 。控件設置在 「發佈」 框 (動作 post_submitbox_misc_actions) 中,由另一個獲取相同元類的視圖呈現。

所以 T5_Post_Meta 知道在哪裏和什麼時候存儲元值,這些視圖用它做一些事情。此外,掛鈎到 transition_post_status 刪除發佈後的帖子元字段。我們不想浪費資源,對吧?

這只是一個大綱。有很多細節要覆蓋… 我寫了一個小插件,顯示如何實現:T5 Public Preview

次佳解決方案

我解決了這個問題,我以為比 @ toscho 上面的答案更簡單一些。

我的用例是使用相同的數據庫進行內部 Intranet 分段站點和 public-facing 站點,工作流程是作者撰寫草稿並與發佈之前在內部網站上查看這些草稿的其他用户共享。我特意不要求審閲者登錄查看草稿,所以我只是依賴於一個常數 ENV_PRODUCTION,它是根據 $_SERVER['SERVER_NAME']中的主機名在 wp-config 文件中設置的。這是 ENV_PRODUCTION 在這裏做的檢查?如果正在查看生產現場,只需將所有這些過濾器縮短。

這有點奇怪,因為 WP_Query 從 $ wp_query-> posts 數組中刪除了所有的帖子,因此你必須掛鈎,但對我來説似乎是穩定和安全的。

/*
 * On staging site home and archives, drafts should be visible.
 */
function show_drafts_in_staging_archives( $query ) {
    if ( ENV_PRODUCTION )
        return;

    if ( is_admin() || is_feed() )
        return;

    $query->set( 'post_status', array( 'publish', 'draft' ) );
}

add_action( 'pre_get_posts', 'show_drafts_in_staging_archives' );


/*
 * Make drafts visible on staging site single views.
 *
 * (Because on single views, WP_Query goes through logic to make sure the
 * current user can edit the post before displaying a draft.)
 */
function show_single_drafts_on_staging( $posts, $wp_query ) {
    if ( ENV_PRODUCTION )
        return $posts;

    if ( count( $posts ) )
        return $posts;

    if ( !empty( $wp_query->query['p'] ) ) {
        return array ( get_post( $wp_query->query['p'] ) );
    }
}

add_filter( 'the_posts', 'show_single_drafts_on_staging', 10, 2 );

過濾器有兩個單獨的部分。

  • “pre_get_posts” 掛鈎上的過濾器將默認的 post_status 設置為分段站點上的’publish,draft’ 。這將歸檔歸檔列表中的草稿員。

  • 單個視圖需要單獨的過濾器,因為 WP_Query 類中有一些令人討厭的邏輯從查詢結果中刪除草稿文件,除非當前的 cuser 可以編輯它們。我通過過濾’the_posts’ 來解決這個問題,並將我想要的帖子添加到結果中。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。