- Add /{slug}/page/N/ rules and keep the page number through 301s
- Route only regions synced to a term, so unsaved presets never claim /europe/ etc.
- Flush rewrites on the request after activation so structure routes survive
- Suggest the existing term slug for new cities (keeps live /tour-destination/ URLs)
- Refuse saves without the editor sentinel; confirm before saving an empty structure
- Show term-sync failures to the admin instead of reporting success
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
174 lines
6.5 KiB
PHP
174 lines
6.5 KiB
PHP
<?php
|
|
/**
|
|
* VC_Structure unit tests.
|
|
*/
|
|
|
|
function vc_fixture_structure() {
|
|
return array(
|
|
array(
|
|
'name' => 'Europe',
|
|
'slug' => 'europe',
|
|
'term_id' => 0,
|
|
'cities' => array(
|
|
array( 'id' => '737', 'name' => 'Amsterdam', 'slug' => 'amsterdam' ),
|
|
array( 'id' => '479', 'name' => 'Paris', 'slug' => 'paris' ),
|
|
),
|
|
),
|
|
array(
|
|
'name' => 'Americas',
|
|
'slug' => 'americas',
|
|
'term_id' => 0,
|
|
'cities' => array(
|
|
array( 'id' => '678', 'name' => 'Boston', 'slug' => 'boston' ),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
function vc_fixture_map() {
|
|
return array( '737' => 'Amsterdam', '479' => 'Paris', '678' => 'Boston', '22' => 'Victoria' );
|
|
}
|
|
|
|
function test_default_regions() {
|
|
$regions = VC_Structure::default_regions();
|
|
vc_assert_same(
|
|
array( 'uk', 'europe', 'asia', 'middle-east-and-africa', 'americas', 'australasia' ),
|
|
array_column( $regions, 'slug' )
|
|
);
|
|
vc_assert_same( 'Middle East and Africa', $regions[3]['name'] );
|
|
vc_assert_same( array(), $regions[0]['cities'] );
|
|
vc_assert_same( 0, $regions[0]['term_id'] );
|
|
}
|
|
|
|
function test_normalize_fills_slugs() {
|
|
$s = VC_Structure::normalize(
|
|
array(
|
|
array(
|
|
'name' => ' Middle East and Africa ',
|
|
'slug' => '',
|
|
'term_id' => '7',
|
|
'cities' => array(
|
|
array( 'id' => '', 'name' => 'Ghost', 'slug' => 'ghost' ),
|
|
array( 'id' => '828', 'name' => 'Dubai', 'slug' => '' ),
|
|
),
|
|
),
|
|
)
|
|
);
|
|
vc_assert_same( 'Middle East and Africa', $s[0]['name'] );
|
|
vc_assert_same( 'middle-east-and-africa', $s[0]['slug'] );
|
|
vc_assert_same( 7, $s[0]['term_id'] );
|
|
vc_assert_same( array( array( 'id' => '828', 'name' => 'Dubai', 'slug' => 'dubai' ) ), $s[0]['cities'] );
|
|
}
|
|
|
|
function test_validate_ok() {
|
|
vc_assert_same( array(), VC_Structure::validate( vc_fixture_structure(), vc_fixture_map(), array() ) );
|
|
}
|
|
|
|
function test_validate_unknown_city() {
|
|
$s = vc_fixture_structure();
|
|
$s[1]['cities'][0]['id'] = '999';
|
|
vc_assert_contains( 'City ID 999 is not a Viator destination.', VC_Structure::validate( $s, vc_fixture_map(), array() ) );
|
|
}
|
|
|
|
function test_validate_duplicate_city() {
|
|
$s = vc_fixture_structure();
|
|
$s[1]['cities'][] = array( 'id' => '737', 'name' => 'Amsterdam', 'slug' => 'amsterdam-2' );
|
|
vc_assert_contains( 'Amsterdam is listed more than once.', VC_Structure::validate( $s, vc_fixture_map(), array() ) );
|
|
}
|
|
|
|
function test_validate_duplicate_slug() {
|
|
$s = vc_fixture_structure();
|
|
$s[1]['slug'] = 'paris';
|
|
vc_assert_contains( 'Slug "paris" is used more than once.', VC_Structure::validate( $s, vc_fixture_map(), array() ) );
|
|
}
|
|
|
|
function test_validate_bad_slug() {
|
|
$s = vc_fixture_structure();
|
|
$s[0]['cities'][0]['slug'] = 'amsterdam!';
|
|
$s[1]['cities'][0]['slug'] = 'New York';
|
|
$errors = VC_Structure::validate( $s, vc_fixture_map(), array() );
|
|
vc_assert_contains( 'Slug "amsterdam!" is invalid: use only a-z, 0-9 and -.', $errors );
|
|
vc_assert_contains( 'Slug "New York" is invalid: use only a-z, 0-9 and -.', $errors );
|
|
}
|
|
|
|
function test_validate_reserved() {
|
|
$s = vc_fixture_structure();
|
|
$s[0]['cities'][0]['slug'] = 'contact';
|
|
vc_assert_contains( 'Slug "contact" is reserved.', VC_Structure::validate( $s, vc_fixture_map(), array() ) );
|
|
}
|
|
|
|
function test_validate_taken_slug() {
|
|
$s = vc_fixture_structure();
|
|
$s[1]['cities'][] = array( 'id' => '22', 'name' => 'Victoria', 'slug' => 'victoria' );
|
|
$errors = VC_Structure::validate( $s, vc_fixture_map(), array( 'victoria' => 'destination "Victoria"' ) );
|
|
vc_assert_contains( 'Slug "victoria" is already used by destination "Victoria".', $errors );
|
|
}
|
|
|
|
function test_validate_empty_region() {
|
|
$s = vc_fixture_structure();
|
|
$s[0]['name'] = '';
|
|
vc_assert_contains( 'Region 1 has no name.', VC_Structure::validate( $s, vc_fixture_map(), array() ) );
|
|
}
|
|
|
|
function test_canonical_city_primary() {
|
|
vc_assert_same( 'paris', VC_Structure::canonical_city( vc_fixture_structure(), array( '479', '737' ), '479' ) );
|
|
}
|
|
|
|
function test_canonical_city_fallback_order() {
|
|
vc_assert_same( 'amsterdam', VC_Structure::canonical_city( vc_fixture_structure(), array( '678', '479', '737' ), '5555' ) );
|
|
}
|
|
|
|
function test_canonical_city_none() {
|
|
vc_assert_same( '', VC_Structure::canonical_city( vc_fixture_structure(), array( '5555' ), '' ) );
|
|
}
|
|
|
|
function test_primary_destination_id() {
|
|
vc_assert_same( '2', VC_Structure::primary_destination_id( array( array( 'ref' => '1' ), array( 'ref' => '2', 'primary' => true ) ) ) );
|
|
vc_assert_same( '', VC_Structure::primary_destination_id( array() ) );
|
|
}
|
|
|
|
function vc_fixture_synced() {
|
|
$s = vc_fixture_structure();
|
|
$s[0]['term_id'] = 11;
|
|
$s[1]['term_id'] = 12;
|
|
return $s;
|
|
}
|
|
|
|
function test_rewrite_rules() {
|
|
vc_assert_same(
|
|
array(
|
|
'^europe/page/([0-9]+)/?$' => 'index.php?viator_destination=europe&paged=$matches[1]',
|
|
'^europe/?$' => 'index.php?viator_destination=europe',
|
|
'^americas/page/([0-9]+)/?$' => 'index.php?viator_destination=americas&paged=$matches[1]',
|
|
'^americas/?$' => 'index.php?viator_destination=americas',
|
|
'^amsterdam/page/([0-9]+)/?$' => 'index.php?viator_destination=amsterdam&paged=$matches[1]',
|
|
'^amsterdam/?$' => 'index.php?viator_destination=amsterdam',
|
|
'^amsterdam/([^/]+)/?$' => 'index.php?viator_tour=$matches[1]',
|
|
'^paris/page/([0-9]+)/?$' => 'index.php?viator_destination=paris&paged=$matches[1]',
|
|
'^paris/?$' => 'index.php?viator_destination=paris',
|
|
'^paris/([^/]+)/?$' => 'index.php?viator_tour=$matches[1]',
|
|
'^boston/page/([0-9]+)/?$' => 'index.php?viator_destination=boston&paged=$matches[1]',
|
|
'^boston/?$' => 'index.php?viator_destination=boston',
|
|
'^boston/([^/]+)/?$' => 'index.php?viator_tour=$matches[1]',
|
|
),
|
|
VC_Structure::rewrite_rules( vc_fixture_synced() )
|
|
);
|
|
}
|
|
|
|
function test_rewrite_rules_empty_region() {
|
|
$rules = VC_Structure::rewrite_rules( array( array( 'name' => 'Europe', 'slug' => 'europe', 'term_id' => 11, 'cities' => array() ) ) );
|
|
vc_assert_same(
|
|
array(
|
|
'^europe/page/([0-9]+)/?$' => 'index.php?viator_destination=europe&paged=$matches[1]',
|
|
'^europe/?$' => 'index.php?viator_destination=europe',
|
|
),
|
|
$rules
|
|
);
|
|
}
|
|
|
|
// Before the structure is ever saved, get() returns the unsynced presets:
|
|
// they must not claim /uk/, /europe/, … over existing pages.
|
|
function test_rewrite_rules_skip_unsynced_regions() {
|
|
vc_assert_same( array(), VC_Structure::rewrite_rules( VC_Structure::default_regions() ) );
|
|
}
|