$query ) { add_rewrite_rule( $regex, $query, 'top' ); } if ( get_option( 'vc_flush_rewrite' ) ) { delete_option( 'vc_flush_rewrite' ); flush_rewrite_rules( false ); } } public static function is_configured_term( $term ) { if ( ! $term instanceof WP_Term || 'viator_destination' !== $term->taxonomy ) { return false; } if ( get_term_meta( $term->term_id, '_vc_region', true ) ) { return true; } $viator_id = (string) get_term_meta( $term->term_id, '_vc_viator_destination_id', true ); if ( '' === $viator_id ) { return false; } $cities = VC_Structure::cities( VC_Structure::get() ); return isset( $cities[ $viator_id ] ); } /** * Slug of the city a tour's URL lives under, or '' (it stays at /tours/). */ public static function product_city( $post_id ) { $post_id = (int) $post_id; if ( isset( self::$product_city[ $post_id ] ) ) { return self::$product_city[ $post_id ]; } $dest_ids = array(); $destinations = json_decode( (string) get_post_meta( $post_id, '_vc_destinations', true ), true ); foreach ( is_array( $destinations ) ? $destinations : array() as $destination ) { $ref = is_array( $destination ) ? ( $destination['ref'] ?? ( $destination['destinationId'] ?? '' ) ) : $destination; if ( '' !== (string) $ref ) { $dest_ids[] = (string) $ref; } } $primary = (string) get_post_meta( $post_id, '_vc_primary_destination', true ); self::$product_city[ $post_id ] = VC_Structure::canonical_city( VC_Structure::get(), $dest_ids, $primary ); return self::$product_city[ $post_id ]; } public static function term_link( $url, $term, $taxonomy ) { if ( 'viator_destination' === $taxonomy && self::is_configured_term( $term ) ) { return home_url( '/' . $term->slug . '/' ); } return $url; } public static function post_type_link( $url, $post ) { if ( 'viator_tour' !== $post->post_type || '' === $post->post_name ) { return $url; } $city = self::product_city( $post->ID ); if ( '' === $city ) { return $url; } return home_url( '/' . $city . '/' . $post->post_name . '/' ); } public static function redirect() { if ( is_preview() ) { return; } $canonical = ''; if ( is_singular( 'viator_tour' ) ) { $post = get_queried_object(); if ( $post && 'publish' === $post->post_status ) { $canonical = get_permalink( $post ); } } elseif ( is_tax( 'viator_destination' ) ) { $term = get_queried_object(); if ( self::is_configured_term( $term ) ) { $canonical = get_term_link( $term ); // Keep the page: /tour-destination/x/page/2/ and /x/?paged=2 // both land on /x/page/2/ (the form core's redirect_canonical // would produce anyway). $paged = (int) get_query_var( 'paged' ); if ( $paged > 1 && ! is_wp_error( $canonical ) ) { $canonical = trailingslashit( $canonical ) . 'page/' . $paged . '/'; } } } if ( ! $canonical || is_wp_error( $canonical ) ) { return; } $request = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $parts = explode( '?', $request, 2 ); $current = untrailingslashit( rawurldecode( $parts[0] ) ); $target = untrailingslashit( rawurldecode( (string) wp_parse_url( $canonical, PHP_URL_PATH ) ) ); if ( $current === $target ) { return; } if ( isset( $parts[1] ) && '' !== $parts[1] ) { $canonical .= '?' . $parts[1]; $canonical = remove_query_arg( 'paged', $canonical ); } wp_safe_redirect( $canonical, 301 ); exit; } /** * Core prints rel=canonical for single tours only; add it for region and * city archives unless an SEO plugin already handles canonicals. */ public static function term_canonical() { if ( defined( 'WPSEO_VERSION' ) || defined( 'RANK_MATH_VERSION' ) || ! is_tax( 'viator_destination' ) ) { return; } $term = get_queried_object(); if ( ! self::is_configured_term( $term ) ) { return; } $link = get_term_link( $term ); if ( ! is_wp_error( $link ) ) { echo '' . "\n"; } } }