From eb84bb827446ba8830bced69622c8083700fc451 Mon Sep 17 00:00:00 2001 From: Vladimir Bryzgalov Date: Sat, 16 May 2026 20:03:04 +0500 Subject: [PATCH] feat(wpmc S4): Redirect class 301s on page_unic clone access Co-Authored-By: Claude Sonnet 4.6 --- includes/class-redirect.php | 71 ++++++++++++++++++++++++ tests/RedirectTest.php | 104 ++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 includes/class-redirect.php create mode 100644 tests/RedirectTest.php diff --git a/includes/class-redirect.php b/includes/class-redirect.php new file mode 100644 index 0000000..299eec1 --- /dev/null +++ b/includes/class-redirect.php @@ -0,0 +1,71 @@ +ID)) { + return; + } + $current_page_id = (int) $post->ID; + if (!\function_exists('get_field')) { + return; + } + $page_unic = \get_field('page_unic', 'option'); + if (!is_array($page_unic)) { + return; + } + $request_uri = $_SERVER['REQUEST_URI'] ?? '/'; + foreach ($page_unic as $row) { + if (!is_array($row)) { + continue; + } + if ((int) ($row['page_new'] ?? 0) !== $current_page_id) { + continue; + } + $town_term_id = (int) ($row['town'] ?? 0); + if (!$town_term_id) { + continue; + } + $term = \get_term_by('id', $town_term_id, 'town'); + if (!($term instanceof \WP_Term) || $term->slug === '' || $term->slug === $main) { + continue; + } + $town_slug = $term->slug; + if (preg_match('#^/' . preg_quote($town_slug, '#') . '(/|$)#', $request_uri)) { + return; + } + $orig_id = (int) ($row['page_old'] ?? 0); + if (!$orig_id) { + return; + } + $orig_permalink = \get_permalink($orig_id); + if (!is_string($orig_permalink) || $orig_permalink === '') { + return; + } + $path_only = Helpers::remove_domain_link($orig_permalink); + $redirect_to = '/' . $town_slug . $path_only; + \wp_safe_redirect($redirect_to, 301); + exit; + } + } +} diff --git a/tests/RedirectTest.php b/tests/RedirectTest.php new file mode 100644 index 0000000..2515621 --- /dev/null +++ b/tests/RedirectTest.php @@ -0,0 +1,104 @@ +never(); + \Brain\Monkey\Functions\when('is_admin')->justReturn(false); + $_SERVER['REQUEST_URI'] = '/spb/about/'; + \Brain\Monkey\Functions\when('get_terms')->justReturn([10 => 'spb']); + \Brain\Monkey\Functions\when('get_field')->alias(function ($name) { + if ($name === 'main_town_slug') return 'spb'; + return false; + }); + + Redirect::handle(); + + self::assertTrue(true); + } + + public function test_handle_skips_when_post_not_set(): void + { + \Brain\Monkey\Functions\expect('wp_safe_redirect')->never(); + \Brain\Monkey\Functions\when('is_admin')->justReturn(false); + $_SERVER['REQUEST_URI'] = '/about/'; + \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'; + return false; + }); + unset($GLOBALS['post']); + + Redirect::handle(); + + self::assertTrue(true); + } + + public function test_handle_skips_when_url_already_has_town_prefix(): void + { + \Brain\Monkey\Functions\expect('wp_safe_redirect')->never(); + \Brain\Monkey\Functions\when('is_admin')->justReturn(false); + $_SERVER['REQUEST_URI'] = '/tyumen/about/'; + \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'; + return false; + }); + $GLOBALS['post'] = (object) ['ID' => 84]; + + Redirect::handle(); + + self::assertTrue(true); + } + + public function test_handle_redirects_when_post_is_page_unic_clone_without_prefix(): void + { + \Brain\Monkey\Functions\when('is_admin')->justReturn(false); + $_SERVER['REQUEST_URI'] = '/about/'; + \Brain\Monkey\Functions\when('get_terms')->justReturn([11 => 'tyumen']); + + $term = new \WP_Term(); + $term->term_id = 11; + $term->slug = 'tyumen'; + \Brain\Monkey\Functions\when('get_term_by')->justReturn($term); + + \Brain\Monkey\Functions\when('get_field')->alias(function ($name) { + if ($name === 'main_town_slug') return 'spb'; + if ($name === 'page_unic') return [ + ['town' => 11, 'page_old' => 42, 'page_new' => 84], + ]; + return false; + }); + $GLOBALS['post'] = (object) ['ID' => 84]; + \Brain\Monkey\Functions\when('get_permalink')->justReturn('https://site.com/about/'); + + \Brain\Monkey\Functions\expect('wp_safe_redirect') + ->once() + ->with('/tyumen/about/', 301) + ->andThrow(new \RuntimeException('redirect-called')); + + try { + Redirect::handle(); + self::fail('Expected redirect to be issued'); + } catch (\RuntimeException $e) { + self::assertSame('redirect-called', $e->getMessage()); + } + } +}