@@ -118,6 +118,7 @@ private function __construct() {
118
118
119
119
// Register AJAX handlers
120
120
add_action ( 'wp_ajax_stl_get_file_diff ' , array ( $ this , 'ajax_get_file_diff ' ) );
121
+ add_action ( 'wp_ajax_stl_view_file ' , array ( $ this , 'ajax_view_file ' ) );
121
122
}
122
123
123
124
/**
@@ -289,14 +290,30 @@ public function get_file_diff( $file ) {
289
290
return false ;
290
291
}
291
292
293
+ // Check if file is an image
294
+ if ( $ this ->is_image_file ( $ file ) ) {
295
+ return array (
296
+ 'is_binary ' => true ,
297
+ 'is_image ' => true ,
298
+ 'staging_exists ' => $ staging_exists ,
299
+ 'production_exists ' => $ production_exists ,
300
+ 'staging_size ' => $ staging_exists ? filesize ( $ staging_path ) : 0 ,
301
+ 'production_size ' => $ production_exists ? filesize ( $ production_path ) : 0 ,
302
+ 'staging_url ' => $ staging_exists ? $ this ->get_file_url ( $ file , 'staging ' ) : '' ,
303
+ 'production_url ' => $ production_exists ? $ this ->get_file_url ( $ file , 'production ' ) : '' ,
304
+ 'file_name ' => basename ( $ file ),
305
+ );
306
+ }
307
+
292
308
// Get file contents
293
309
$ staging_content = $ staging_exists ? file_get_contents ( $ staging_path ) : '' ;
294
310
$ production_content = $ production_exists ? file_get_contents ( $ production_path ) : '' ;
295
311
296
- // If file is binary, don't show diff
312
+ // If file is binary (but not image) , don't show diff
297
313
if ( $ this ->is_binary_file ( $ file ) ) {
298
314
return array (
299
315
'is_binary ' => true ,
316
+ 'is_image ' => false ,
300
317
'staging_exists ' => $ staging_exists ,
301
318
'production_exists ' => $ production_exists ,
302
319
'staging_size ' => $ staging_exists ? filesize ( $ staging_path ) : 0 ,
@@ -327,6 +344,7 @@ public function get_file_diff( $file ) {
327
344
328
345
return array (
329
346
'is_binary ' => false ,
347
+ 'is_image ' => false ,
330
348
'staging_exists ' => $ staging_exists ,
331
349
'production_exists ' => $ production_exists ,
332
350
'diff ' => $ diff_table ,
@@ -362,6 +380,75 @@ public function ajax_get_file_diff() {
362
380
wp_send_json_success ( $ diff );
363
381
}
364
382
383
+ /**
384
+ * AJAX handler for viewing files from staging
385
+ */
386
+ public function ajax_view_file () {
387
+ // Check nonce
388
+ if ( ! check_ajax_referer ( 'stl_view_file_nonce ' , 'nonce ' , false ) ) {
389
+ wp_die ( __ ( 'Security check failed. ' , 'staging2live ' ) );
390
+ }
391
+
392
+ // Check if user has permissions
393
+ if ( ! current_user_can ( 'manage_options ' ) ) {
394
+ wp_die ( __ ( 'You do not have permission to view this file. ' , 'staging2live ' ) );
395
+ }
396
+
397
+ // Get file path and environment
398
+ $ file = isset ( $ _GET ['file ' ] ) ? sanitize_text_field ( wp_unslash ( $ _GET ['file ' ] ) ) : '' ;
399
+ $ env = isset ( $ _GET ['env ' ] ) ? sanitize_text_field ( wp_unslash ( $ _GET ['env ' ] ) ) : 'production ' ;
400
+
401
+ if ( empty ( $ file ) ) {
402
+ wp_die ( __ ( 'No file specified. ' , 'staging2live ' ) );
403
+ }
404
+
405
+ // Get the actual file path
406
+ $ file_path = ( $ env === 'staging ' ) ? $ this ->staging_root . $ file : $ this ->production_root . $ file ;
407
+
408
+ // Check if file exists
409
+ if ( ! file_exists ( $ file_path ) || ! is_readable ( $ file_path ) ) {
410
+ wp_die ( __ ( 'File not found or not readable. ' , 'staging2live ' ) );
411
+ }
412
+
413
+ // Get file extension
414
+ $ extension = strtolower ( pathinfo ( $ file , PATHINFO_EXTENSION ) );
415
+
416
+ // Set content type based on file extension
417
+ switch ( $ extension ) {
418
+ case 'jpg ' :
419
+ case 'jpeg ' :
420
+ $ content_type = 'image/jpeg ' ;
421
+ break ;
422
+ case 'png ' :
423
+ $ content_type = 'image/png ' ;
424
+ break ;
425
+ case 'gif ' :
426
+ $ content_type = 'image/gif ' ;
427
+ break ;
428
+ case 'webp ' :
429
+ $ content_type = 'image/webp ' ;
430
+ break ;
431
+ case 'svg ' :
432
+ $ content_type = 'image/svg+xml ' ;
433
+ break ;
434
+ case 'ico ' :
435
+ $ content_type = 'image/x-icon ' ;
436
+ break ;
437
+ case 'bmp ' :
438
+ $ content_type = 'image/bmp ' ;
439
+ break ;
440
+ default :
441
+ $ content_type = 'application/octet-stream ' ;
442
+ break ;
443
+ }
444
+
445
+ // Output file contents
446
+ header ( 'Content-Type: ' . $ content_type );
447
+ header ( 'Content-Length: ' . filesize ( $ file_path ) );
448
+ readfile ( $ file_path );
449
+ exit ;
450
+ }
451
+
365
452
/**
366
453
* Get all files in a directory recursively
367
454
*
@@ -472,6 +559,40 @@ private function get_relative_path( $path, $base ) {
472
559
return ltrim ( str_replace ( $ base , '' , $ path ), '/ ' );
473
560
}
474
561
562
+ /**
563
+ * Check if a file is an image based on extension
564
+ *
565
+ * @param string $file File path
566
+ * @return bool True if image, false otherwise
567
+ */
568
+ private function is_image_file ( $ file ) {
569
+ $ image_extensions = array ('jpg ' , 'jpeg ' , 'png ' , 'gif ' , 'webp ' , 'bmp ' , 'ico ' , 'svg ' );
570
+ $ extension = strtolower ( pathinfo ( $ file , PATHINFO_EXTENSION ) );
571
+ return in_array ( $ extension , $ image_extensions );
572
+ }
573
+
574
+ /**
575
+ * Get URL for a file in staging or production
576
+ *
577
+ * @param string $file Relative file path
578
+ * @param string $environment 'staging' or 'production'
579
+ * @return string URL to the file
580
+ */
581
+ private function get_file_url ( $ file , $ environment = 'production ' ) {
582
+ if ( $ environment === 'staging ' ) {
583
+ // For staging, we'll use a special endpoint to serve the file
584
+ $ nonce = wp_create_nonce ( 'stl_view_file_nonce ' );
585
+ return admin_url ( 'admin-ajax.php?action=stl_view_file&file= ' . urlencode ( $ file ) . '&env=staging&nonce= ' . $ nonce );
586
+ } else {
587
+ // For production, we can use the site URL
588
+ if ( strpos ( $ file , 'wp-content/ ' ) === 0 ) {
589
+ return content_url ( str_replace ( 'wp-content/ ' , '' , $ file ) );
590
+ } else {
591
+ return site_url ( $ file );
592
+ }
593
+ }
594
+ }
595
+
475
596
/**
476
597
* Check if a file is binary based on extension
477
598
*
0 commit comments