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:
@@ -14,7 +14,8 @@ use Livewire\WithPagination;
|
|||||||
* The competitor-discovery search: "who sells honey with a .es domain?" — keyword
|
* 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
|
* 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,
|
* 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')]
|
#[Layout('components.layouts.app')]
|
||||||
class Search extends Component
|
class Search extends Component
|
||||||
@@ -30,6 +31,9 @@ class Search extends Component
|
|||||||
#[Url(as: 'platform', history: true)]
|
#[Url(as: 'platform', history: true)]
|
||||||
public string $platform = '';
|
public string $platform = '';
|
||||||
|
|
||||||
|
#[Url(as: 'lang', history: true)]
|
||||||
|
public string $language = '';
|
||||||
|
|
||||||
public function updatingKeyword(): void
|
public function updatingKeyword(): void
|
||||||
{
|
{
|
||||||
$this->resetPage();
|
$this->resetPage();
|
||||||
@@ -45,12 +49,18 @@ class Search extends Component
|
|||||||
$this->resetPage();
|
$this->resetPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updatingLanguage(): void
|
||||||
|
{
|
||||||
|
$this->resetPage();
|
||||||
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
$keyword = trim($this->keyword);
|
$keyword = trim($this->keyword);
|
||||||
$tld = strtolower(trim(ltrim($this->tld, '.')));
|
$tld = strtolower(trim(ltrim($this->tld, '.')));
|
||||||
$platform = trim($this->platform);
|
$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
|
// 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.
|
// 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.'%');
|
->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) {
|
->withCount(['pages as matching_pages_count' => function ($pageQuery) use ($keyword) {
|
||||||
if ($keyword !== '') {
|
if ($keyword !== '') {
|
||||||
$pageQuery->whereFullText(['title', 'description', 'keywords', 'content'], $keyword);
|
$pageQuery->whereFullText(['title', 'description', 'keywords', 'content'], $keyword);
|
||||||
|
|||||||
@@ -23,6 +23,12 @@
|
|||||||
placeholder="Platform, e.g. WordPress"
|
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"
|
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>
|
||||||
|
|
||||||
<div class="mt-6 overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-800">
|
<div class="mt-6 overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-800">
|
||||||
@@ -53,7 +59,7 @@
|
|||||||
@if ($hasQuery)
|
@if ($hasQuery)
|
||||||
No matching sites.
|
No matching sites.
|
||||||
@else
|
@else
|
||||||
Enter a keyword, TLD, or platform to search.
|
Enter a keyword, TLD, platform, or language to search.
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user