- Extract _build_article_where() helper, eliminating duplicated WHERE
logic from _get_article_list() and _get_article_list_grouped()
- Add template_slug='__manual__' sentinel → filters template_slug IS NULL
(cornerstone / hand-written articles without a pSEO template)
- Add GET /articles/matching-count endpoint returning count of articles
matching current filter params (for the Gmail-style select-all banner)
- Extend POST /articles/bulk with apply_to_all=true mode: builds WHERE
from filter params instead of explicit IDs; rebuild capped at 2,000,
delete at 5,000
- Add "Manual" option to Template filter dropdown
- Add Gmail-style "select all matching" banner: appears when select-all
checkbox is checked, fetches total count, lets user switch to
apply_to_all mode with confirmation dialog
- Sync filter hidden inputs into bulk form on filter change; changing
filters resets apply-to-all state and clears selection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>