<?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;
}
});
Comments