Skip to content

Commit

Permalink
规范:多重筛选对 $_GET 参数的解析
Browse files Browse the repository at this point in the history
  • Loading branch information
swling committed Nov 17, 2022
1 parent 1a65ef6 commit 8313b85
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 96 deletions.
6 changes: 3 additions & 3 deletions docs/$_GET.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
### 移除
```php
// 完全移除
remove_action('pre_get_posts', ['Wnd\View\Wnd_Filter', 'action_on_pre_get_posts']);
remove_action('pre_get_posts', ['Wnd\View\Wnd_Filter_Query', 'action_on_pre_get_posts']);

// 选择性移除示例:当请求参数中包含 action 时移除
if(isset($_GET['action'])){
remove_action('pre_get_posts', ['Wnd\View\Wnd_Filter', 'action_on_pre_get_posts']);
remove_action('pre_get_posts', ['Wnd\View\Wnd_Filter_Query', 'action_on_pre_get_posts']);
}
```

### 参考
@see Wnd\View\Wnd_filter::parse_query_vars();
@see Wnd\View\Wnd_Filter::action_on_pre_get_posts();
@see Wnd\View\Wnd_Filter_Query::action_on_pre_get_posts();
3 changes: 2 additions & 1 deletion includes/hook/wnd-add-action-wp.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private function __construct() {
add_action('before_delete_post', [__CLASS__, 'action_on_before_delete_post'], 10, 1);
add_action('post_updated', [__CLASS__, 'action_on_post_updated'], 10, 3);
add_action('add_attachment', [__CLASS__, 'action_on_add_attachment'], 10, 1);
add_action('pre_get_posts', ['Wnd\View\Wnd_Filter', 'action_on_pre_get_posts'], 10, 1);
add_action('pre_get_posts', ['Wnd\View\Wnd_Filter_Query', 'action_on_pre_get_posts'], 10, 1);

/**
* 匿名用户评论验证码,基于 WordPress 原生评论表单及 wp_handle_comment_submission 评论提交
Expand Down Expand Up @@ -265,4 +265,5 @@ public static function action_before_shutdown() {
}
}
}

}
21 changes: 4 additions & 17 deletions includes/view/wnd-filter-abstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,26 +53,12 @@ public function __construct(bool $independent = true) {
$this->independent = $independent;
$this->wp_base_url = get_pagenum_link(1, false);

// 初始化查询参数
$defaults = [
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => [],
'tax_query' => [],
'date_query' => [],
'meta_key' => '',
'meta_value' => '',
'post_type' => '',
'post_status' => '',
'no_found_rows' => true,
'paged' => 1,
];

/**
* - 独立型 WP Query:分页需要自定义处理
* - 依赖型 WP Query:获取全局 $wp_query,并读取全局查询参数赋值到当前筛选环境,以供构建与之匹配的 tabs
* @since 0.8.64
*/
$defaults = [];
if ($this->independent) {
$this->wp_base_url = remove_query_arg(Wnd_Pagination::$page_query_var, $this->wp_base_url);
} else {
Expand All @@ -82,7 +68,7 @@ public function __construct(bool $independent = true) {
}

$this->wp_query = $wp_query;
$defaults = array_merge($defaults, $wp_query->query_vars);
$defaults = $wp_query->query_vars;
}

/**
Expand Down Expand Up @@ -528,7 +514,7 @@ protected function build_current_filter() {
/**
* 执行查询
* - 执行独立 WP Query
* - 当设置为非独立查询(依赖当前页面查询)时,查询参数将通过 'pre_get_posts' 实现修改,无需执行 WP Query @see static::action_on_pre_get_posts();
* - 当设置为非独立查询(依赖当前页面查询)时,查询参数将通过 'pre_get_posts' 实现修改,无需执行 WP Query @see Wnd\View\Wnd_Filter_Query::action_on_pre_get_posts();
* 当下场景中 $this->wp_query 为 global $wp_query; @see __construct();
* @since 2019.08.01
* @since 0.8.64
Expand Down Expand Up @@ -652,4 +638,5 @@ abstract protected function get_results();
* @since 0.9.25
*/
abstract protected function get_pagination();

}
103 changes: 101 additions & 2 deletions includes/view/wnd-filter-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,28 @@ class Wnd_Filter_Query {
*/
private $query_vars = [];

// 初始化查询参数
public static $defaults = [
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => [],
'tax_query' => [],
'date_query' => [],
'meta_key' => '',
'meta_value' => '',
'post_type' => '',
'post_status' => '',
'no_found_rows' => true,
'paged' => 1,
];

/**
* Constructor.
* 解析 GET 请求为查询参数,并与默认参数合并组成初始查询参数
*/
public function __construct(array $default_query_vars = []) {
static::$request_query_vars = static::parse_query_vars();
$this->query_vars = array_merge($default_query_vars, static::$request_query_vars);
$this->query_vars = array_merge(static::$defaults, $default_query_vars, static::$request_query_vars);
}

/**
Expand Down Expand Up @@ -68,6 +83,12 @@ public static function parse_query_vars(): array{
'date_query' => [],
];

/**
* @since 0.9.59
* 新增 $allowed_keys = array_keys(static::$defaults);
* 若不设置 $allowed_keys 则 $_GET 参数将全部写入 WP_Query 可能引起错误的数据库查询
*/
$allowed_keys = array_keys(static::$defaults);
foreach ($_GET as $key => $value) {
/**
* post type tabs生成的GET参数为:type={$post_type}
Expand Down Expand Up @@ -152,7 +173,11 @@ public static function parse_query_vars(): array{
continue;
}

// 其他:按键名自动匹配
// 其他:若在允许的查询键名范围内,按键名自动匹配
if (!in_array($key, $allowed_keys)) {
continue;
}

if (is_array($value)) {
$query_vars = wp_parse_args($value, $query_vars);
} else {
Expand Down Expand Up @@ -242,4 +267,78 @@ public function get_query_vars(): array{
public function get_add_query_vars(): array{
return $this->add_query_vars;
}

/**
* 多重筛选:解析 $_GET 获取 WP_Query 参数,写入查询
* - 排除无 $_GET 参数的查询
* - 排除后台
* - 排除 Ajax 请求
* - 排除内页
* - 排除 WP 内置功能型 Post Type 查询
* 在内页或 Ajax 请求中,应且只能执行独立的 WP Query
*
* @since 0.8.64
* @since 0.8.72
*/
public static function action_on_pre_get_posts($query) {
if (empty($_GET) or is_admin() or wnd_is_rest_request() or $query->is_singular()) {
return $query;
}

$post_type = $query->query_vars['post_type'] ?? false;
if ($post_type) {
if (is_array($post_type)) {
foreach ($post_type as $single_post_type) {
if (!in_array($single_post_type, static::get_supported_post_types())) {
return $query;
}
}unset($single_post_type);
}

if (!in_array($post_type, static::get_supported_post_types())) {
return $query;
}
}

/**
* 解析 $_GET 获取 WP_Query 参数
* - 排除分页:pre_get_posts 仅适用于非独立 wp query,此种情况下分页已在 URL 中确定
*/
$query_vars = static::parse_query_vars();
if (!$query_vars) {
return $query;
}
unset($query_vars['paged']);

/**
* 依次将 $_GET 解析参数写入
*/
foreach ($query_vars as $key => $value) {
/**
* tax_query 需要额外处理:
* 当在 taxonomy 归档页添加其他分类多重查询时,会导致归档类型判断错乱。
* 为保证归档页类型不变,需要提前获取默认 tax_query 查询参数,并保证默认查询为查询数组首元素(WP 以第一条 taxonomy 为标准)。
* @see WP_Query->get_queried_object();
*/
if ('tax_query' == $key) {
$default_tax_query = $query->tax_query->queries ?? [];
$query->set($key, array_merge($default_tax_query, $value));
} else {
$query->set($key, $value);
}
}unset($key, $value);

return $query;
}

/**
* 定义多重筛选支持的 Post Types
* - 排除 WP 内置功能型 Post Type 查询
* @since 0.9.0
*/
private static function get_supported_post_types(): array{
$custom_post_types = get_post_types(['_builtin' => false]);
return array_merge($custom_post_types, ['post' => 'post', 'page' => 'page', 'attachment' => 'attachment']);
}

}
71 changes: 0 additions & 71 deletions includes/view/wnd-filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,75 +206,4 @@ public function get_results(): string {
return $this->get_posts() . $this->get_pagination();
}

/**
* 多重筛选:解析 $_GET 获取 WP_Query 参数,写入查询
* - 排除无 $_GET 参数的查询
* - 排除后台
* - 排除 Ajax 请求
* - 排除内页
* - 排除 WP 内置功能型 Post Type 查询
* 在内页或 Ajax 请求中,应且只能执行独立的 WP Query
* @since 0.8.64
* @since 0.8.72
*/
public static function action_on_pre_get_posts($query) {
if (empty($_GET) or is_admin() or wnd_is_rest_request() or $query->is_singular()) {
return $query;
}

$post_type = $query->query_vars['post_type'] ?? false;
if ($post_type) {
if (is_array($post_type)) {
foreach ($post_type as $single_post_type) {
if (!in_array($single_post_type, static::get_supported_post_types())) {
return $query;
}
}unset($single_post_type);
}

if (!in_array($post_type, static::get_supported_post_types())) {
return $query;
}
}

/**
* 解析 $_GET 获取 WP_Query 参数
* - 排除分页:pre_get_posts 仅适用于非独立 wp query,此种情况下分页已在 URL 中确定
*/
$query_vars = Wnd_Filter_Query::parse_query_vars();
if (!$query_vars) {
return $query;
}
unset($query_vars['paged']);

/**
* 依次将 $_GET 解析参数写入
*/
foreach ($query_vars as $key => $value) {
/**
* tax_query 需要额外处理:
* 当在 taxonomy 归档页添加其他分类多重查询时,会导致归档类型判断错乱。
* 为保证归档页类型不变,需要提前获取默认 tax_query 查询参数,并保证默认查询为查询数组首元素(WP 以第一条 taxonomy 为标准)。
* @see WP_Query->get_queried_object();
*/
if ('tax_query' == $key) {
$default_tax_query = $query->tax_query->queries ?? [];
$query->set($key, array_merge($default_tax_query, $value));
} else {
$query->set($key, $value);
}
}unset($key, $value);

return $query;
}

/**
* 定义多重筛选支持的 Post Types
* - 排除 WP 内置功能型 Post Type 查询
* @since 0.9.0
*/
private static function get_supported_post_types(): array{
$custom_post_types = get_post_types(['_builtin' => false]);
return array_merge($custom_post_types, ['post' => 'post', 'page' => 'page', 'attachment' => 'attachment']);
}
}
4 changes: 2 additions & 2 deletions wnd-frontend.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: Wnd-Frontend
* Plugin URI: https://github.com/swling/wnd-frontend
* Description: Wnd-Frontend 是一套基于 ajax 交互逻辑的 WordPress 前端基础框架。商业用途需购买授权。<a href="https://github.com/swling/wnd-frontend/releases">更新日志</a>
* Version: 0.9.58.12
* Version: 0.9.59
* Author: swling
* Author URI: https://wndwp.com
* Requires PHP: 7.3
Expand All @@ -26,7 +26,7 @@
use Wnd\Model\Wnd_Init;

// 版本
define('WND_VER', '0.9.58.12');
define('WND_VER', '0.9.59');

// 定义插件网址路径
define('WND_URL', plugin_dir_url(__FILE__));
Expand Down

0 comments on commit 8313b85

Please sign in to comment.