fix(admin): replicate reference advanced-filter settings page 1:1

- Rewrite post_list/filter schema (PHP + JS) with the reference theme's
  field set, order, defaults and dependencies; topics fields excluded
  (no topics taxonomy), AKSRT private filter_* toggles dropped
- Support dynamic checkbox options in AksField (options as formData key)
  so cat_custom_filter.custom_filters lists the custom_filter dimensions
- Map PostDisplay filter settings to the new keys without legacy fallback;
  cat_custom_filter now carries lists/dropdown fieldsets and array filters
- Wire the archive chain to reference semantics: cat_custom_filter
  overrides per-category filter projects, custom_filter_show gates the
  default display, dimension chip groups render on category/tag archives
- Filter archive queries (main query + AJAX endpoint) by _aksrt_cf_{key}
  meta with exact-quoted LIKE matching
- Add advanced-filter settings reference contract test
This commit is contained in:
2026-09-24 15:39:25 +08:00
parent 4d6b2c6045
commit a8060fa71d
16 changed files with 635 additions and 154 deletions
+69 -24
View File
@@ -104,34 +104,46 @@ class PostDisplay {
$settings = Settings::get_all();
return [
'enabled' => !empty($settings['filter_enabled']),
'categories' => !isset($settings['filter_categories']) || !empty($settings['filter_categories']),
'tags' => !empty($settings['filter_tags']),
'sort' => !isset($settings['filter_sort']) || !empty($settings['filter_sort']),
'ajax_enabled' => !empty($settings['filter_ajax_enabled']),
'cat_show_cat' => !isset($settings['filter_cat_show_cat']) || !empty($settings['filter_cat_show_cat']),
'cat_show_tag' => !empty($settings['filter_cat_show_tag']),
'tag_show_cat' => !isset($settings['filter_tag_show_cat']) || !empty($settings['filter_tag_show_cat']),
'tag_show_tag' => !empty($settings['filter_tag_show_tag']),
'custom_filter_show' => is_array($settings['custom_filter_show'] ?? null) ? array_map('sanitize_key', $settings['custom_filter_show']) : ['cat', 'tag'],
'custom_filter_show' => is_array($settings['custom_filter_show'] ?? null) ? array_values(array_intersect(array_map('sanitize_key', $settings['custom_filter_show']), ['cat', 'tag'])) : [],
'custom_filter' => self::sanitize_custom_filter_defs($settings['custom_filter'] ?? []),
'cat_custom_filter' => self::sanitize_cat_custom_filter($settings['cat_custom_filter'] ?? []),
];
}
public static function get_filter_config_for_category(int $term_id): array {
/**
* 归档页高级筛选配置(参考主题 zib-category.php:zib_get_ajax_option_menu 语义)。
*
* cat 页优先匹配 cat_custom_filter(绑定 cats 含当前 term 时全量覆盖筛选项目);
* 未匹配或 tag 页回退默认配置:custom_filter_show 决定是否显示自定义筛选('all')。
*
* @return array{custom_enabled:bool,custom_filters:mixed,overrides:array<string,mixed>}
*/
public static function get_archive_custom_filter_config(int $term_id, string $page): array {
$cfg = self::get_post_filter_settings();
foreach ($cfg['cat_custom_filter'] as $rule) {
if (in_array($term_id, $rule['cats'], true)) {
return $rule;
if ($page === 'cat') {
foreach ($cfg['cat_custom_filter'] as $rule) {
if (in_array($term_id, $rule['cats'], true)) {
return [
'custom_enabled' => $rule['custom_filters'] !== [],
'custom_filters' => $rule['custom_filters'],
'overrides' => [
'cat_s' => $rule['cat_s'],
'cat_lists' => $rule['cat_lists'],
'tag_s' => $rule['tag_s'],
'tag_lists' => $rule['tag_lists'],
'orderby_s' => $rule['orderby_s'],
'orderby_lists' => $rule['orderby_lists'],
],
];
}
}
}
return [
'cats' => [],
'cat_s' => $cfg['cat_show_cat'],
'tag_s' => $cfg['cat_show_tag'],
'orderby_s' => $cfg['sort'],
'custom_filters' => [],
'custom_enabled' => in_array($page, $cfg['custom_filter_show'], true),
'custom_filters' => 'all',
'overrides' => [],
];
}
@@ -506,16 +518,49 @@ class PostDisplay {
if (!is_array($item)) continue;
$cats = is_array($item['cats'] ?? null) ? array_values(array_filter(array_map('absint', $item['cats']), static fn($id) => $id > 0)) : [];
if (empty($cats)) continue;
$filters_raw = trim((string) ($item['custom_filters'] ?? ''));
$filters = $filters_raw === '' ? [] : array_values(array_filter(array_map('sanitize_key', preg_split('/[,,\s]+/', $filters_raw) ?: [])));
$result[] = [
'cats' => $cats,
'cat_s' => !isset($item['cat_s']) || !empty($item['cat_s']),
'cat_s' => !empty($item['cat_s']),
'cat_lists' => self::sanitize_filter_option_lists($item['cat_lists'] ?? []),
'tag_s' => !empty($item['tag_s']),
'orderby_s' => !isset($item['orderby_s']) || !empty($item['orderby_s']),
'custom_filters' => $filters,
'tag_lists' => self::sanitize_filter_option_lists($item['tag_lists'] ?? []),
'orderby_s' => !empty($item['orderby_s']),
'orderby_lists' => self::sanitize_filter_orderby_lists($item['orderby_lists'] ?? []),
'custom_filters' => is_array($item['custom_filters'] ?? null)
? array_values(array_unique(array_filter(array_map('sanitize_key', $item['custom_filters']))))
: [],
];
}
return $result;
}
/**
* 归档筛选按钮列表 fieldset(lists + dropdown,参考主题 CFS_Module::ajax_but)。
*/
private static function sanitize_filter_option_lists($raw): array {
$option = is_array($raw) ? $raw : [];
$lists = is_array($option['lists'] ?? null) ? array_values(array_filter(array_map('absint', $option['lists']), static fn($id) => $id > 0)) : [];
return [
'lists' => $lists,
'dropdown' => !empty($option['dropdown']),
];
}
/**
* 排序方式 fieldset(lists + dropdown,参考主题 CFS_Module::orderby)。
*/
private static function sanitize_filter_orderby_lists($raw): array {
$option = is_array($raw) ? $raw : [];
$allowed = Settings::homepage_allowed_sorts();
$lists = is_array($option['lists'] ?? null)
? array_values(array_intersect(array_map('sanitize_key', $option['lists']), $allowed))
: [];
if ($lists === []) {
$lists = ['modified', 'views', 'like', 'comment_count'];
}
return [
'lists' => $lists,
'dropdown' => !empty($option['dropdown']),
];
}
}