*/ function vyatka_shop_known_hosts(): array { $hosts = array(); foreach ( array( 'home', 'siteurl' ) as $option_name ) { $host = wp_parse_url( (string) get_option( $option_name ), PHP_URL_HOST ); if ( is_string( $host ) && '' !== $host ) { $hosts[] = strtolower( $host ); } } // Sites behind a proxy answer to a name the stored options do not know. // Declare those in wp-config.php: // define( 'VYATKA_SHOP_HOSTS', 'shop.example.com, www.example.com' ); if ( defined( 'VYATKA_SHOP_HOSTS' ) ) { foreach ( explode( ',', (string) VYATKA_SHOP_HOSTS ) as $host ) { $host = strtolower( trim( $host ) ); if ( '' !== $host ) { $hosts[] = $host; } } } /** * Additional hosts the site is served under. * * @param array $hosts Known hostnames. */ return array_values( array_unique( (array) apply_filters( 'vyatka_shop_known_hosts', $hosts ) ) ); } /** * @param string $host Hostname to test. */ function vyatka_shop_host_is_known( string $host ): bool { return in_array( strtolower( $host ), vyatka_shop_known_hosts(), true ); } /** * Strip the origin from internal links in the finished HTML. * * Rewriting only the rendered document leaves redirects, REST responses and * WP-CLI output fully qualified, while the markup a browser receives stays * usable under whichever host served it. * * @param string $html Completed response body. * @return string */ function vyatka_shop_relative_frontend_urls( string $html ): string { foreach ( headers_list() as $header ) { if ( 0 === stripos( $header, 'Content-Type:' ) && false === stripos( $header, 'text/html' ) ) { return $html; } } $hosts = vyatka_shop_known_hosts(); $request_host = vyatka_shop_request_host(); if ( '' !== $request_host ) { $hosts[] = $request_host; } $absolute_bases = array(); foreach ( array_unique( $hosts ) as $host ) { $absolute_bases[] = 'https://' . $host; $absolute_bases[] = 'http://' . $host; $absolute_bases[] = '//' . $host; } // Longest first, so "//host" never truncates "https://host". usort( $absolute_bases, static fn( string $left, string $right ): int => strlen( $right ) <=> strlen( $left ) ); return str_replace( $absolute_bases, '', $html ); } /** * Buffer ordinary frontend documents so their internal links can be made * relative without changing the site's canonical configuration. */ function vyatka_shop_start_relative_url_buffer(): void { if ( is_admin() || wp_doing_ajax() || wp_is_json_request() || is_feed() ) { return; } ob_start( 'vyatka_shop_relative_frontend_urls' ); } add_action( 'template_redirect', 'vyatka_shop_start_relative_url_buffer', 0 ); /** * Recover stale filtered category URLs when the selected page no longer exists. * * Filter forms always target page one, but bookmarked or cached /page/N/ URLs * can still reach WordPress directly and become a 404 after the result set is * narrowed. Preserve their query string and retry the category from page one. */ function vyatka_shop_redirect_stale_filtered_category_page(): void { if ( ! is_404() || empty( $_GET ) ) { return; } $filter_keys = array( 'filter_min_price', 'filter_max_price', 'feature', 'collection', 'per_page', 'orderby', ); if ( ! array_intersect( $filter_keys, array_keys( $_GET ) ) ) { return; } $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : ''; $request_path = wp_parse_url( $request_uri, PHP_URL_PATH ); if ( ! is_string( $request_path ) || ! preg_match( '#^(.*/product-category/[^/]+)/page/[1-9][0-9]*/?$#u', $request_path, $matches ) ) { return; } $target = add_query_arg( wp_unslash( $_GET ), trailingslashit( $matches[1] ) ); wp_safe_redirect( $target, 302, 'Vyatka Shop' ); exit; } add_action( 'template_redirect', 'vyatka_shop_redirect_stale_filtered_category_page', -10 );