Skip to content

Commit 7f89984

Browse files
committed
feat(acf): target PFCPT pages via page_type location filters
Extend ACF's built-in page_type location rule with <cpt>_page values using the documented acf/location/rule_values/type=page_type and acf/location/match_rule/type=page_type filters, instead of removing and re-registering ACF's native location type. This augments core behavior without mutating ACF's location store or subclassing internal ACF classes, so it stays compatible across ACF updates. Api is injected via the container and the integration is wired into Plugin::getIntegrations() so it bootstraps with the others. Removes the LocationPageType subclass. Adds integration tests for both filters plus PluginTest/ContainerTest coverage, registers ACF in the test bootstrap, and adds a test:advanced-custom-fields composer script.
1 parent 8691c2b commit 7f89984

6 files changed

Lines changed: 183 additions & 132 deletions

File tree

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@
9191
"@test:wordpress-seo",
9292
"@test:polylang",
9393
"@test:wpml",
94-
"@test:autodescription"
94+
"@test:autodescription",
95+
"@test:advanced-custom-fields"
9596
],
97+
"test:advanced-custom-fields": "PLUGINS=advanced-custom-fields phpunit --testsuite=unit,integration,plugin-integration",
9698
"test:autodescription": "PLUGINS=autodescription phpunit --testsuite=unit,integration,plugin-integration",
9799
"test:core": "phpunit --testsuite=unit,integration",
98100
"test:coverage": "php -d pcov.enabled=1 phpunit --testsuite=unit,integration --coverage-text",

src/Container.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ public function __construct()
142142
),
143143

144144
// Integration composites
145-
AdvancedCustomFields\AdvancedCustomFields::class => static fn (): AdvancedCustomFields\AdvancedCustomFields => new AdvancedCustomFields\AdvancedCustomFields(),
145+
AdvancedCustomFields\AdvancedCustomFields::class => fn (): AdvancedCustomFields\AdvancedCustomFields => new AdvancedCustomFields\AdvancedCustomFields(
146+
$this->get(Api::class)
147+
),
146148
Polylang\Polylang::class => fn (): Polylang\Polylang => new Polylang\Polylang(
147149
$this->get(Polylang\UrlTranslation::class),
148150
$this->get(Polylang\Translation::class),

src/Integration/AdvancedCustomFields/AdvancedCustomFields.php

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,86 @@
44

55
namespace n5s\PageForCustomPostType\Integration\AdvancedCustomFields;
66

7+
use n5s\PageForCustomPostType\Core\Api;
78
use n5s\PageForCustomPostType\Integration\IntegrationInterface;
89

910
/**
10-
* Advanced Custom Fields integration composite.
11+
* Advanced Custom Fields integration.
1112
*
12-
* Registers a custom location type that exposes `<cpt>_page` values on the
13-
* `page_type` rule, so field groups can target PFCPT-bound pages.
13+
* Extends the built-in `page_type` location rule with `<cpt>_page` values so
14+
* field groups can target PFCPT-bound pages.
1415
*/
1516
final class AdvancedCustomFields implements IntegrationInterface
1617
{
18+
public function __construct(
19+
private readonly Api $api
20+
) {
21+
}
22+
1723
public function isSupported(): bool
1824
{
19-
return \function_exists('acf_register_location_type');
25+
return \function_exists('acf_get_location_type');
2026
}
2127

2228
public function registerHooks(): void
2329
{
24-
add_action('acf/include_location_rules', [$this, 'registerLocationRules']);
30+
add_filter('acf/location/rule_values/type=page_type', [$this, 'addPageTypeValues'], 10, 2);
31+
add_filter('acf/location/match_rule/type=page_type', [$this, 'matchPageType'], 10, 4);
2532
}
2633

27-
public function registerLocationRules(int $acfFieldApiVersion): void
34+
/**
35+
* Add `<cpt>_page` options to the Page Type rule values dropdown.
36+
*
37+
* @param array<string, string> $values
38+
* @param array<string, mixed> $rule
39+
* @return array<string, string>
40+
*/
41+
public function addPageTypeValues(array $values, array $rule): array
2842
{
29-
if ($acfFieldApiVersion !== 5) {
30-
return;
43+
foreach (array_keys($this->api->getPageIds()) as $postType) {
44+
$postTypeObject = get_post_type_object($postType);
45+
46+
if ($postTypeObject && \is_string($postTypeObject->labels->archives)) {
47+
$values[$postType . '_page'] = $postTypeObject->labels->archives;
48+
}
49+
}
50+
51+
return $values;
52+
}
53+
54+
/**
55+
* Match a `page_type == <cpt>_page` rule against the current screen.
56+
*
57+
* @param array<string, mixed> $rule
58+
* @param array<string, mixed> $screen
59+
* @param array<string, mixed> $fieldGroup
60+
*/
61+
public function matchPageType(bool $match, array $rule, array $screen, array $fieldGroup): bool
62+
{
63+
if ($match) {
64+
return true;
65+
}
66+
67+
if (!isset($screen['post_id'])) {
68+
return false;
69+
}
70+
71+
$post = get_post($screen['post_id']);
72+
73+
if (!$post instanceof \WP_Post) {
74+
return false;
75+
}
76+
77+
foreach ($this->api->getPageIds() as $postType => $pageId) {
78+
if ($rule['value'] !== $postType . '_page') {
79+
continue;
80+
}
81+
82+
$result = ($pageId === $post->ID);
83+
84+
return ($rule['operator'] === '!=') ? !$result : $result;
3185
}
3286

33-
$store = acf_get_store('location-types');
34-
$store->remove('page_type');
35-
acf_register_location_type(LocationPageType::class);
87+
return false;
3688
}
3789
}

src/Integration/AdvancedCustomFields/LocationPageType.php

Lines changed: 0 additions & 119 deletions
This file was deleted.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace n5s\PageForCustomPostType\Tests\Integration\Integration;
6+
7+
use n5s\PageForCustomPostType\Tests\Fixtures\TestCase;
8+
use PHPUnit\Framework\Attributes\RequiresFunction;
9+
10+
/**
11+
* Integration tests for the Advanced Custom Fields integration.
12+
*
13+
* Exercises the `acf/location/rule_values/type=page_type` and
14+
* `acf/location/match_rule/type=page_type` filters that expose
15+
* `<cpt>_page` values on the Page Type location rule.
16+
*/
17+
#[RequiresFunction('acf_get_location_type')]
18+
class AdvancedCustomFieldsTest extends TestCase
19+
{
20+
private const RULE_TYPE = 'page_type';
21+
22+
protected function setUp(): void
23+
{
24+
if (!\function_exists('acf_get_location_type')) {
25+
$this->markTestSkipped('Advanced Custom Fields is not installed.');
26+
}
27+
28+
parent::setUp();
29+
$this->createFixtures();
30+
$this->configureStaticFrontPage();
31+
}
32+
33+
public function testPageTypeValuesIncludeCustomPostTypePages(): void
34+
{
35+
$values = $this->applyValuesFilter();
36+
37+
$this->assertArrayHasKey('book_page', $values);
38+
$this->assertArrayHasKey('bike_page', $values);
39+
}
40+
41+
public function testPageTypeValuesPreserveCoreOptions(): void
42+
{
43+
$values = $this->applyValuesFilter();
44+
45+
foreach (['front_page', 'posts_page', 'top_level', 'parent', 'child'] as $key) {
46+
$this->assertArrayHasKey($key, $values);
47+
}
48+
}
49+
50+
public function testMatchRuleReturnsTrueForBoundPage(): void
51+
{
52+
$matched = $this->applyMatchFilter('==', 'book_page', $this->homeForBookId);
53+
54+
$this->assertTrue($matched);
55+
}
56+
57+
public function testMatchRuleReturnsFalseForUnrelatedPage(): void
58+
{
59+
$matched = $this->applyMatchFilter('==', 'book_page', $this->staticFrontPageId);
60+
61+
$this->assertFalse($matched);
62+
}
63+
64+
public function testMatchRuleInvertsForNotEqualsOperator(): void
65+
{
66+
$matched = $this->applyMatchFilter('!=', 'book_page', $this->homeForBookId);
67+
68+
$this->assertFalse($matched);
69+
}
70+
71+
public function testMatchRuleShortCircuitsWhenCoreAlreadyMatched(): void
72+
{
73+
$matched = acf_match_location_rule(
74+
['param' => self::RULE_TYPE, 'operator' => '==', 'value' => 'front_page'],
75+
['post_id' => $this->staticFrontPageId],
76+
[]
77+
);
78+
79+
$this->assertTrue($matched);
80+
}
81+
82+
public function testMatchRuleReturnsFalseWhenPostIdMissing(): void
83+
{
84+
$matched = acf_match_location_rule(
85+
['param' => self::RULE_TYPE, 'operator' => '==', 'value' => 'book_page'],
86+
[],
87+
[]
88+
);
89+
90+
$this->assertFalse($matched);
91+
}
92+
93+
/**
94+
* @return array<string, string>
95+
*/
96+
private function applyValuesFilter(): array
97+
{
98+
return acf_get_location_rule_values([
99+
'param' => self::RULE_TYPE,
100+
'operator' => '==',
101+
'value' => '',
102+
]);
103+
}
104+
105+
private function applyMatchFilter(string $operator, string $value, int $postId): bool
106+
{
107+
return acf_match_location_rule(
108+
['param' => self::RULE_TYPE, 'operator' => $operator, 'value' => $value],
109+
['post_id' => $postId],
110+
[]
111+
);
112+
}
113+
}

tests/bootstrap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
'wordpress-seo' => 'wordpress-seo/wp-seo.php',
2121
'polylang' => 'polylang/polylang.php',
2222
'autodescription' => 'autodescription/autodescription.php',
23+
'advanced-custom-fields' => 'advanced-custom-fields/acf.php',
2324
];
2425
$requestedPlugins = array_filter(explode(',', getenv('PLUGINS') ?: ''));
2526
$plugins = array_values(array_filter(array_map(static function (string $p) use ($availablePlugins): ?string {

0 commit comments

Comments
 (0)