@@ -205,6 +205,9 @@ function sse_init_plugin() {
205205 // Hook scheduled deletion handler.
206206 add_action ( 'sse_delete_export_file ' , 'sse_delete_export_file_handler ' );
207207
208+ // Hook bulk cleanup handler.
209+ add_action ( 'sse_bulk_cleanup_exports ' , 'sse_bulk_cleanup_exports_handler ' );
210+
208211 // Hook secure download handler.
209212 add_action ( 'admin_init ' , 'sse_handle_secure_download ' );
210213
@@ -336,7 +339,15 @@ function sse_handle_export() {
336339 }
337340
338341 sse_cleanup_files ( array ( $ database_file ['filepath ' ] ) );
342+
343+ // Test cron scheduling capability before attempting real scheduling
344+ sse_test_cron_scheduling ();
345+
339346 sse_schedule_export_cleanup ( $ zip_result ['filepath ' ] );
347+
348+ // Schedule a bulk cleanup sweep in case individual files were missed
349+ sse_schedule_bulk_cleanup ();
350+
340351 sse_show_success_notice ( $ zip_result );
341352 } finally {
342353 // Always release the lock and clean up user preferences.
@@ -850,11 +861,185 @@ function sse_cleanup_files( $files ) {
850861 * @param string $zip_filepath The zip file path to schedule for deletion.
851862 */
852863function sse_schedule_export_cleanup ( $ zip_filepath ) {
853- if ( ! wp_next_scheduled ( 'sse_delete_export_file ' , array ( $ zip_filepath ) ) ) {
854- wp_schedule_single_event ( time () + ( 5 * 60 ), 'sse_delete_export_file ' , array ( $ zip_filepath ) );
864+ sse_log ( 'Attempting to schedule deletion for: ' . $ zip_filepath , 'info ' );
865+
866+ // Check if already scheduled
867+ $ already_scheduled = wp_next_scheduled ( 'sse_delete_export_file ' , array ( $ zip_filepath ) );
868+ if ( $ already_scheduled ) {
869+ sse_log ( 'Export file deletion already scheduled for ' . gmdate ( 'Y-m-d H:i:s ' , $ already_scheduled ) . ' GMT: ' . $ zip_filepath , 'info ' );
870+ return ;
871+ }
872+
873+ // Schedule the deletion
874+ $ scheduled_time = time () + ( 5 * 60 );
875+ sse_log ( 'Attempting to schedule for: ' . gmdate ( 'Y-m-d H:i:s ' , $ scheduled_time ) . ' GMT ' , 'info ' );
876+
877+ $ result = wp_schedule_single_event ( $ scheduled_time , 'sse_delete_export_file ' , array ( $ zip_filepath ) );
878+
879+ if ( $ result === false ) {
880+ sse_log ( 'wp_schedule_single_event returned false - scheduling failed: ' . $ zip_filepath , 'error ' );
881+
882+ // Additional debugging
883+ $ cron_disabled = defined ( 'DISABLE_WP_CRON ' ) && DISABLE_WP_CRON ;
884+ sse_log ( 'DISABLE_WP_CRON status: ' . ( $ cron_disabled ? 'true ' : 'false ' ), 'info ' );
885+
886+ // Check if we can get cron array
887+ $ cron_array = _get_cron_array ();
888+ if ( empty ( $ cron_array ) ) {
889+ sse_log ( 'WordPress cron array is empty ' , 'warning ' );
890+ } else {
891+ sse_log ( 'WordPress cron array exists with ' . count ( $ cron_array ) . ' entries ' , 'info ' );
892+ }
893+ } else {
894+ sse_log ( 'Export file deletion scheduled successfully for ' . gmdate ( 'Y-m-d H:i:s ' , $ scheduled_time ) . ' GMT: ' . $ zip_filepath , 'info ' );
895+
896+ // Verify it was actually scheduled
897+ $ verify_scheduled = wp_next_scheduled ( 'sse_delete_export_file ' , array ( $ zip_filepath ) );
898+ if ( $ verify_scheduled ) {
899+ sse_log ( 'Verification: Event confirmed scheduled for ' . gmdate ( 'Y-m-d H:i:s ' , $ verify_scheduled ) . ' GMT ' , 'info ' );
900+ } else {
901+ sse_log ( 'Verification: Event NOT found in cron schedule despite success return! ' , 'error ' );
902+ }
903+ }
904+ }
905+
906+ /**
907+ * Test function to verify WordPress cron scheduling is working.
908+ * Can be called manually to test the scheduling system.
909+ */
910+ function sse_test_cron_scheduling () {
911+ sse_log ( 'Testing WordPress cron scheduling capability... ' , 'info ' );
912+
913+ // Test with a simple event
914+ $ test_time = time () + 60 ; // 1 minute from now
915+ $ test_result = wp_schedule_single_event ( $ test_time , 'sse_test_cron_event ' );
916+
917+ if ( $ test_result === false ) {
918+ sse_log ( 'Test cron scheduling FAILED - wp_schedule_single_event returned false ' , 'error ' );
919+ return false ;
920+ }
921+
922+ // Verify it was scheduled
923+ $ verify_test = wp_next_scheduled ( 'sse_test_cron_event ' );
924+ if ( $ verify_test ) {
925+ sse_log ( 'Test cron scheduling SUCCESS - event scheduled for ' . gmdate ( 'Y-m-d H:i:s ' , $ verify_test ) . ' GMT ' , 'info ' );
926+
927+ // Clean up the test event
928+ wp_unschedule_event ( $ verify_test , 'sse_test_cron_event ' );
929+ sse_log ( 'Test event cleaned up ' , 'info ' );
930+ return true ;
931+ } else {
932+ sse_log ( 'Test cron scheduling FAILED - event not found after scheduling ' , 'error ' );
933+ return false ;
934+ }
935+ }
936+
937+ /**
938+ * Schedules a bulk cleanup of all export files in the upload directory.
939+ * This runs as a safety net to catch any files that individual cleanup missed.
940+ */
941+ function sse_schedule_bulk_cleanup () {
942+ // Only schedule if not already scheduled
943+ if ( ! wp_next_scheduled ( 'sse_bulk_cleanup_exports ' ) ) {
944+ // Schedule bulk cleanup for 10 minutes from now (after individual files should be cleaned up)
945+ $ scheduled_time = time () + ( 10 * 60 );
946+ $ result = wp_schedule_single_event ( $ scheduled_time , 'sse_bulk_cleanup_exports ' );
947+
948+ if ( $ result ) {
949+ error_log ( 'SSE DEBUG: Bulk cleanup scheduled for ' . gmdate ( 'Y-m-d H:i:s ' , $ scheduled_time ) . ' GMT ' );
950+ sse_log ( 'Bulk export cleanup scheduled for ' . gmdate ( 'Y-m-d H:i:s ' , $ scheduled_time ) . ' GMT ' , 'info ' );
951+ } else {
952+ error_log ( 'SSE DEBUG: Failed to schedule bulk cleanup ' );
953+ sse_log ( 'Failed to schedule bulk export cleanup ' , 'error ' );
954+ }
955+ } else {
956+ error_log ( 'SSE DEBUG: Bulk cleanup already scheduled ' );
957+ sse_log ( 'Bulk export cleanup already scheduled ' , 'info ' );
958+ }
959+ }
960+
961+ /**
962+ * Handles bulk cleanup of all export files older than 5 minutes.
963+ * This is a safety net to catch any files missed by individual cleanup.
964+ */
965+ function sse_bulk_cleanup_exports_handler () {
966+ error_log ( 'SSE DEBUG: Bulk cleanup handler triggered ' );
967+ sse_log ( 'Bulk export cleanup handler triggered ' , 'info ' );
968+
969+ $ upload_dir = wp_upload_dir ();
970+ $ export_dir = $ upload_dir ['basedir ' ] . '/simple-wp-site-exports ' ;
971+
972+ if ( ! is_dir ( $ export_dir ) ) {
973+ sse_log ( 'Export directory does not exist, nothing to clean up ' , 'info ' );
974+ return ;
975+ }
976+
977+ $ files = glob ( $ export_dir . '/*.zip ' );
978+ if ( empty ( $ files ) ) {
979+ sse_log ( 'No export files found in bulk cleanup ' , 'info ' );
980+ return ;
981+ }
982+
983+ $ cleaned_count = 0 ;
984+ $ cutoff_time = time () - ( 5 * 60 ); // Files older than 5 minutes
985+
986+ foreach ( $ files as $ file_path ) {
987+ $ file_time = filemtime ( $ file_path );
988+
989+ if ( $ file_time && $ file_time < $ cutoff_time ) {
990+ // File is older than 5 minutes, validate it's an export file
991+ $ filename = basename ( $ file_path );
992+ $ validation = sse_validate_export_file_for_deletion ( $ filename );
993+
994+ if ( ! is_wp_error ( $ validation ) ) {
995+ if ( sse_safely_delete_file ( $ file_path ) ) {
996+ error_log ( 'SSE DEBUG: Bulk cleanup deleted: ' . $ file_path );
997+ sse_log ( 'Bulk cleanup deleted export file: ' . $ file_path , 'info ' );
998+ $ cleaned_count ++;
999+ } else {
1000+ sse_log ( 'Bulk cleanup failed to delete: ' . $ file_path , 'error ' );
1001+ }
1002+ } else {
1003+ sse_log ( 'Bulk cleanup skipped invalid file: ' . $ file_path . ' - ' . $ validation ->get_error_message (), 'warning ' );
1004+ }
1005+ }
8551006 }
1007+
1008+ sse_log ( "Bulk cleanup completed. Deleted {$ cleaned_count } export files. " , 'info ' );
8561009}
8571010
1011+ /**
1012+ * Gets information about scheduled export file deletions (for debugging).
1013+ *
1014+ * @return array Array of scheduled deletion events.
1015+ */
1016+ function sse_get_scheduled_deletions () {
1017+ $ scheduled_events = array ();
1018+ $ cron_jobs = _get_cron_array ();
1019+
1020+ if ( ! is_array ( $ cron_jobs ) ) {
1021+ return $ scheduled_events ;
1022+ }
1023+
1024+ foreach ( $ cron_jobs as $ timestamp => $ cron_job ) {
1025+ if ( isset ( $ cron_job ['sse_delete_export_file ' ] ) ) {
1026+ foreach ( $ cron_job ['sse_delete_export_file ' ] as $ job ) {
1027+ $ scheduled_events [] = array (
1028+ 'timestamp ' => $ timestamp ,
1029+ 'scheduled_time ' => gmdate ( 'Y-m-d H:i:s ' , $ timestamp ) . ' GMT ' ,
1030+ 'file_path ' => isset ( $ job ['args ' ][0 ] ) ? $ job ['args ' ][0 ] : 'Unknown ' ,
1031+ );
1032+ }
1033+ }
1034+ }
1035+
1036+ return $ scheduled_events ;
1037+ }
1038+
1039+
1040+
1041+
1042+
8581043// --- Scheduled Deletion Handler ---
8591044
8601045/**
@@ -864,6 +1049,8 @@ function sse_schedule_export_cleanup( $zip_filepath ) {
8641049 * @return void
8651050 */
8661051function sse_delete_export_file_handler ( $ file ) {
1052+ sse_log ( 'Scheduled deletion handler triggered for file: ' . $ file , 'info ' );
1053+
8671054 // Validate that this is actually an export file before deletion.
8681055 $ filename = basename ( $ file );
8691056
0 commit comments