Skip to content

Commit 830696e

Browse files
authored
Merge pull request #27 from fairpm/ac_22_featured_hotness_take_1
2 parents c56c023 + f88db5e commit 830696e

File tree

2 files changed

+38
-56
lines changed

2 files changed

+38
-56
lines changed

app/Services/PluginServices/QueryPluginsService.php

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ class QueryPluginsService
1212
{
1313
public function queryPlugins(Plugins\QueryPluginsRequest $req): Plugins\QueryPluginsResponse
1414
{
15-
$page = $req->page;
15+
$page = $req->page;
1616
$perPage = $req->per_page;
17-
$browse = $req->browse ?: 'popular';
18-
$search = $req->search ?? null;
19-
$author = $req->author ?? null;
17+
$browse = $req->browse ?: 'popular';
18+
$search = $req->search ?? null;
19+
$author = $req->author ?? null;
2020

2121
// Operators coming from the DTO
22-
$tags = $req->tags ?? [];
22+
$tags = $req->tags ?? [];
2323
$tagAnd = $req->tagAnd ?? [];
24-
$tagOr = $req->tagOr ?? [];
24+
$tagOr = $req->tagOr ?? [];
2525
$tagNot = $req->tagNot ?? [];
2626

2727
// merge base tags with tagOr
@@ -31,8 +31,8 @@ public function queryPlugins(Plugins\QueryPluginsRequest $req): Plugins\QueryPlu
3131
$callbacks = collect();
3232

3333
!empty($anyTags) && $callbacks->push(fn($q) => self::applyTagAny($q, $anyTags));
34-
!empty($tagAnd) && $callbacks->push(fn($q) => self::applyTagAll($q, $tagAnd));
35-
!empty($tagNot) && $callbacks->push(fn($q) => self::applyTagNot($q, $tagNot));
34+
!empty($tagAnd) && $callbacks->push(fn($q) => self::applyTagAll($q, $tagAnd));
35+
!empty($tagNot) && $callbacks->push(fn($q) => self::applyTagNot($q, $tagNot));
3636

3737
$search && $callbacks->push(fn($q) => self::applySearchWeighted($q, $search, $req));
3838
$author && $callbacks->push(fn($q) => self::applyAuthor($q, $author));
@@ -56,7 +56,7 @@ public function queryPlugins(Plugins\QueryPluginsRequest $req): Plugins\QueryPlu
5656

5757
return Plugins\QueryPluginsResponse::from([
5858
'plugins' => $plugins,
59-
'info' => ['page' => $page, 'pages' => $totalPages, 'results' => $total],
59+
'info' => ['page' => $page, 'pages' => $totalPages, 'results' => $total],
6060
]);
6161
}
6262

@@ -69,9 +69,8 @@ public function queryPlugins(Plugins\QueryPluginsRequest $req): Plugins\QueryPlu
6969
public static function applySearchWeighted(
7070
Builder $query,
7171
string $search,
72-
Plugins\QueryPluginsRequest $request
73-
): Builder
74-
{
72+
Plugins\QueryPluginsRequest $request,
73+
): Builder {
7574
$lcsearch = mb_strtolower($search);
7675
$slug = Regex::replace('/[^-\w]+/', '-', $lcsearch);
7776
$wordchars = Regex::replace('/\W+/', '', $lcsearch);
@@ -84,7 +83,7 @@ public static function applySearchWeighted(
8483
->orWhereRaw("slug %> ?", [$wordchars])
8584
->orWhereRaw("name %> ?", [$wordchars])
8685
->orWhereRaw("short_description %> ?", [$wordchars])
87-
->orWhereFullText('description', $search)
86+
->orWhereFullText('description', $search),
8887
)
8988
->selectRaw("plugins.*,
9089
CASE
@@ -97,37 +96,36 @@ public static function applySearchWeighted(
9796
WHEN short_description %> ? THEN 400000
9897
WHEN to_tsvector('english', description) @@ plainto_tsquery(?) THEN 300000
9998
ELSE 0
100-
END + log(GREATEST($sortColumn, 1)) AS score", [
101-
$search,
102-
$search,
103-
"$slug%",
104-
"$search%",
105-
$wordchars,
106-
$wordchars,
107-
$wordchars,
108-
$search,
109-
])
99+
END + log(GREATEST($sortColumn, 1)) AS score",
100+
[
101+
$search,
102+
$search,
103+
"$slug%",
104+
"$search%",
105+
$wordchars,
106+
$wordchars,
107+
$wordchars,
108+
$search,
109+
])
110110
->orderByDesc('score');
111111
}
112112

113113
/** @param Builder<Plugin> $query */
114114
public static function applyAuthor(Builder $query, string $author): Builder
115115
{
116-
return $query->where(fn(Builder $q)
117-
=> $q
116+
return $query->where(fn(Builder $q) => $q
118117
->whereRaw("author %> '$author'")
119118
->orWhereHas(
120119
'contributors',
121-
fn(Builder $q)
122-
=> $q
120+
fn(Builder $q) => $q
123121
->whereRaw("user_nicename %> '$author'")
124122
->orWhereRaw("display_name %> '$author'"),
125123
));
126124
}
127125

128126
/**
129127
* @param Builder<Plugin> $query
130-
* @param list<string> $tags
128+
* @param list<string> $tags
131129
*/
132130
public static function applyTagAny(Builder $query, array $tags): Builder
133131
{
@@ -136,21 +134,21 @@ public static function applyTagAny(Builder $query, array $tags): Builder
136134

137135
/**
138136
* @param Builder<Plugin> $query
139-
* @param list<string> $tags
137+
* @param list<string> $tags
140138
*/
141139
public static function applyTagAll(Builder $query, array $tags): Builder
142140
{
143141
return $query->whereHas(
144142
'tags',
145143
fn(Builder $q) => $q->whereIn('slug', $tags),
146144
'>=',
147-
count($tags)
145+
count($tags),
148146
);
149147
}
150148

151149
/**
152150
* @param Builder<Plugin> $query
153-
* @param list<string> $tags
151+
* @param list<string> $tags
154152
*/
155153
public static function applyTagNot(Builder $query, array $tags): Builder
156154
{
@@ -164,15 +162,22 @@ public static function applyTagNot(Builder $query, array $tags): Builder
164162
*/
165163
public static function applyBrowse(Builder $query, string $browse): Builder
166164
{
165+
if ($browse === 'featured') {
166+
$query->where(fn($q) => $q
167+
->where(fn($q) => $q->where('rating', '>=', 80)->where('num_ratings', '>', 100))
168+
->orWhere('ac_origin', '!=', 'wp_org')
169+
);
170+
}
171+
167172
return $query->reorder(self::browseToSortColumn($browse), 'desc');
168173
}
169174

170175
public static function browseToSortColumn(?string $browse): string
171176
{
172177
return match ($browse) {
173178
'new' => 'added',
174-
'updated' => 'last_updated',
175-
'top-rated', 'featured' => 'rating',
179+
'top-rated' => 'rating',
180+
'updated', 'featured' => 'last_updated',
176181
default => 'active_installs',
177182
};
178183
}

tests/Feature/Services/Plugins/QueryPluginsServiceTest.php

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -208,29 +208,6 @@
208208
expect($sql)->toContain('order by');
209209
});
210210

211-
test('browseToSortColumn returns correct column for each browse parameter', function () {
212-
expect(QueryPluginsService::browseToSortColumn('new'))
213-
->toBe('added')
214-
->and(QueryPluginsService::browseToSortColumn('updated'))->toBe('last_updated')
215-
->and(QueryPluginsService::browseToSortColumn('top-rated'))->toBe('rating')
216-
->and(QueryPluginsService::browseToSortColumn('featured'))->toBe('rating')
217-
->and(QueryPluginsService::browseToSortColumn('popular'))->toBe('active_installs')
218-
->and(QueryPluginsService::browseToSortColumn(null))->toBe('active_installs');
219-
});
220-
221-
// [chuck 2025-09-13] These are no longer used, but keeping them commented for future reference.
222-
// If they're still not used after 6 months, just delete them.
223-
//
224-
// test('normalizeSearchString handles various inputs correctly', function () {
225-
// expect(QueryPluginsService::normalizeSearchString(null))
226-
// ->toBeNull()
227-
// ->and(QueryPluginsService::normalizeSearchString(''))->toBe('')
228-
// ->and(QueryPluginsService::normalizeSearchString(' test '))->toBe('test')
229-
// ->and(QueryPluginsService::normalizeSearchString('test search'))->toBe('test search')
230-
// ->and(QueryPluginsService::normalizeSearchString('test@example.com'))->toBe('test@example.com')
231-
// ->and(QueryPluginsService::normalizeSearchString('test*search'))->toBe('test search');
232-
// });
233-
234211
test('applySearchWeighted prioritizes relevance over install count', function () {
235212
// Create plugins with different install counts and names
236213
Plugin::factory()->create([

0 commit comments

Comments
 (0)