diff --git a/includes/class-helpers.php b/includes/class-helpers.php index f9863cd..0fb6688 100644 --- a/includes/class-helpers.php +++ b/includes/class-helpers.php @@ -11,6 +11,11 @@ final class Helpers private static array $page_unic_cache = []; private static int $bypass_depth = 0; + private static function acf_ready(): bool + { + return \did_action('acf/init') > 0; + } + public static function reset_cache(): void { self::$current_town_memo = null; @@ -80,6 +85,9 @@ final class Helpers public static function alt_get_field(string $selector, $post_id = false, bool $format_value = true) { + if (!self::acf_ready()) { + return null; + } $post_id = \apply_filters('wpmc_alt_get_field_post_id', $post_id, $selector); if (!\function_exists('get_field')) { return null; @@ -106,6 +114,9 @@ final class Helpers public static function index_town_alt_page_id(): ?int { + if (!self::acf_ready()) { + return null; + } if (!\function_exists('get_field')) { return null; } @@ -116,6 +127,9 @@ final class Helpers public static function main_town_slug(): ?string { + if (!self::acf_ready()) { + return null; + } if (!\function_exists('get_field')) { return null; } @@ -132,6 +146,9 @@ final class Helpers if (array_key_exists($key, self::$page_unic_cache)) { return self::$page_unic_cache[$key]; } + if (!self::acf_ready()) { + return null; + } $term = self::get_term_by_slug($town_slug); if ($term === null) { return self::$page_unic_cache[$key] = null; @@ -161,6 +178,9 @@ final class Helpers if ($path === null) { $path = $_SERVER['REQUEST_URI'] ?? '/'; } + if (!self::acf_ready()) { + return true; + } if (!\function_exists('get_field')) { return true; } diff --git a/tests/HelpersTest.php b/tests/HelpersTest.php index 5506b2c..14c2d79 100644 --- a/tests/HelpersTest.php +++ b/tests/HelpersTest.php @@ -133,6 +133,7 @@ final class HelpersTest extends TestCase public function test_alt_get_field_applies_do_shortcode_to_string_values(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); // expect() must come before when('function_exists') so Brain Monkey's // FunctionStub::__construct can eval-define get_field() before the shim // fakes function_exists('get_field') === true. @@ -153,6 +154,7 @@ final class HelpersTest extends TestCase public function test_alt_get_field_returns_arrays_as_is(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); // expect() before when('function_exists') to avoid FunctionStub seeing // the shim and skipping the eval-declaration of get_field. // do_shortcode is intentionally NOT registered: if the implementation @@ -167,6 +169,7 @@ final class HelpersTest extends TestCase public function test_alt_get_field_post_id_filter_overrides_caller_id(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('title', 99, true) @@ -207,13 +210,27 @@ final class HelpersTest extends TestCase self::assertTrue(function_exists('wpmc_get_term_by_slug')); self::assertTrue(function_exists('wpmc_alt_get_field')); self::assertTrue(function_exists('wpmc_remove_domain_link')); + self::assertTrue(function_exists('wpmc_main_town_slug')); // remove_domain_link is pure (no WP function dependencies) — exercise the proxy. self::assertSame('/foo/', wpmc_remove_domain_link('https://site.com/foo/')); } + public function test_wpmc_main_town_slug_delegates_to_helpers(): void + { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); + \Brain\Monkey\Functions\expect('get_field') + ->once() + ->with('main_town_slug', 'option') + ->andReturn('spb'); + + require_once dirname(__DIR__) . '/includes/wpmc-functions.php'; + self::assertSame('spb', wpmc_main_town_slug()); + } + public function test_main_town_slug_reads_option_via_acf(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('main_town_slug', 'option') @@ -224,6 +241,7 @@ final class HelpersTest extends TestCase public function test_main_town_slug_returns_null_when_option_empty(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('main_town_slug', 'option') @@ -234,6 +252,7 @@ final class HelpersTest extends TestCase public function test_is_routable_path_returns_true_when_no_exclusions(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('page_no_rep', 'option') @@ -244,6 +263,7 @@ final class HelpersTest extends TestCase public function test_is_routable_path_returns_false_when_path_matches_exclusion(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('page_no_rep', 'option') @@ -257,6 +277,7 @@ final class HelpersTest extends TestCase public function test_is_routable_path_uses_request_uri_when_path_null(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); $_SERVER['REQUEST_URI'] = '/terms/'; \Brain\Monkey\Functions\expect('get_field') ->once() @@ -268,6 +289,7 @@ final class HelpersTest extends TestCase public function test_page_unic_swap_returns_clone_id_when_row_matches(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); $term = new \WP_Term(); $term->term_id = 11; $term->slug = 'tyumen'; @@ -285,6 +307,7 @@ final class HelpersTest extends TestCase public function test_page_unic_swap_returns_null_when_no_row_matches(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); $term = new \WP_Term(); $term->term_id = 11; $term->slug = 'tyumen'; @@ -298,6 +321,7 @@ final class HelpersTest extends TestCase public function test_page_unic_swap_caches_within_request(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); $term = new \WP_Term(); $term->term_id = 11; \Brain\Monkey\Functions\when('get_term_by')->justReturn($term); @@ -314,6 +338,7 @@ final class HelpersTest extends TestCase public function test_index_town_alt_page_id_returns_int_when_option_set(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('index_town_alt', 'option') @@ -324,6 +349,7 @@ final class HelpersTest extends TestCase public function test_index_town_alt_page_id_returns_null_when_zero(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_field') ->once() ->with('index_town_alt', 'option') @@ -334,6 +360,7 @@ final class HelpersTest extends TestCase public function test_reset_cache_clears_page_unic_cache(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); $term = new \WP_Term(); $term->term_id = 11; \Brain\Monkey\Functions\when('get_term_by')->justReturn($term); @@ -348,6 +375,48 @@ final class HelpersTest extends TestCase self::assertTrue(true); } + public function test_main_town_slug_returns_null_before_acf_init(): void + { + \Brain\Monkey\Functions\expect('did_action') + ->with('acf/init') + ->andReturn(0); + // get_field should NOT be called — no expectation means Brain Monkey throws if it is. + + self::assertNull(Helpers::main_town_slug()); + } + + public function test_main_town_slug_calls_get_field_after_acf_init(): void + { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); + \Brain\Monkey\Functions\expect('get_field') + ->once() + ->with('main_town_slug', 'option') + ->andReturn('spb'); + + self::assertSame('spb', Helpers::main_town_slug()); + } + + public function test_is_routable_path_returns_true_before_acf_init(): void + { + \Brain\Monkey\Functions\expect('did_action') + ->with('acf/init') + ->andReturn(0); + // get_field should NOT be called. + + self::assertTrue(Helpers::is_routable_path('/some/path/')); + } + + public function test_is_routable_path_checks_exclusions_after_acf_init(): void + { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); + \Brain\Monkey\Functions\expect('get_field') + ->once() + ->with('page_no_rep', 'option') + ->andReturn([['link' => '/excluded/']]); + + self::assertFalse(Helpers::is_routable_path('/excluded/page/')); + } + public function test_is_bypassed_returns_false_by_default(): void { self::assertFalse(Helpers::is_bypassed()); diff --git a/tests/LinkFilterTest.php b/tests/LinkFilterTest.php index e330954..1ca4702 100644 --- a/tests/LinkFilterTest.php +++ b/tests/LinkFilterTest.php @@ -44,6 +44,7 @@ final class LinkFilterTest extends TestCase { $_SERVER['REQUEST_URI'] = '/' . $town_slug . '/'; $_SERVER['HTTP_HOST'] = $host; + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => $town_slug]); \Brain\Monkey\Functions\when('get_field')->alias(function ($name) use ($main) { if ($name === 'main_town_slug') return $main; @@ -62,6 +63,7 @@ final class LinkFilterTest extends TestCase { $_SERVER['REQUEST_URI'] = '/random/'; $_SERVER['HTTP_HOST'] = 'site.com'; + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('get_terms')->justReturn([10 => 'spb']); \Brain\Monkey\Functions\when('get_field')->justReturn(false); @@ -129,6 +131,7 @@ final class LinkFilterTest extends TestCase { $_SERVER['REQUEST_URI'] = '/tyumen/'; $_SERVER['HTTP_HOST'] = 'site.com'; + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); \Brain\Monkey\Functions\when('get_field')->alias(function ($name) { if ($name === 'main_town_slug') return 'spb'; diff --git a/tests/RedirectTest.php b/tests/RedirectTest.php index 2515621..105d1c6 100644 --- a/tests/RedirectTest.php +++ b/tests/RedirectTest.php @@ -20,6 +20,7 @@ final class RedirectTest extends TestCase public function test_handle_skips_when_current_town_equals_main(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('wp_safe_redirect')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/spb/about/'; @@ -36,6 +37,7 @@ final class RedirectTest extends TestCase public function test_handle_skips_when_post_not_set(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('wp_safe_redirect')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/about/'; @@ -53,6 +55,7 @@ final class RedirectTest extends TestCase public function test_handle_skips_when_url_already_has_town_prefix(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('wp_safe_redirect')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/about/'; @@ -70,6 +73,7 @@ final class RedirectTest extends TestCase public function test_handle_redirects_when_post_is_page_unic_clone_without_prefix(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/about/'; \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); diff --git a/tests/RouterTest.php b/tests/RouterTest.php index d590423..e31f474 100644 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -48,6 +48,7 @@ final class RouterTest extends TestCase public function test_route_skips_when_current_town_is_null(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('url_to_postid')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/something-not-a-city/'; @@ -61,6 +62,7 @@ final class RouterTest extends TestCase public function test_route_skips_when_current_town_equals_main_town(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('url_to_postid')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/spb/'; @@ -77,6 +79,7 @@ final class RouterTest extends TestCase public function test_route_skips_when_path_not_routable(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('url_to_postid')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/privacy/'; @@ -94,6 +97,7 @@ final class RouterTest extends TestCase public function test_route_uses_main_page_alt_term_meta_for_root_url(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/'; \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); @@ -123,6 +127,7 @@ final class RouterTest extends TestCase public function test_route_falls_back_to_index_town_alt_option(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/'; \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); @@ -148,6 +153,7 @@ final class RouterTest extends TestCase public function test_route_does_not_install_query_when_neither_main_nor_fallback_set(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_post')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/'; @@ -169,6 +175,7 @@ final class RouterTest extends TestCase public function test_route_resolves_internal_page_via_url_to_postid(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/about/'; \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); @@ -193,6 +200,7 @@ final class RouterTest extends TestCase public function test_route_applies_page_unic_swap_when_clone_exists(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/about/'; \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); @@ -220,6 +228,7 @@ final class RouterTest extends TestCase public function test_route_does_not_install_query_when_url_to_postid_returns_zero(): void { + \Brain\Monkey\Functions\stubs(['did_action' => 1]); \Brain\Monkey\Functions\expect('get_post')->never(); \Brain\Monkey\Functions\when('is_admin')->justReturn(false); $_SERVER['REQUEST_URI'] = '/tyumen/unknown/';