这篇文章也可以在我的博客中查看
在WordPress中存在层级文章的设定,常见于:Page、Custom Post Type
有时候我们需要让子文章的访问权“继承”于父文章,即:
将子文章的状态设置为inherit
一般情况下,inherit
主要用于attachment等附属于主文章的内容,但事实上任何文章都可以设置为inherit
你可以通过以下代码实现:
if ($post_id) {
$post_data = array(
'ID' => $post_id,
'post_status' => 'inherit',
);
wp_update_post($post_data);
}
但并不推荐这么做,因为:
在某个hook中检测当前文章的父文章/祖先文章的状态,再检测当前用户的访问权限,最后根据结果决定是否驳回。
我们可以使用get_post_ancestors()
获取文章的各级祖宗,返回是个list
$ancestors = get_post_ancestors($post->ID);
是什么权限?
是使用current_user_can()
检测用户是否有私有读权限吗?
并不是,如果只检测角色权限(Role Capabilities
),那作者本人或者其它有编辑权限的人也可能会被拦截。
那难道我们就不能用current_user_can()
了?
也不是
虽然这个函数在官方文档中非常隐晦,而且看起来它只能按类别处理权限
但其实不是,它可以按实体处理权限
换言之,它可以实现:用户对“某文章”是否有访问权限
这个东西称为元权限(Meta Capabilities
)
它并不实际存储于任何位置,而是在使用时实时计算,并最终转换为角色权限处理
事实上current_user_can()
可以接受role
或者meta
作为参数
我不知道为什么这么重要的东西在官网找不到
但你可以在这里找到对这个函数更详细的使用介绍
比如我们的目标,检测用户对某私有文章是否有访问权限:
current_user_can('read_post', $private_post_id)
它会检测当前用户是否为作者等有编辑能力的人,随后检测是否有私有读权限
一次满足三个愿望,爽到
我将以继承根文章的访问权限作为例子
如果你需要继承其它层级,你需要做一些小改动
pre_handle_404
可以最快地在主查询后访问结果所以我们可以写出这样的代码:
add_filter('pre_handle_404', function ($_, $wp_query) {
if (empty($wp_query->post))
return false;
$ancestors = get_post_ancestors($wp_query->post->ID);
$ancestor_id = end($ancestors);
// 是子文章,且无权访问爷/爹
if ($ancestor_id && !current_user_can('read_post', $ancestor_id)) {
//清空文章
$wp_query->posts = [];
unset($wp_query->post);
$wp_query->post_count = 0;
//设置404
$wp_query->set_404();
status_header(404);
nocache_headers();
}
return false;
}, 10, 2);
参数$wp_query
中存储了当前的文章
如果压根没有文章,我们提前返回
否则就检测用户对根文章的访问权限
使用get_post_ancestors()
获得各级祖先,再用end()
得到最后一个元素,即根文章
若根文章是私有/草稿,且用户无访问权限,我们就返回404