登录

在这个站点登录

保存我的登录记录

<<忘记密码?

还没有账号?点此注册>>

Jerry

WordPress自定义文章密码表单

分享到:

本文已被浏览2071

WordPress的文章或者页面有三种保密等级:开放、密码、私密。最常见的就是开放等级,访客不受任何限制即可看到文章的内容;对于密码等级的文章,WordPress添加一个文章密码,当访客希望查看文章的内容时,必须提供管理员或者作者提供的密码才能看到文章的内容;私密等级的文章就直接不对任何访客开放,只有作者才能看到文章和其内容。

最近完成齐软之后,本想吐槽一下齐软,文章写出来有点反动所以想加个密码,然而,仅仅是在本地镜像站试着加了一个带有密码的测试文章,发现那个索要密码的表单简直丑爆,导致我最后吐槽齐软的动力全转化成吐槽密码表单的动力。光这么放着也不行啊,强迫症的我决定魔改一波~~

WordPress原生密码表单

最开始,这个框子从哪里来的我也不是很清楚,但是唯一知道的是主题调用了the_content函数来输出文章内容,而这个表单恰巧完整的替代了文章内容,所以表单必定是由the_content函数来输出。通过FileLocator的搜索,这个函数的定义在wp-include/post-template.php中的230行附近:

/**
 * Display the post content.(显示文章的内容)
 *
 * @since 0.71(源自 0.71)
 *
 * @param string $more_link_text Optional. Content for when there is more text.(可选,'更多内容'连接显示的内容)
 * @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false.(可选,在'更多内容'分隔栏的内容)
 */
function the_content( $more_link_text = null, $strip_teaser = false) {
    $content = get_the_content( $more_link_text, $strip_teaser );
    /**
     * Filters the post content.(过滤修饰文章内容)
     *
     * @since 0.71(源自0.71)
     *
     * @param string $content Content of the current post.(参数$content包含了当前文章的内容)
     */
    $content = apply_filters( 'the_content', $content );
    $content = str_replace( ']]&gt;', ']]&amp;gt;', $content );
    echo $content;
}

函数功能很简单,get_the_content然后触发过滤器the_content最后输出。这些代码的内容和密码表单没有任何关系,想必是在get_the_content函数的返回值就已经是一个表单了,所以继续追踪get_the_content函数,这个函数就在the_content附近,位于260行。这个函数就复杂点了,不过发现其中有这么一点东西:

	$output = '';
	$has_teaser = false;

	// If post password required and it doesn't match the cookie.(如果文章需要密码验证并且Cookie中不包含使访客正确通过授权的参数)
	if ( post_password_required( $post ) )
		return get_the_password_form( $post );

	if ( $page > count( $pages ) ) // if the requested page doesn't exist
		$page = count( $pages ); // give them the highest numbered page that DOES exist

从函数名也能够看出来在干些什么:先判断是否需要密码解锁,如果需要就输出表单,否则继续执行并输出文章内容。那么距离真相已经很近了,这个表单一定在get_the_password_form中。巧的是这个函数也在这个文件中,这里把它全部复制到到这里了:

/**
 * Retrieve protected post password form content.(取得文章密码索取表单的内容)
 *
 * @since 1.0.0
 *
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.(可选,PostID或者一个WP_Post的对象,默认情况下是全局变量$post)
 * @return string HTML content for password form for password protected post.(返回以HTML形式表示的密码表单)
 */
function get_the_password_form( $post = 0 ) {
	$post = get_post( $post );
	$label = 'pwbox-' . ( empty($post->ID) ? rand() : $post->ID );
	$output = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass', 'login_post' ) ) . '" class="post-password-form" method="post">
	<p>' . __( 'This content is password protected. To view it please enter your password below:' ) . '</p>
	<p><label for="' . $label . '">' . __( 'Password:' ) . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr_x( 'Enter', 'post password form' ) . '" /></p></form>
	';

	/**
	 * Filters the HTML output for the protected post password form.(过滤修饰表单的HTML输出)
	 *
	 * If modifying the password field, please note that the core database schema(如果您希望修改密码字段,请注意)
	 * limits the password field to 20 characters regardless of the value of the(无论表单允许输入多少个字符核心)
	 * size attribute in the form input.(数据默认密码字段只允许最多20个字符.)
	 *
	 * @since 2.7.0(源自2.7.0)
	 *
	 * @param string $output The password form HTML output.(参数$output时密码表单的HTML格式的输出)
	 */
	return apply_filters( 'the_password_form', $output );
}

从上边的代码即可看出,首先是获取到文章的编号,然后使用编号构建一个表单,将表单使用get_the_password_form过滤器来处理一下,然后返回。比较想不通的就是WordPress官方为什么不把到手的postid给过滤器传一下,而是只传一个生成完成的表单html,这样还得让开发者自己写正则来取出postid。既然都分析到这里了,那么剩下的也就好说了。直接给get_the_password_form挂一个自定义函数,重新生成表单的html结构并返回。

首先,我们需要自己定义一个位于functions.php的函数用来处理这个表单,暂且就叫jz_password_form吧:

function jz_password_form($form){
	//这里提供一些从原版form中提取postid的代码,以供使用
	preg_match_all("/pwbox-\\d+/",$form,$matches);
	$match=array_unique($matches[0])[0];
	preg_match("/\\d+/",$match,$matches);
	$postid=intval($matches[0]);
	//开始自定义生成表单
	$html=$form;       //这里不做特殊的表单代码生成实例,以免干扰您的思路
	//结束
	return $html;
	}

这里需要注意的是密码表单最终提交的位置,如果不希望把这里改成ajax的,需要把表单以post方式提交到http://domain/path/to/wordpress/wp-login.php?action=postpass才能让WordPress正确的接收到访客提交的密码并将密码的Hash值写入Cookie,从而使post_password_required函数能够正确的判断出授权状态。表单的内容中包含了文章的密码,命名为post_password。

完成上述内容之后,一定要把这个函数使用add_filter与get_the_password_form进行绑定,随后才能被WordPress的核心源码调用并替换掉那个原版密码表单。

add_filter("get_the_password_form","jz_password_form");

然后创建一个带有密码的文章或者页面进行测试:
最终效果图
后来发现这种直接提交的界面交互不是太好,就又把它改成了ajax的,直接创建一个ajax接口来实现wp-login中action为postpass部分的代码(实际上就是求hash值然后存进Cookie,让我比较费解的是如果访客正确的通过了两个文章,第二个文章通过授权时会不会把第一个文章的密码从Cookie中覆盖掉)。至于具体的jQuery如何做ajax,就不再赘言。
除了这些内容,后来发现网上一些针对页面访问量统计的代码中缺少对于这种密码文章的统计控制。在输入密码前是不应当将访客统计如已查看的计数当中,所以需要在形如set_post_views之类的函数最开始调用一下post_password_required来判断一下当前的访客是否真正的看到了文章的内容.

 手机扫描左边的二维码,立刻将文章收入手机!
 微信扫描左边二维码,点击右上角即可分享到朋友圈!
严禁任何非授权的采集与转载,转载须经站长同意并在文章显著位置标注本文连接,站长保留追究法律责任的权利.

评论

 您需要 先登录 才可以回复.