normalizeUrl( $source_url ); $destination_url = $this->normalizeUrl( $destination_url ); if ( '' === $source_url || '' === $destination_url ) { throw new \InvalidArgumentException( 'Source and destination URLs are required.' ); } if ( ! $this->isAbsoluteUrl( $source_url ) || ! $this->isAbsoluteUrl( $destination_url ) ) { throw new \InvalidArgumentException( 'Source and destination URLs must include a scheme and host.' ); } $this->source_url = $source_url; $this->destination_url = $destination_url; } public function sourceUrl(): string { return $this->source_url; } public function destinationUrl(): string { return $this->destination_url; } private function normalizeUrl( string $url ): string { $url = trim( $url ); $parts = wp_parse_url( $url ); if ( ! is_array( $parts ) || ! isset( $parts['path'] ) || '/' !== $parts['path'] ) { return $url; } unset( $parts['path'] ); return $this->buildUrl( $parts ); } private function isAbsoluteUrl( string $url ): bool { $parts = wp_parse_url( $url ); return is_array( $parts ) && ! empty( $parts['scheme'] ) && ! empty( $parts['host'] ); } /** * @param array $parts URL parts. */ private function buildUrl( array $parts ): string { $url = (string) $parts['scheme'] . '://'; if ( isset( $parts['user'] ) ) { $url .= (string) $parts['user']; if ( isset( $parts['pass'] ) ) { $url .= ':' . (string) $parts['pass']; } $url .= '@'; } $url .= (string) $parts['host']; if ( isset( $parts['port'] ) ) { $url .= ':' . (string) $parts['port']; } if ( isset( $parts['query'] ) ) { $url .= '?' . (string) $parts['query']; } if ( isset( $parts['fragment'] ) ) { $url .= '#' . (string) $parts['fragment']; } return $url; } }