我有一个与自定义模板关联的页面,该模板列出了所有受密码保护的帖子。
我们来命名吧MyPage.
我试图实现的是当用户查看MyPage 仅显示一次password protected form 当他/她输入有效密码->重定向回MyPage 这样他就可以查看受保护帖子的列表。
我想在列表模板上只显示一个表单,当用户输入密码时,只显示具有相同密码(或相同类别中的帖子)且未锁定的帖子。
密码是发布元框中的默认后期保护密码:
我有一个与自定义模板关联的页面,该模板列出了所有受密码保护的帖子。
我们来命名吧MyPage.
我试图实现的是当用户查看MyPage 仅显示一次password protected form 当他/她输入有效密码->重定向回MyPage 这样他就可以查看受保护帖子的列表。
我想在列表模板上只显示一个表单,当用户输入密码时,只显示具有相同密码(或相同类别中的帖子)且未锁定的帖子。
密码是发布元框中的默认后期保护密码:
TL;TR? 扰流板警报-将鼠标悬停在下一个blockquote上以显示它
构建一个可通过当前输入的密码轻松过滤的档案绝非易事,也绝对不可能优雅地构建。解决方案包括一个辅助查询和一个小插件,但它可以工作。还会显示所有错误和错误路径,以帮助您避免犯相同的错误。
$wpdb->posts
桌子它保存在纯文本中(只是为了说明这一点。不要害怕。它没有连接到任何实际的用户登录,所以你不必担心,当有人每次意外发现它时,你正在打开一个安全漏洞。WHERE
条款适用于:一个页面,任何公共页面,所有页面都有一个文件名为的模板password-protected.php
not 工作二者都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 这样做。如果你真的想从那里走下去,希望你知道如何继续。为了理智起见,我不会透露比这更多的内容——片段搜寻者可能会在公开发布的主题中抓住并使用它,我不想说出问题的根源。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
}
有趣的问题:)
下面是一个非常简单的实现。
/**
* 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,并进行查询搜索。您还需要一种“重置”的方式来输入新密码。
希望这能让你开始。
has_password
和post_password
. Trac ticket 可获得的我正在创建一个插件。我收到以下错误(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