@@ -258,7 +258,7 @@ private function serve_css_with_rewritten_urls( $full_path, $hash, $mime_type, $
258258 return ;
259259 }
260260
261- $ base_url = rest_url ( ' exelearning/v1/content/ ' . $ hash . ' / ' );
261+ $ base_url = self :: get_uploads_url ( $ hash );
262262
263263 // Get the directory of the current CSS file for resolving relative paths.
264264 $ current_dir = '' ;
@@ -301,7 +301,8 @@ function ( $matches ) use ( $base_url, $current_dir ) {
301301 * @return string Modified HTML with absolute URLs.
302302 */
303303 private function rewrite_relative_urls ( $ html , $ hash , $ file_path = '' ) {
304- $ base_url = rest_url ( 'exelearning/v1/content/ ' . $ hash . '/ ' );
304+ $ uploads_url = self ::get_uploads_url ( $ hash );
305+ $ proxy_url = self ::get_proxy_url ( $ hash , '' );
305306
306307 // Get the directory of the current file for resolving relative paths.
307308 $ current_dir = '' ;
@@ -325,7 +326,7 @@ private function rewrite_relative_urls( $html, $hash, $file_path = '' ) {
325326 foreach ( $ patterns as $ pattern ) {
326327 $ html = preg_replace_callback (
327328 $ pattern ,
328- function ( $ matches ) use ( $ base_url , $ current_dir ) {
329+ function ( $ matches ) use ( $ uploads_url , $ proxy_url , $ current_dir ) {
329330 $ prefix = $ matches [1 ];
330331 $ attr = $ matches [2 ];
331332 $ url = $ matches [3 ];
@@ -339,33 +340,47 @@ function ( $matches ) use ( $base_url, $current_dir ) {
339340 // Resolve the relative URL based on current directory.
340341 $ resolved_path = $ this ->resolve_relative_path ( $ current_dir , $ url );
341342
342- // Build absolute URL.
343- $ absolute_url = $ base_url . $ resolved_path ;
343+ // HTML files go through the proxy (for CSP headers);
344+ // all other assets are served directly from uploads.
345+ $ base_url = self ::is_html_path ( $ resolved_path ) ? $ proxy_url : $ uploads_url ;
344346
345- return $ prefix . $ attr . esc_url ( $ absolute_url ) . $ end_quote ;
347+ return $ prefix . $ attr . esc_url ( $ base_url . $ resolved_path ) . $ end_quote ;
346348 },
347349 $ html
348350 );
349351 }
350352
351- // Also handle url() in inline styles.
353+ // Also handle url() in inline styles (never HTML, always assets) .
352354 $ html = preg_replace_callback (
353355 '/url\s*\(\s*[" \']?(?!https?:\/\/|data:|\/\/|#)([^" \')\s]+)[" \']?\s*\)/i ' ,
354- function ( $ matches ) use ( $ base_url , $ current_dir ) {
356+ function ( $ matches ) use ( $ uploads_url , $ current_dir ) {
355357 $ url = $ matches [1 ];
356358 if ( empty ( $ url ) || '/ ' === $ url [0 ] ) {
357359 return $ matches [0 ];
358360 }
359361 // Resolve the relative URL based on current directory.
360362 $ resolved_path = $ this ->resolve_relative_path ( $ current_dir , $ url );
361- return 'url(" ' . esc_url ( $ base_url . $ resolved_path ) . '") ' ;
363+ return 'url(" ' . esc_url ( $ uploads_url . $ resolved_path ) . '") ' ;
362364 },
363365 $ html
364366 );
365367
366368 return $ html ;
367369 }
368370
371+ /**
372+ * Check if a file path points to an HTML file.
373+ *
374+ * @param string $path File path to check.
375+ * @return bool True if the path ends with .html or .htm.
376+ */
377+ private static function is_html_path ( $ path ) {
378+ // Strip query string and fragment before checking extension.
379+ $ clean_path = strtok ( $ path , '?# ' );
380+ $ extension = strtolower ( pathinfo ( $ clean_path , PATHINFO_EXTENSION ) );
381+ return 'html ' === $ extension || 'htm ' === $ extension ;
382+ }
383+
369384 /**
370385 * Resolve a relative path against a base directory.
371386 *
@@ -501,4 +516,20 @@ public static function get_proxy_url( $hash, $file = 'index.html' ) {
501516 }
502517 return rest_url ( 'exelearning/v1/content/ ' . $ hash . '/ ' . $ file );
503518 }
519+
520+ /**
521+ * Generate a direct uploads URL for the given hash and file.
522+ *
523+ * Sub-assets (CSS, JS, images, fonts) are served directly from the uploads
524+ * directory to avoid 404s on hosted environments where the web server
525+ * intercepts requests with static file extensions.
526+ *
527+ * @param string $hash Extraction hash.
528+ * @param string $file File path (default: empty).
529+ * @return string Uploads URL.
530+ */
531+ public static function get_uploads_url ( $ hash , $ file = '' ) {
532+ $ upload_dir = wp_upload_dir ();
533+ return trailingslashit ( $ upload_dir ['baseurl ' ] ) . 'exelearning/ ' . $ hash . '/ ' . $ file ;
534+ }
504535}
0 commit comments