feat(wpmc S4): Redirect class 301s on page_unic clone access
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WPMultiCity;
|
||||
|
||||
final class Redirect
|
||||
{
|
||||
public static function register(): void
|
||||
{
|
||||
\add_action('wp', [self::class, 'handle'], 9998);
|
||||
}
|
||||
|
||||
public static function handle(): void
|
||||
{
|
||||
if (\is_admin()) {
|
||||
return;
|
||||
}
|
||||
if (\defined('DOING_AJAX') && \DOING_AJAX) {
|
||||
return;
|
||||
}
|
||||
$main = Helpers::main_town_slug();
|
||||
if ($main === null) {
|
||||
return;
|
||||
}
|
||||
global $post;
|
||||
if (!isset($post->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WPMultiCity\Tests;
|
||||
|
||||
use WPMultiCity\Redirect;
|
||||
|
||||
final class RedirectTest extends TestCase
|
||||
{
|
||||
public function test_register_attaches_wp_action_at_priority_9998(): void
|
||||
{
|
||||
Redirect::register();
|
||||
|
||||
self::assertSame(
|
||||
9998,
|
||||
has_action('wp', [Redirect::class, 'handle']),
|
||||
'Redirect::register() must hook wp action at priority 9998'
|
||||
);
|
||||
}
|
||||
|
||||
public function test_handle_skips_when_current_town_equals_main(): void
|
||||
{
|
||||
\Brain\Monkey\Functions\expect('wp_safe_redirect')->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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user