问题描述

我的 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。