# HXSE — Code-First Search

> Code-first search & filter for WordPress. Define filters with PHP arrays, output with a shortcode. Powered by htmx — no page reloads.

Current version: 1.7.0
WordPress.org: https://wordpress.org/plugins/hxse-code-first-search/
GitHub: https://github.com/okuboyouhei/hxse-code-first-search
Author: Youhei Okubo (https://zenn.dev/youheiokubo)

## Docs

- [ai-reference.md](./docs/ai-reference.md): Full schema reference for AI agents
- [readme.txt](./readme.txt): WordPress.org readme

## Key Facts

- Shortcode: `[hxse id="schema_key"]`
- Filter: `hxse_schemas`
- Filter types: search, taxonomy, meta, date, relation, select (external sources v1.8.0+, merged mode v1.9.0+)
- UI types: select, radio, checkbox, range
- Display modes: grid (default), list, table, custom
- Grid columns: controlled via `columns` key (default: 3)
- Table headers: customizable via `table_columns` key
- Display switcher: `display_switcher: ['grid','list','table']`
- Tabs: `tabs` key for tab-based filtering
- Pagination modes: pager, loadmore
- URL parameter sync with browser history support
- Multiple instances on one page supported via `prefix`
- htmx bundled (no jQuery required)
- Assets loaded only on pages with [hxse] shortcode
- No database for schema — code only
- Static-site mode (Distan, v2.0.0+): htmx/REST-free client-side filtering; auto-detected via `X-Distan-Render`, or force with `'static' => true`; client-side pagination v2.1.0+ (honors `pagination`, works with/without filters); client-side sort v2.2.0+ (honors `sort`: `date_*` / `title_*` / `menu_order`)
- AI-friendly: simple consistent schema structure

## Version history (latest first)

### v2.2.0
- Added: Sort in static mode — the `sort` schema (wp_query keys `date_desc` / `date_asc` / `title_asc` / `title_desc` / `menu_order`) is reproduced client-side; composes with filters and pagination, resets to page 1 on change

### v2.1.0
- Added: Client-side pagination in static mode — honors the schema's `pagination` (`per_page` / `range` / labels / `count_format`); works with or without filters, resets to page 1 on filter change; `pagination.mode: 'none'` (or `per_page: 0`) renders all on one page
- Fixed: Static-mode inline script is now printed via `wp_footer` instead of inside `the_content`, so content filters (wpautop / wptexturize) can no longer break the JS

### v2.0.0
- Added: Static-site (Distan) mode — when a page is statically generated, HXSE serves an htmx/REST-free variant so search keeps working after WordPress is removed from production
- Added: Auto-detection via the `X-Distan-Render` request header (no config); force with `'static' => true|false` or the `hxse_static_active` filter
- Added: Client-side filtering over baked items for `wp_query` sources (`search`, `taxonomy`, non-range `meta`) via `data-*` attributes; live count and no-results without a server
- Added: `hxse_static_max_items` filter (default 500) — above the cap, static mode falls back to a plain paged list
- Note: In static mode htmx and `hxse.js` are not enqueued; `range` / `date` / `relation` / sort / `table` are not reproduced; external `api` / `rss` / `xml` / `sources` are baked as a filter-less snapshot; `ai-reference.md` is relocated under `docs/` in the WordPress.org build

### v1.9.0
- Added: Filter / sort / pagination for merged mode (`sources`) — same opt-in mechanism as v1.8.0 external sources (`filters` / `sort` / `pagination` in schema)
- Added: REST endpoint branch for merged-mode schemas — htmx filter interactions and pager work without page reloads
- Note: Merged items are normalized, so filter/sort fields target `title` / `link` / `date` / `excerpt` / `source`; `'field' => 'source'` + `'options' => 'auto'` generates a per-source filter from source labels
- Note: In-memory processing of merged cached data; no remote re-fetches. Pager mode only (no loadmore). Backward compatible.

### v1.8.0
- Added: Filter UI for external sources (api / rss / xml) — `search` and `select` filter types work on fetched data (opt-in via `filters` / `sort` / `pagination` in schema)
- Added: `select` filter type — exact match on any item field, `'options' => 'auto'` generates choices from data
- Added: `sort` for external sources — `field` / `order` / `compare` ('string' | 'numeric' | 'date')
- Added: Pagination for external sources — in-memory slicing of cached data
- Added: `items_key` — extract item list from wrapped JSON payloads (dot notation)
- Added: Bundled default template `templates/api.php` — replaces raw JSON debug output for schemas without a custom template
- Note: All external-source filtering runs in memory against cached data; no remote re-fetches on filter interaction
- Note: Fully backward compatible — schemas without filters/sort/pagination behave as before

### v1.7.0
- Added: 埋め込みビュー内のフィルターUI（embed.show_filters、WordPressソースのみ）
- Added: iframe高さの自動通知（postMessageで親に通知。load/resize/htmx絞り込み後）
- Added: postMessage送信先originをallowed_originsに限定（ワイルドカード不使用）
- Note: 親ページ側にiframe自動リサイズ用の受信スニペットを貼る必要あり（マニュアル参照）

### v1.6.0
- Added: iframe埋め込みビュー（?hxse_embed={schema_id} で一覧のみの自己完結HTMLを出力）
- Added: embedスキーマキー（enabled / allowed_origins / title / per_page）
- Added: クリックジャッキング対策（CSP frame-ancestorsで許可ドメインを制限）

### v1.5.0
- Added: マージモード（sourcesキー）— WordPress投稿・RSS・APIを1つの時系列リストに統合
- Added: ソース正規化（wp_query/rss/api/xmlを共通フォーマットに変換）
- Added: orderby/order/limit でマージ後のソート・件数制限
- Added: mapキーでAPI/XMLのキーマッピング
- Added: templates/merged.php（ソースバッジ付きデフォルトテンプレート）

### v1.4.0
- Added: `source: 'rss'` — RSS 2.0・AtomフィードをPHP配列に自動変換
- Added: `source: 'xml'` — 汎用XMLをxpathでPHP配列に変換
- Improved: hxse_do_remote_fetchがjson/rss/xmlをsourceキーで切り替え

### v1.3.0
- Added: キャッシュマッピング（hxse_cache_mapオプション）でスキーマID→ファイル名の対応を管理
- Added: 孤立ファイル検出・警告・一括削除
- Added: 「今すぐ更新」ボタン（管理画面からAPIを即時フェッチ・JSON再生成）
- Added: 全キャッシュ一括削除・合計サイズ表示
- Improved: hxse_delete_static_cache()でマッピングも同時削除
- Improved: uninstall.phpでhxse_cache_mapオプションも削除

### v1.2.0
- Added: `cache_mode: 'static'` — APIレスポンスをJSONファイルとして保存（wp-content/hxse-cache/、.htaccessでWebアクセスをブロック）
- Added: `cache_file` key — 静的キャッシュのファイル名を指定
- Added: `includes/cache.php` — キャッシュディレクトリ管理
- Improved: `hxse_fetch_api_data()` をtransient/staticの2モードに対応

### v1.1.0
- Added: `source: 'api'` mode — PHPで外部APIをフェッチしてテーマテンプレートに渡す
- Added: `token` key — `_token` GETパラメータでAPI認証
- Added: `cache` key — transientベースのAPIレスポンスキャッシュ

### v1.0.2
- Added: SECURITY.md — security policy, vulnerability reporting, disclosure timeline
- Added: MAINTENANCE.md — architecture overview, htmx update steps, fork guide
- Docs: Updated ai-reference.md — design philosophy and maintainability section for AI agents

### v1.0.1
- Added: `columns` key for grid column count control
- Added: `table_columns` key for custom table headers
- Added: `display_switcher` for grid/list/table switching
- Added: `tabs` for tab-based filtering
- Added: `conditions` for fixed filter conditions without UI
- Fixed: Assets now loaded only on pages with [hxse] shortcode
