受密码保护的帖子重定向

时间:2014-02-21 作者:NoSense

我有一个与自定义模板关联的页面,该模板列出了所有受密码保护的帖子。

我们来命名吧MyPage.

我试图实现的是当用户查看MyPage 仅显示一次password protected form 当他/她输入有效密码->重定向回MyPage 这样他就可以查看受保护帖子的列表。

我想在列表模板上只显示一个表单,当用户输入密码时,只显示具有相同密码(或相同类别中的帖子)且未锁定的帖子。

密码是发布元框中的默认后期保护密码:

WordPress post publish meta box

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

TL;TR? 扰流板警报-将鼠标悬停在下一个blockquote上以显示它

构建一个可通过当前输入的密码轻松过滤的档案绝非易事,也绝对不可能优雅地构建。解决方案包括一个辅助查询和一个小插件,但它可以工作。还会显示所有错误和错误路径,以帮助您避免犯相同的错误。

DB结构密码是主$wpdb->posts 桌子它保存在纯文本中(只是为了说明这一点。不要害怕。它没有连接到任何实际的用户登录,所以你不必担心,当有人每次意外发现它时,你正在打开一个安全漏洞。

构建/更改主查询

为了将结果减少到受密码保护的帖子,我们正在拦截WHERE 条款适用于:

一个页面,任何公共页面,所有页面都有一个文件名为的模板password-protected.phpnot 工作二者都is_page_template()is_page() 使用slug 参数将从get_queried_object(). 当我们已经检索到最终查询结果时,查询的对象就存在了。

<?php
/** Plugin Name: (#135443) Password Protected Posts Page Template Query */

add_action( \'pre_get_posts\', \'wpse135443ExcludeProtectedAction\' );
function wpse135443ExcludeProtectedAction( $query )
{
    if (
            is_page( \'slug-of-protected-page\' )
            AND is_page_template( \'password-protected.php\' )
            AND ! is_admin()
    )
        add_filter( \'posts_where\', \'wpse135443ExcludeProtected\' );
}
// Callback for the posts WHERE clause that only queries for password protected posts
function wpse135443ExcludeProtected( $where )
{
    return $where .= " AND NOT {$GLOBALS[\'wpdb\']->posts}.post_password = \'\' ";
}
页面模板有几种方法。一种是使用过滤器:

add_filter( \'the_excerpt\', \'wpse135443PasswordProtectedExcerpt\' );
function wpse135443PasswordProtectedExcerpt( $excerpt )
{
    return post_password_required()
        ? get_the_password_form()
        : $excerpt;

}
更简单的方法是只列出标题,然后将摘录或内容直接添加到专用模板中。post_password_required() 返回布尔结果,以便轻松检查。该函数接受一个参数,即post ID。它已经从循环内的全局中检索到,但您也可以在循环外使用它,并向其中抛出密码。

post_password_required() AND print get_the_password_form();
检索密码并将其添加到查询中:以下函数将密码添加到(公共)查询字符串中。正如您所见,此解决方案非常不安全:它在HTTP请求中公开密码。

add_action( \'login_form_postpass\', \'wpse135443PasswordToQueryString\' );
function wpse135443PasswordToQueryString()
{
    require_once ABSPATH . \'wp-includes/class-phpass.php\';
    $hasher = new PasswordHash( 8, true );

    $expire = apply_filters( \'post_password_expires\', time() + 10 * DAY_IN_SECONDS );
    setcookie( \'wp-postpass_\' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST[\'post_password\'] ) ), $expire, COOKIEPATH );

    exit( wp_safe_redirect( add_query_arg(
        \'post_password\',
        esc_attr( $_POST[\'post_password\'] ),
        wp_get_referer()
    ) ) );
} );
虽然这可能有用,但实际上not recommended 这样做。如果你真的想从那里走下去,希望你知道如何继续。为了理智起见,我不会透露比这更多的内容——片段搜寻者可能会在公开发布的主题中抓住并使用它,我不想说出问题的根源。

什么都没用?其他选择

第一个大问题是,WordPress默认没有“受保护的帖子存档”see in the template hierarchy. 当我们想要改变页面模板中的主查询时,我们必须检查SQL字符串并与之进行比较。插件可能会拦截(很差),并且没有可靠的方法来处理WP中被拦截和修改的SQL子句。筛选器回调/操作的值的外观示例,链接到posts_clauses. $wpdb->posts 是posts表的名称。

array (size=7)
  \'where\' => string \' AND $wpdb->posts.ID = 1519 AND $wpdb->posts.post_type = \'page\'\' (length=63)
  \'groupby\' => string \'\' (length=0)
  \'join\' => string \'\' (length=0)
  \'orderby\' => string \'$wpdb->posts.post_date DESC\' (length=27)
  \'distinct\' => string \'\' (length=0)
  \'fields\' => string \'$wpdb->posts.*\' (length=14)
  \'limits\' => string \'\' (length=0)
这里没什么可看的。

因此,下一步我们将尝试添加另一个查询。为了便于识别,我们将添加一个额外的自定义查询变量。

$ppQuery = new WP_Query( array(
    \'password_protected\' => TRUE,
    \'post_type\'          => \'post\',
    \'posts_per_page\'     => get_option( \'posts_per_page\' ),
    \'post_status\'        => \'publish\',
) );
生成的SQL语句将类似于以下内容:

SELECT SQL_CALC_FOUND_ROWS  $wpdb->posts.*
FROM $wpdb->posts
WHERE 1=1
    AND $wpdb->posts.post_type = \'post\' 
    AND ($wpdb->posts.post_status = \'publish\')
    AND NOT ($wpdb->posts.post_password = \'\')
ORDER BY $wpdb->posts.post_date DESC LIMIT 0, 10
然后我们可以循环:

<?php
if ( $ppQuery->have_posts() )
{
    ?>
    <div class="entry-content">
        <?php echo get_the_password_form( $GLOBALS[\'post\'] ); ?>
    </div>
    <?php
    while ( $ppQuery->have_posts() )
    {
        $ppQuery->the_post(); ?>

        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <?php the_title( \'<header class="entry-header"><h2>\', \'</h2></header>\' ); ?>
            <div class="entry-content">
            <?php
            post_password_required()
                OR the_excerpt();
            ?>
            </div>
        </article>

    <?php
    }
} ?>
密码表单显示在模板顶部。它从全球$post 对象,它是第一个WP_Post 实例由全局$wp_query 对象使用哪个帖子并不重要,因为它只用于构建<label> 的窗体和IDinput 字段而不是其他内容。表单仍将为name="post_password".

只有在以下情况下才会显示摘录post_password_required()TRUE. 启动窗体时,wp-login.php?action=postpass 检索$_POST 数据,设置cookie并执行安全重定向。因此every 共享相同密码的帖子将被“解锁”——WP只是根据所有帖子密码的哈希值检查Cookie哈希值。如果匹配,则显示。

下面是对齐此模板的插件,这是使其工作所需的插件。

<?php
/**
 * Plugin Name: (#135443) Password Protected Posts Page Template Query
 */

add_action( \'pre_get_posts\', \'wpse135443ExcludeProtectedAction\' );
function wpse135443ExcludeProtectedAction( $query )
{
    if (
        $query->get( \'password_protected\' )
        AND ! is_admin()
    )
        add_filter( \'posts_where\', \'wpse135443ExcludeProtected\' );
}
// Callback for the posts WHERE clause that only queries for password protected posts
function wpse135443ExcludeProtected( $pieces )
{
    remove_filter( current_filter(), __FUNCTION__ );
    return $where .= " AND NOT ({$GLOBALS[\'wpdb\']->posts}.post_password = \'\') ";
}
过滤帖子在查询过程中,几乎不可能(或几乎不可能)查询散列值并对帖子密码进行散列。因此,最简单的方法是使用FilterIterator:

class PasswordProtectedPostsLoop extends \\FilterIterator implements \\Countable
{
    protected $wp_query;

    protected $allowed = FALSE;

    protected $total = 0;

    protected $counter = 0;

    /**
     * @param \\Iterator $iterator
     * @param \\WP_Query $wp_query
     */
    public function __construct( \\Iterator $iterator, \\WP_Query $wp_query )
    {
        # Setup properties
        // Global main query object
        NULL === $this->wp_query AND $this->wp_query = $wp_query;

        // Posts for this request
        $this->total = $this->wp_query->query_vars[\'posts_per_page\'];

        // Internal counter
        0 !== $this->counter AND $this->counter = 0;

        $this->allowed = $this->wp_query->have_posts();

        parent::__construct( $iterator );
    }

    /**
     * @return bool
     */
    public function accept()
    {
        if (
            ! $this->allowed
            OR ! $this->current() instanceof \\WP_Post
        )
            return FALSE;

        $this->wp_query->the_post();

        // Rewind posts for next loop
        $this->wp_query->current_post === $this->total -1
            AND $this->wp_query->rewind_posts();

        if ( ! post_password_required() )
            return FALSE;

        $this->counter++;
        return TRUE;
    }

    /**
     * Helper function to retrieve the ID of the currently looped post.
     * @return int
     */
    public function getID()
    {
        return $this->current()->ID;
    }

    /**
     * @return int
     */
    public function count()
    {
        return $this->counter;
    }
}
循环将非常简单:

$ppArrayObj = new \\ArrayObject( $ppQuery->->get_posts() );
$ppLoop = new PasswordProtectedPostsLoop( $ppArrayObj->getIterator(), $ppQuery );
$ppLoop->rewind();
foreach ( $ppyLoop as $post )
{
        ?>
        <article <?php post_class(); ?>>
            <?php the_title( \'<header class="entry-header"><h2>\', \'</h2></header>\' ); ?>
            <div class="entry-content">
                <?php the_excerpt(); >
            </div>
        </article>
        <?php
}

SO网友:s_ha_dum

有趣的问题:)

下面是一个非常简单的实现。

/**
 * Template Name: Pass-Prot
 *
 */

function only_password_protected($where) {
  remove_action(\'posts_where\',\'only_password_protected\');
  return \' AND post_password != ""\';
}
add_action(\'posts_where\',\'only_password_protected\');

$protected = new WP_Query(
  array(
    \'post_type\' => \'post\'
  )
);
get_header();

if ($protected->have_posts()) {
  $form = true;
  while ($protected->have_posts()) {
    $protected->the_post();
    if (!post_password_required($post)) {
      $form = false;
      the_title();
      the_content();
      echo \'<hr/>\';
    }
  }
  if ($form) {
    echo get_the_password_form();
  }
}
get_footer();
这应该适用于简单的情况。如果您有很多受密码保护的帖子,或者需要分页,那么您将需要更复杂的内容。您可能需要检查post password Cookie,并进行查询搜索。

您还需要一种“重置”的方式来输入新密码。

希望这能让你开始。

SO网友:kaiser

未来/下一个WP版本。。。将已按功能查询has_passwordpost_password. Trac ticket 可获得的

结束

相关推荐

未定义函数wp_set_password

我正在创建一个插件。我收到以下错误(WP 3.5):Fatal error: Call to undefined function wp_set_password() in \\path\\to\\plugin.php on line 18 第18行包括:wp_set_password( \'newpass\', $user_id ); 这位于主插件文件中,所有其他代码都已注释掉,以便尝试隐藏此错误。我不知道为什么它显示为未定义。我是不是遗漏了什么http://codex.wordpr