Add language filter to Discover

The CDX languages field (ISO 639 codes, e.g. "spa,eng") has been
captured on every page since the first ingestion command, but never
surfaced anywhere. Filters via FIND_IN_SET for an exact code match
rather than a LIKE substring match, since the column holds a
comma-separated list.

Verified against real data: lang=spa returns exactly the expected 47
sites (25+22 across two pages), a bogus code renders the empty state,
and lang=spa combined with tld=es correctly narrows to 20.
This commit is contained in:
m105
2026-07-22 23:11:30 +03:00
parent 59e152fd29
commit 4c0cc5a7f5
2 changed files with 28 additions and 3 deletions
+21 -2
View File
@@ -14,7 +14,8 @@ use Livewire\WithPagination;
* The competitor-discovery search: "who sells honey with a .es domain?" — keyword
* matches a site's pages via MySQL fulltext (natural language mode, so free-text input
* never trips a boolean-mode syntax error), TLD filters the site's domain suffix,
* platform filters its detected server/powered-by/generator signature.
* platform filters its detected server/powered-by/generator signature, language
* filters by the CDX-reported ISO 639 code of a page's content (e.g. "spa", "eng").
*/
#[Layout('components.layouts.app')]
class Search extends Component
@@ -30,6 +31,9 @@ class Search extends Component
#[Url(as: 'platform', history: true)]
public string $platform = '';
#[Url(as: 'lang', history: true)]
public string $language = '';
public function updatingKeyword(): void
{
$this->resetPage();
@@ -45,12 +49,18 @@ class Search extends Component
$this->resetPage();
}
public function updatingLanguage(): void
{
$this->resetPage();
}
public function render(): View
{
$keyword = trim($this->keyword);
$tld = strtolower(trim(ltrim($this->tld, '.')));
$platform = trim($this->platform);
$hasQuery = $keyword !== '' || $tld !== '' || $platform !== '';
$language = strtolower(trim($this->language));
$hasQuery = $keyword !== '' || $tld !== '' || $platform !== '' || $language !== '';
// Without any filter this would just be the full site list — that's what the
// Sites page is for. Discover only returns results once you've asked it something.
@@ -73,6 +83,15 @@ class Search extends Component
->orWhere('generator', 'like', '%'.$platform.'%');
});
})
->when(
$language !== '',
// languages is a comma-separated list of ISO 639 codes (e.g. "spa,eng") —
// FIND_IN_SET matches an exact code, not a LIKE substring match.
fn ($query) => $query->whereHas(
'pages',
fn ($pageQuery) => $pageQuery->whereRaw('FIND_IN_SET(?, languages)', [$language])
)
)
->withCount(['pages as matching_pages_count' => function ($pageQuery) use ($keyword) {
if ($keyword !== '') {
$pageQuery->whereFullText(['title', 'description', 'keywords', 'content'], $keyword);
@@ -23,6 +23,12 @@
placeholder="Platform, e.g. WordPress"
class="w-full max-w-[14rem] rounded-md border border-neutral-300 px-3 py-2 text-sm focus:border-neutral-500 focus:outline-none dark:border-neutral-700 dark:bg-neutral-900"
>
<input
type="text"
wire:model.live.debounce.400ms="language"
placeholder="Language code, e.g. spa"
class="w-full max-w-[12rem] rounded-md border border-neutral-300 px-3 py-2 text-sm focus:border-neutral-500 focus:outline-none dark:border-neutral-700 dark:bg-neutral-900"
>
</div>
<div class="mt-6 overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-800">
@@ -53,7 +59,7 @@
@if ($hasQuery)
No matching sites.
@else
Enter a keyword, TLD, or platform to search.
Enter a keyword, TLD, platform, or language to search.
@endif
</td>
</tr>