<?php /** * Create a ZIP of every attachment in a "Documents" CPT, * organized into main folders and sub-folders using your exact labels, * with "/" replaced by "-" in folder names, * and named after the document’s title. */ function create_documents_zip( $post_id ) { if ( ! $post_id ) { return false; } // Build ZIP filename from post title $post_title = get_the_title( $post_id ); $slug = sanitize_title( $post_title ); $zip_name = "{$slug}.zip"; // 1) Define main folders (sections) and sub-folders (fields) $sections = [ 'Personal Information' => [ 'passport-sized-photo' => 'Passport Sized Photo', 'valid-passport' => 'Valid Passport', 'national-identity-cards' => 'National Identity Cards', 'employment-pass-s-pass-dependent-pass' => 'Employment Pass/ S Pass/ Dependent Pass', 'birth-certificates-household-registration' => 'Birth Certificates/ Household Registration', 'official-marriage-certificate' => 'Official Marriage Certificate', ], 'Education & Professional Information' => [ 'education-certificates-transcripts' => 'Education Certificates/ Transcripts', 'child039schildren039s-school-admission-letter-results' => "Child's/Children's School Admission Letter/ Results", 'additional-certifications-courses-workshops' => 'Additional Certifications/ Courses/ Workshops', ], 'Social Contributions' => [ 'media-article-s-in-company--newsletters-websites--magazines--showcasing-contributions' => 'Media article (s) in Company / Newsletters / Websites / Magazines / Showcasing Contributions', 'membership-in-clubs--societies' => 'Membership in Clubs / Societies', 'charity-contribution-receipts--letters' => 'Charity Contribution Receipt(s) / Letter(s)', 'corporate-social-responsibility--community-participated-events' => 'Corporate Social Responsibility / Community Participated Events', ], 'Employment Documents' => [ 'latest-6-months-payslips' => 'Latest 6 Months Payslips', 'valid-business-registration-certificate-acrabizfile' => 'Valid Business Registration Certificate (ACRABizfile)', 'current-employer039s-letter-stating-date-of-employment-position-held-and-salary-per-month-for-past-6-months' => "Current Employer's Letter Stating Date of Employment, Position Held and Salary Per Month for Past 6 Months", 'up-to-date-resume' => 'Up To Date Resume', 'salary-increment-letters--promotion-letter-s' => 'Salary Increment Letter(s) / Promotion Letter (s)', 'annex-a-of-form-4a' => 'Annex A of Form 4A', ], 'Economic Contributions' => [ 'summary-of-personal-insurance' => 'Summary of Personal Insurance', 'summary-of-portfolio-of-personal-investments' => 'Summary of Portfolio of Personal Investments', 'summary-of-property-investments' => 'Summary of Property Investments', ], 'Testimonials' => [ 'testimonial-from-current--previous-employer' => 'Testimonial from Current / Previous Employer', 'testimonial-from-others' => 'Testimonial from Others', ], // "Additional Documents" repeater handled below only if it has files ]; // Prepare the ZIP archive $upload_dir = wp_upload_dir(); $zip_path = trailingslashit( $upload_dir['basedir'] ) . $zip_name; $zip = new ZipArchive(); if ( $zip->open( $zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE ) !== true ) { return false; } // Helper: add one file into Main/Sub $add_file = function( $att_id, $main_label, $sub_label ) use ( $zip ) { $file = get_attached_file( $att_id ); if ( ! $file || ! file_exists( $file ) ) { return; } // Clean up labels, replace "/" with "-" $safe_main = sanitize_file_name( str_replace( '/', '-', $main_label ) ); $safe_sub = sanitize_file_name( str_replace( '/', '-', $sub_label ) ); // Create the folders and add the file $zip->addEmptyDir( $safe_main ); $zip->addEmptyDir( "{$safe_main}/{$safe_sub}" ); $zip->addFile( $file, "{$safe_main}/{$safe_sub}/" . basename( $file ) ); }; // 2) Loop each defined section and its fields foreach ( $sections as $main_label => $fields ) { foreach ( $fields as $meta_key => $sub_label ) { $raw = get_post_meta( $post_id, $meta_key, true ); if ( empty( $raw ) ) { continue; } // Normalize to array of items $items = is_array( $raw ) ? $raw : ( strpos( $raw, ',' ) !== false ? array_map( 'trim', explode( ',', $raw ) ) : [ $raw ] ); foreach ( $items as $item ) { if ( is_array( $item ) && ! empty( $item['id'] ) ) { $item = $item['id']; } if ( is_string( $item ) && filter_var( $item, FILTER_VALIDATE_URL ) ) { $item = attachment_url_to_postid( $item ); } $att_id = intval( $item ); if ( $att_id ) { $add_file( $att_id, $main_label, $sub_label ); } } } } // 3) Handle the repeater field "upload-additional-documents" only if it has items $repeater = get_post_meta( $post_id, 'upload-additional-documents', true ); if ( is_array( $repeater ) && ! empty( $repeater ) ) { foreach ( $repeater as $row ) { $sub_label_raw = ! empty( $row['document-about'] ) ? $row['document-about'] : 'Miscellaneous'; $raw_items = $row['select-documents']; if ( empty( $raw_items ) ) { continue; } // Normalize repeater gallery values $items = is_array( $raw_items ) ? $raw_items : ( strpos( $raw_items, ',' ) !== false ? array_map( 'trim', explode( ',', $raw_items ) ) : [ $raw_items ] ); foreach ( $items as $item ) { if ( is_array( $item ) && ! empty( $item['id'] ) ) { $item = $item['id']; } if ( is_string( $item ) && filter_var( $item, FILTER_VALIDATE_URL ) ) { $item = attachment_url_to_postid( $item ); } $att_id = intval( $item ); if ( $att_id ) { $add_file( $att_id, 'Additional Documents', $sub_label_raw ); } } } } $zip->close(); return $zip_path; } /** * Stream the ZIP when ?download_all=1&post_id=… is requested. */ add_action( 'template_redirect', function() { if ( isset( $_GET['download_all'], $_GET['post_id'] ) ) { $post_id = intval( $_GET['post_id'] ); // Optional: verify nonce or user capability here $zip_file = create_documents_zip( $post_id ); if ( ! $zip_file || ! file_exists( $zip_file ) ) { wp_die( 'Unable to generate ZIP.' ); } header( 'Content-Type: application/zip' ); header( 'Content-Disposition: attachment; filename="' . basename( $zip_file ) . '"' ); header( 'Content-Length: ' . filesize( $zip_file ) ); readfile( $zip_file ); exit; } });