Skip to content

Commit e1ca095

Browse files
Fix Polylang filtering of uploaded custom font attachments (#1884)
* feat(polylang): move font attachment query handling to integration Agent-Logs-Url: https://github.com/helsingborg-stad/Municipio/sessions/26b2264a-26a1-4a7d-91fa-b5aceaa535e8 Co-authored-by: sebastianthulin <797129+sebastianthulin@users.noreply.github.com> * test(polylang): fix font attachment query test setup Agent-Logs-Url: https://github.com/helsingborg-stad/Municipio/sessions/26b2264a-26a1-4a7d-91fa-b5aceaa535e8 Co-authored-by: sebastianthulin <797129+sebastianthulin@users.noreply.github.com> * test(polylang): assert unchanged query vars correctly Agent-Logs-Url: https://github.com/helsingborg-stad/Municipio/sessions/26b2264a-26a1-4a7d-91fa-b5aceaa535e8 Co-authored-by: sebastianthulin <797129+sebastianthulin@users.noreply.github.com> * fix(polylang): avoid suppressing filters for font queries Agent-Logs-Url: https://github.com/helsingborg-stad/Municipio/sessions/596c6b63-d545-41bd-9fd1-5cf348dc39ee Co-authored-by: sebastianthulin <797129+sebastianthulin@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sebastianthulin <797129+sebastianthulin@users.noreply.github.com>
1 parent 4dc372d commit e1ca095

File tree

4 files changed

+277
-24
lines changed

4 files changed

+277
-24
lines changed

library/App.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,11 @@ public function __construct(
227227
$resolvePageTreeMenuPageIds = new \Municipio\Integrations\Polylang\ResolvePageTreeMenuPageIds($this->wpService);
228228
$resolveNavigationCacheKey = new \Municipio\Integrations\Polylang\ResolveNavigationCacheKey($this->wpService);
229229
$resolvePdfNotFoundUrl = new \Municipio\Integrations\Polylang\ResolvePdfNotFoundUrl($this->wpService);
230+
$resolveFontAttachmentQueries = new \Municipio\Integrations\Polylang\ResolveFontAttachmentQueries($this->wpService);
230231
$this->hooksRegistrar->register($resolvePageTreeMenuPageIds);
231232
$this->hooksRegistrar->register($resolveNavigationCacheKey);
232233
$this->hooksRegistrar->register($resolvePdfNotFoundUrl);
234+
$this->hooksRegistrar->register($resolveFontAttachmentQueries);
233235

234236
/* Admin uploads */
235237
$uploads = new \Municipio\Admin\Uploads();

library/Content/PostFilters.php

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ class PostFilters
1414
*/
1515
public function __construct()
1616
{
17-
add_action('pre_get_posts', array($this, 'suppressFiltersOnFontAttachments'));
18-
1917
add_action('parse_query', array($this, 'handleQuery'));
2018

2119
remove_filter('content_save_pre', 'wp_filter_post_kses');
@@ -35,26 +33,4 @@ public function handleQuery($query)
3533
}
3634
}
3735

38-
/**
39-
* Suppress filters on font attachments
40-
*/
41-
public function suppressFiltersOnFontAttachments($query)
42-
{
43-
/**
44-
* Suppress filters for font attachments in queries
45-
*
46-
* @param WP_Query $query
47-
* @return void
48-
*/
49-
if (
50-
$query->get('post_type') == 'attachment' && is_array($query->get('post_mime_type')) &&
51-
!empty(array_filter($query->get('post_mime_type'), function ($item) {
52-
return strpos($item, 'font') !== false;
53-
}))
54-
) {
55-
$query->set('suppress_filters', true);
56-
}
57-
58-
return $query;
59-
}
6036
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Municipio\Integrations\Polylang;
6+
7+
use Closure;
8+
use Municipio\HooksRegistrar\Hookable;
9+
use WP_Query;
10+
use WpService\Contracts\AddAction;
11+
12+
/**
13+
* Makes font attachment queries language agnostic when Polylang is active.
14+
*/
15+
class ResolveFontAttachmentQueries implements Hookable
16+
{
17+
/**
18+
* Constructor.
19+
*
20+
* @param AddAction $wpService The WordPress service.
21+
* @param ?Closure $polylangIsActiveResolver Optional Polylang availability resolver.
22+
*/
23+
public function __construct(
24+
private AddAction $wpService,
25+
private ?Closure $polylangIsActiveResolver = null
26+
) {
27+
}
28+
29+
/**
30+
* @inheritDoc
31+
*/
32+
public function addHooks(): void
33+
{
34+
$this->wpService->addAction('pre_get_posts', [$this, 'makeFontAttachmentQueryLanguageAgnostic'], 1);
35+
}
36+
37+
/**
38+
* Make font attachment queries language agnostic.
39+
*
40+
* @param WP_Query $query The query to inspect.
41+
*
42+
* @return void
43+
*/
44+
public function makeFontAttachmentQueryLanguageAgnostic(WP_Query $query): void
45+
{
46+
if (!$this->isPolylangActive() || !$this->isFontAttachmentQuery($query)) {
47+
return;
48+
}
49+
50+
$query->set('lang', '');
51+
}
52+
53+
/**
54+
* Determine whether the query targets font attachments.
55+
*
56+
* @param WP_Query $query The query to inspect.
57+
*
58+
* @return bool True when the query targets font attachments, otherwise false.
59+
*/
60+
private function isFontAttachmentQuery(WP_Query $query): bool
61+
{
62+
if ($query->get('post_type') !== 'attachment') {
63+
return false;
64+
}
65+
66+
$postMimeType = $query->get('post_mime_type');
67+
68+
if (is_string($postMimeType)) {
69+
return str_contains($postMimeType, 'font');
70+
}
71+
72+
if (!is_array($postMimeType)) {
73+
return false;
74+
}
75+
76+
foreach ($postMimeType as $mimeType) {
77+
if (is_string($mimeType) && str_contains($mimeType, 'font')) {
78+
return true;
79+
}
80+
}
81+
82+
return false;
83+
}
84+
85+
/**
86+
* Determine whether Polylang is active.
87+
*
88+
* @return bool True when Polylang is active, otherwise false.
89+
*/
90+
private function isPolylangActive(): bool
91+
{
92+
return $this->getPolylangIsActiveResolver()?->__invoke() ?? false;
93+
}
94+
95+
/**
96+
* Get the Polylang availability resolver.
97+
*
98+
* @return ?Closure The Polylang availability resolver.
99+
*/
100+
private function getPolylangIsActiveResolver(): ?Closure
101+
{
102+
if ($this->polylangIsActiveResolver instanceof Closure) {
103+
return $this->polylangIsActiveResolver;
104+
}
105+
106+
if (!is_callable('pll_current_language')) {
107+
return null;
108+
}
109+
110+
return static fn (): bool => true;
111+
}
112+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Municipio\Integrations\Polylang;
6+
7+
use Closure;
8+
use PHPUnit\Framework\Attributes\TestDox;
9+
use PHPUnit\Framework\TestCase;
10+
use WP_Query;
11+
use WpService\Implementations\FakeWpService;
12+
13+
class ResolveFontAttachmentQueriesTest extends TestCase
14+
{
15+
#[TestDox('class can be instantiated')]
16+
public function testCanBeInstantiated(): void
17+
{
18+
static::assertInstanceOf(ResolveFontAttachmentQueries::class, $this->getSut());
19+
}
20+
21+
#[TestDox('addHooks() registers the pre_get_posts action')]
22+
public function testAddHooksRegistersPreGetPostsAction(): void
23+
{
24+
$wpService = new FakeWpService([
25+
'addAction' => true,
26+
]);
27+
28+
$sut = new ResolveFontAttachmentQueries($wpService);
29+
30+
$sut->addHooks();
31+
32+
static::assertSame('pre_get_posts', $wpService->methodCalls['addAction'][0][0]);
33+
static::assertSame(1, $wpService->methodCalls['addAction'][0][2]);
34+
}
35+
36+
#[TestDox('makeFontAttachmentQueryLanguageAgnostic() updates font attachment queries with array mime types')]
37+
public function testMakeFontAttachmentQueryLanguageAgnosticUpdatesArrayMimeTypeQuery(): void
38+
{
39+
$query = $this->createQuery();
40+
$query->set('post_type', 'attachment');
41+
$query->set('post_mime_type', ['application/font-woff', 'font/woff2']);
42+
43+
$sut = $this->getSut(
44+
polylangIsActiveResolver: static fn (): bool => true
45+
);
46+
47+
$sut->makeFontAttachmentQueryLanguageAgnostic($query);
48+
49+
static::assertSame('', $query->get('lang'));
50+
static::assertArrayNotHasKey('suppress_filters', $query->query_vars);
51+
}
52+
53+
#[TestDox('makeFontAttachmentQueryLanguageAgnostic() updates font attachment queries with string mime types')]
54+
public function testMakeFontAttachmentQueryLanguageAgnosticUpdatesStringMimeTypeQuery(): void
55+
{
56+
$query = $this->createQuery();
57+
$query->set('post_type', 'attachment');
58+
$query->set('post_mime_type', 'application/font-woff');
59+
60+
$sut = $this->getSut(
61+
polylangIsActiveResolver: static fn (): bool => true
62+
);
63+
64+
$sut->makeFontAttachmentQueryLanguageAgnostic($query);
65+
66+
static::assertSame('', $query->get('lang'));
67+
static::assertArrayNotHasKey('suppress_filters', $query->query_vars);
68+
}
69+
70+
#[TestDox('makeFontAttachmentQueryLanguageAgnostic() does not update non-font attachment queries')]
71+
public function testMakeFontAttachmentQueryLanguageAgnosticDoesNotUpdateNonFontQueries(): void
72+
{
73+
$query = $this->createQuery();
74+
$query->set('post_type', 'attachment');
75+
$query->set('post_mime_type', 'image/jpeg');
76+
77+
$sut = $this->getSut(
78+
polylangIsActiveResolver: static fn (): bool => true
79+
);
80+
81+
$sut->makeFontAttachmentQueryLanguageAgnostic($query);
82+
83+
static::assertArrayNotHasKey('lang', $query->query_vars);
84+
static::assertArrayNotHasKey('suppress_filters', $query->query_vars);
85+
}
86+
87+
#[TestDox('makeFontAttachmentQueryLanguageAgnostic() does not update queries when Polylang is unavailable')]
88+
public function testMakeFontAttachmentQueryLanguageAgnosticDoesNotUpdateQueriesWhenPolylangIsUnavailable(): void
89+
{
90+
$query = $this->createQuery();
91+
$query->set('post_type', 'attachment');
92+
$query->set('post_mime_type', 'application/font-woff');
93+
94+
$sut = $this->getSut(
95+
polylangIsActiveResolver: static fn (): bool => false
96+
);
97+
98+
$sut->makeFontAttachmentQueryLanguageAgnostic($query);
99+
100+
static::assertArrayNotHasKey('lang', $query->query_vars);
101+
static::assertArrayNotHasKey('suppress_filters', $query->query_vars);
102+
}
103+
104+
/**
105+
* Get the system under test.
106+
*
107+
* @param ?Closure $polylangIsActiveResolver Optional Polylang availability resolver.
108+
*
109+
* @return ResolveFontAttachmentQueries The system under test.
110+
*/
111+
private function getSut(?Closure $polylangIsActiveResolver = null): ResolveFontAttachmentQueries
112+
{
113+
return new ResolveFontAttachmentQueries(
114+
new FakeWpService([
115+
'addAction' => true,
116+
]),
117+
$polylangIsActiveResolver
118+
);
119+
}
120+
121+
/**
122+
* Create a query double with working get/set methods.
123+
*
124+
* @return WP_Query The query double.
125+
*/
126+
private function createQuery(): WP_Query
127+
{
128+
return new class extends WP_Query {
129+
/**
130+
* Query vars storage.
131+
*
132+
* @var array<string, mixed>
133+
*/
134+
public $query_vars = [];
135+
136+
/**
137+
* Set a query var.
138+
*
139+
* @param string $queryVar The query var name.
140+
* @param mixed $value The query var value.
141+
*
142+
* @return void
143+
*/
144+
public function set($queryVar, $value = ''): void
145+
{
146+
$this->query_vars[$queryVar] = $value;
147+
}
148+
149+
/**
150+
* Get a query var.
151+
*
152+
* @param string $queryVar The query var name.
153+
* @param mixed $defaultValue The default value.
154+
*
155+
* @return mixed The query var value.
156+
*/
157+
public function get($queryVar, $defaultValue = '')
158+
{
159+
return $this->query_vars[$queryVar] ?? $defaultValue;
160+
}
161+
};
162+
}
163+
}

0 commit comments

Comments
 (0)