如何通过完整的url/slug访问草稿帖子或正在审核的帖子?

时间:2016-02-19 作者:Sebastian

我使用WordPress 4.2运行一个网站,并更改了草稿帖子或处于审阅状态的帖子向未登录用户显示的方式(这些帖子对任何访问该网站的人都是可见的)。

我已经实施了以下解决方案:https://wordpress.org/support/topic/problem-filtering-query-to-allow-displaying-drafts-even-for-not-logged-users

现在,虽然任何人现在都可以访问草稿帖子/挂起的帖子,而无需登录,但这些帖子只能通过post\\u id访问,如下所示:

http://my-domain.com/?p=1234

它们无法通过slug/nice permalink访问,以前是这样的:

http://my-domain.com/2015/12/07/post-with-nice-slug/

有没有人对如何“启用”草稿帖子/挂起帖子的永久链接有什么想法?

非常感谢。

UPDATE Feb. 20th

@userabuser给出的答案很有魅力!!由于我所有的待定/草稿帖子都是以前发布的帖子,所以我不需要先发布。我本以为我自己已经想出了一个可行的解决方案,但:这是我以前使用的代码,它不起作用(我不明白为什么会这样):

function guest_enable_hidden_single_post($query) {
    if(is_user_logged_in()) return $query;
    //user is not logged

    if(!is_single()) return $query;
    //this is a single post

    if(!$query->is_main_query())return $query;
    //this is the main query    

    $query->set(\'post_status\',array(\'publish\', \'pending\'));
    //allowed post statuses for guest

    return $query;
}

function guest_reload_hidden_single_post($posts) {
    global $wp_query, $wpdb;

    if(is_user_logged_in()) return $posts;
    //user is not logged

    if(!is_single()) return $posts;
    //this is a single post

    if(!$wp_query->is_main_query()) return $posts;
    //this is the main query

    if($wp_query->post_count) return $posts;
    //no posts were found

    $posts = $wpdb->get_results($wp_query->request);

    return $posts;
}

//allow guests to view single posts even if they have not post_status="publish"
add_filter(\'pre_get_posts\', \'guest_enable_hidden_single_post\');

//reload hidden posts
add_filter(\'the_posts\', \'guest_reload_hidden_single_post\');

UPDATE Feb. 22nd

未向管理员/登录用户显示私人页面时出现问题。我用以下代码修复了此问题:

function preview_draft_posts($query) {
    if(is_user_logged_in()) return $query;
    // user is not logged

    if(is_admin()) return $query;
    // user is not admin

    if(is_attachment()) return $query;
    // is not an attachment

    if(get_query_var(\'suppress_filters\')) return $query;
    // no suppressed filters

    if(!is_single()) return $query;
    // query for a single post

    if(!$query->is_main_query()) return $query;
    // this is the main query

    $query->set(\'post_status\', array(\'publish\', \'pending\'));

    return $query;
}
add_filter(\'pre_get_posts\', \'preview_draft_posts\');
现在,挂起的帖子将显示给任何人,私人帖子仍然只对管理员可见;-)

1 个回复
最合适的回答,由SO网友:Adam 整理而成

警告:这个答案中的代码示例非常基本,可能需要也可能不需要进一步的条件逻辑来适应您的精确需求,这个逻辑是作为一个示例来帮助您完成任务的

您需要注意两个方面:

考虑事项1:

如果您添加新帖子并将其保存为post_status 属于draft 首先,该职位将不会有slugpost_name 数据库中的字段*_posts 直到您publish 至少once.

考虑事项2:

如果添加新帖子,请将其保存为post_status 属于draft, 或者只是通过draft 登台并直接进入publish 然后将帖子放回draft post_status, 然后,立柱会将缓动块插入post_name 中的列*_posts 桌子

为什么这一点很重要:与考虑因素1有关id 或者post_name 为了检索帖子,它是唯一的。

您会注意到,当您创建草稿帖子并尝试预览它时,WordPress会将您带到一个类似以下内容的预览URL:

http://example.com/?p=123&preview=true

之所以这样做,是因为识别和预览相关帖子的唯一方法是通过数据库中与之关联的ID来完成。

关于对价2publish 至少发布一次,然后将其放回draft, 您可以在draft 由于post_name 列包含段塞值。

一些示例代码:

以下代码允许您在draftpending 只要帖子之前至少发布过一次,就可以使用slug来获取状态(请参见考虑事项2)。

function preview_draft_posts($query) {

  if ( is_admin() || get_query_var(\'suppress_filters\') )
    return $query;

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


  return $query;

}

add_filter(\'pre_get_posts\', \'preview_draft_posts\');
以上内容适用于登录和注销用户。

如果注销并希望预览草稿,会发生什么情况

正常,因此如果draf 以前至少未发布过一次,预览帖子的唯一方法是使用以下格式:

http://example.com/?p=123

WordPress依赖于这种格式来查找没有slug的帖子。

如果您已注销,尽管pre_get_posts 我们在上述示例中使用的逻辑。

相反,您需要连接到过滤器上the_posts 并将帖子添加回要查看的结果,因为WP_Query 将排除draft 由于注销用户没有适当的用户功能,因此从结果集中为注销用户发布帖子。

另一方面,如果您尝试(在注销时)访问类似于考虑因素1的帖子,其默认预览URL如上述示例中所述http://example.com/?p=123&preview=true (带或不带preview=true) 然后你会看到一个404页的未找到通知。

以下示例代码纠正了以下问题:

function the_posts_preview_draft_posts($posts, $wp_query) {

    //abort if $posts is not empty, this query ain\'t for us...
    if ( count($posts) ) {
        return $posts;
    }

    $p = get_query_var(\'p\');

    //get our post instead and return it as the result...
    if ( !empty($p) ) {
        return array(get_post($p));
    }
}

add_filter(\'the_posts\', \'the_posts_preview_draft_posts\', 10, 2);
太好了。。。但是等等,这还是很糟糕,因为你必须使用URL格式,比如http://example.com/?p=123 访问帖子。

返回中概述的主要问题consideration 1, 我能想到的唯一解决方案如下:

解决方案#1

  • 保存草稿帖子,并通过将标题转换为标题来按标题查找帖子
示例。。。

function the_posts_preview_draft_posts($posts, $wp_query) {
    
    //abort if $posts is not empty, this query ain\'t for us...
    if ( count($posts) ) {
        return $posts;
    }

    $id    = get_query_var(\'p\');
    $name = get_query_var(\'name\');

    //this is a bit of a bad idea...
    if ( empty($id) && !empty($name) ) {

        $name = preg_replace(\'/\\W/\', \' \', $name);

        global $wpdb;
        $id = $wpdb->get_var( 
            "
            SELECT ID 
            FROM $wpdb->posts 
            WHERE UPPER(post_title) LIKE UPPER(\'".$name."\')
            LIMIT 1" 
        );

    }


    //get our post instead and return it as the result...
    if ( !empty($id) ) {
        return array(get_post($id));
    }

}

add_filter(\'the_posts\', \'the_posts_preview_draft_posts\', 10, 2);
以上。。。↑ ...这是一个坏主意,但只是你需要达到的长度的一个例子。为什么这是一个坏主意很简单,您需要确保数据库中没有重复的帖子标题,并且您需要确保不修改slug,以便将其保存为草稿时与标题不同。

正如你所看到的,充满了问题。

解决方案#2

处理此问题的更好方法可能是将post的post\\U状态设置为publish 因此post_name 列获取slug值,然后立即将post放回draft 地位

手动操作会很糟糕,下面是一些代码:

function allow_draft_public_preview( ) {

        global $post;

        if ( !empty($post->post_name) )
            return;

        $html =<<<DOC
        <div class="misc-pub-section">
            <label>
                <input type="checkbox" id="_allow_public_preview" name="_allow_public_preview" value="1" />
                Allow public preview
            </label>
        </div>
DOC;

echo $html;

}

add_action(\'post_submitbox_misc_actions\', \'allow_draft_public_preview\');

function update_post_status( $post_id, $post, $update ) {

    if ( !empty($_POST[\'_allow_public_preview\']) ) {
        
        //un-hook to prevent infinite loop
        remove_action( \'save_post\', \'update_post_status\', 13, 2 );

        //set the post to publish so it gets the slug is saved to post_name
        wp_update_post( array( \'ID\' => $post_id, \'post_status\' => \'publish\' ) );

        //immediately put it back to draft status
        wp_update_post( array( \'ID\' => $post_id, \'post_status\' => \'draft\' ) );

        //re-hool
        add_action( \'save_post\', \'update_post_status\', 13, 2 );
    }

}

add_action(\'save_post\', \'update_post_status\', 13, 2);
附加到的第一个回调post_submitbox_misc_actions 操作将复选框添加到后期编辑屏幕;允许公共预览;。。。

enter image description here

...当您标记此复选框时,将通过在save_post 行动

save_post 操作我们检查中是否存在复选框$_POST 超全局,如果存在,我们将post状态设置为publish 然后立即将其设置回draft.

现在,您可以通过他们的slug/pretty permalinks访问草稿帖子,登录或注销。

现在大家一起:

function preview_draft_posts($query) {

  if ( is_admin() || get_query_var(\'suppress_filters\') )
    return $query;


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


  return $query;

}

add_filter(\'pre_get_posts\', \'preview_draft_posts\');

function the_posts_preview_draft_posts($posts, $wp_query) {

    //abort if $posts is not empty, this query ain\'t for us...
    if ( count($posts) ) {
        return $posts;
    }

    $p = get_query_var(\'p\');

    //get our post instead and return it as the result...
    if ( !empty($p) ) {
        return array(get_post($p));
    }
}

add_filter(\'the_posts\', \'the_posts_preview_draft_posts\', 10, 2);

function allow_draft_public_preview( ) {

        global $post;

        if ( !empty($post->post_name) )
            return;

        $html =<<<DOC
        <div class="misc-pub-section">
            <label>
                <input type="checkbox" id="_allow_public_preview" name="_allow_public_preview" value="1" />
                Allow public preview
            </label>
        </div>
DOC;

echo $html;

}

add_action(\'post_submitbox_misc_actions\', \'allow_draft_public_preview\');

function update_post_status( $post_id, $post, $update ) {

    if ( !empty($_POST[\'_allow_public_preview\']) ) {
        
        //un-hook to prevent infinite loop
        remove_action( \'save_post\', \'update_post_status\', 13, 2 );

        //set the post to publish so it gets the slug is saved to post_name
        wp_update_post( array( \'ID\' => $post_id, \'post_status\' => \'publish\' ) );

        //immediately put it back to draft status
        wp_update_post( array( \'ID\' => $post_id, \'post_status\' => \'draft\' ) );

        //re-hool
        add_action( \'save_post\', \'update_post_status\', 13, 2 );
    }

}

add_action(\'save_post\', \'update_post_status\', 13, 2);

相关推荐

从slug中获取好的类别名称(删除类别的破折号)

我在主题中有一个函数:$category = isset($_GET[\'category\']) ? wp_unslash($_GET[\'category\']) : \'\'; 问题是它输出的类别如下:"E;测试类别;然而,我想表明:"Test Category", 就像它保存在后端一样,没有破折号和较小的字母。有没有办法摆脱这个鼻涕虫,改用这个好名字?我尝试了很多东西(比如get_term_by() 功能),但对我来说什么都不起作用。我想这是因为我使用了$ca