/** * Excel / CSV import engine — inc/excel-import.php * * Handles bulk import of all content types via .xlsx upload. * Called by inc/admin-import.php (admin Tools page) and * inc/dokan-import.php (vendor dashboard). * * @package 4wd-authority */ defined( 'ABSPATH' ) || exit; require_once get_template_directory() . '/inc/lib/SimpleXLSX.php'; /* ============================================================ MAIN DISPATCHER ============================================================ */ function fwd_import_xlsx( string $type, string $file_path, ?int $vendor_id = null ): array { $result = [ 'created' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => [] ]; $xlsx = SimpleXLSX::parse( $file_path ); if ( ! $xlsx ) { $result['errors'][] = 'Could not parse file: ' . SimpleXLSX::parseError(); return $result; } $rows = $xlsx->rows(); if ( count( $rows ) < 5 ) { $result['errors'][] = 'File has fewer than 5 rows — nothing to import (remember: rows 1-4 are the template header).'; return $result; } $headers = array_map( 'trim', $rows[2] ); $data_rows = array_slice( $rows, 4 ); switch ( $type ) { case 'products': return fwd_import_products( $headers, $data_rows, $vendor_id ); case 'parts': return fwd_import_cpt( 'fwd_parts', $headers, $data_rows, $vendor_id ); case 'rentals': return fwd_import_cpt( 'rental', $headers, $data_rows, $vendor_id ); case 'classifieds': case 'market': return fwd_import_cpt( 'listing', $headers, $data_rows, $vendor_id ); case 'drives': return fwd_import_cpt( 'drive', $headers, $data_rows, $vendor_id ); case 'resources': return fwd_import_cpt( 'resource', $headers, $data_rows, $vendor_id ); default: $result['errors'][] = 'Unknown import type: ' . esc_html( $type ); return $result; } } /* ============================================================ WOOCOMMERCE PRODUCTS ============================================================ */ function fwd_import_products( array $headers, array $rows, ?int $vendor_id = null, string $forced_category = '' ): array { $result = [ 'created' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => [] ]; foreach ( $rows as $i => $row ) { if ( empty( array_filter( $row ) ) ) continue; $d = fwd_import_map( $headers, $row ); $title = trim( $d['title'] ?? '' ); if ( ! $title ) { $result['skipped']++; continue; } $sku = trim( $d['sku'] ?? '' ); $existing_id = 0; if ( $sku ) { $existing_id = wc_get_product_id_by_sku( $sku ); } if ( ! $existing_id ) { $q = new WP_Query([ 'post_type' => 'product', 'post_status' => 'any', 'title' => $title, 'posts_per_page' => 1, vfVG2rvG2rғFW7FuBG7G5РbFW7FuBbbGfVF%BG7BvWE7BFW7FuBbG7BbbBG7B7EWF"GfVF%BG&W7VEvW'&'2uյ%&r"FR#4RFFRF6W2FW"fVF"w2&GV7B( B6VB#G&W7VEw6VBuҲ6FVSТРG7FGW2'&7G'FvW"FEw7FGW2uwV&Ɨ6rvG&gBrwVFrrw&fFRrG'VR7G'FvW"FEw7FGW2uwV&Ɨ6sG7E'"w7EFFRrGFFRw7E6FVBrw6W57BFEvFW67&Furrw7EW6W'Brw6W57BFEw6'EFW67&Furrw7E7FGW2rG7FGW2w7EGRrw&GV7Brw7EWF"rGfVF%BvWE7W'&VEW6W%BӰbFW7FuBG7E'%tBuFW7FuCG7EBwWFFU7BG7E'"G'VRb5wW'&"G7EBG&W7VEvW'&'2uյ%&r"FR#"G7EBvWEW'&%W76vR6FVSТG&W7VEwWFFVBuҲV6RG7EBw6W'E7BG7E'"G'VRb5wW'&"G7EBG&W7VEvW'&'2uյ%&r"FR#"G7EBvWEW'&%W76vR6FVSТG&W7VEv7&VFVBuҲРG&GV7Bv5vWE&GV7BG7EBbG&GV7B6FVSbG6RG&GV7B6WE6RG6Rb76WBFEw&VwV%&6Rubb5VW&2FEw&VwV%&6RuG&GV7B6WE&VwV%&6RFEw&VwV%&6Rub76WBFEw6U&6Rubb5VW&2FEw6U&6RuG&GV7B6WE6U&6RFEw6U&6Rub76WBFEw&6Rubb5VW&2FEw&6Rubb76WBFEw&VwV%&6RuG&GV7B6WE&VwV%&6RFEw&6Rub76WBFEwvVvBubb5VW&2FEwvVvBuG&GV7B6WEvVvBFEwvVvBub76WBFEw7F6ubb5VW&2FEw7F6uG&GV7B6WEvU7F6G'VRG&GV7B6WE7F6VFGBFEw7F6uТbVGFEwf'GVubb'&7G'FvW"FEwf'GVuwW2rsrwG'VRrG'VRG&GV7B6WEf'GV‚G'VRТG&GV7B6fRF6G2Ff&6VE6FVv'Ff&6VE6FVv''&fFW"'&wG&rWFRwrFEv6FVv&W2urrbF6G2GFW&G2Ӱf&V6F6G22F6ERGFW&vWEFW&'vRrF6ERw&GV7E6BrbGFW&GFW&vWEFW&'w6Vrr6FUFFRF6ERw&GV7E6BrbGFW&GFW&G5GFW&FW&CТbGFW&G2w6WE7EFW&2G7EBGFW&G2w&GV7E6Brf6RРbVGFEwFw2uGFw2'&fFW"'&wG&rWFRwrFEwFw2ubGFw2w6WE7EFW&2G7EBGFw2w&GV7EFrrf6RРbVGFEvvW2uGW&2'&fFW"'&wG&rWFRwrFEvvW2ugvE'EGF6vW2G7EBGW&2ТР&WGW&G&W7VCРТtTU$25B%DU gV7FgvE'E7B7G&rG7EGR'&FVFW'2'&G&w2BGfVF%BV'&G&W7VBv7&VFVBrwWFFVBrw6VBrvW'&'2rӰf&V6G&w22FG&rbVG'&fFW"G&r6FVSFBgvE'EFVFW'2G&rGFFRG&҂FEwFFRurrbGFFRG&W7VEw6VBuҲ6FVSРGWruVW'w7EGRrG7EGRw7E7FGW2rvrwFFRrGFFRw7G5W%vRrvfVG2rvG2rғFW7FuBG7G5bFW7FuBbbGfVF%BG7BvWE7BFW7FuBbG7BbbBG7B7EWF"GfVF%BG&W7VEvW'&'2uյ%&r"FR#7B&Vw2FFW"W6W"( B6VB#G&W7VEw6VBuҲ6FVSТРG&u7FGW27G'FvW"FEw7FGW2uwV&Ɨ6r66WB'V&Ɨ6VB"2Ɩ2f"'V&Ɨ6 bG&u7FGW2wV&Ɨ6VBrG&u7FGW2wV&Ɨ6sG7FGW2'&G&u7FGW2vG&gBrwVFrrw&fFRrG'VRG&u7FGW2wV&Ɨ6sG7E'"w7EFFRrGFFRw7E6FVBrw6W57BFEvFW67&FuFEv6FVBurrw7EW6W'Brw6W57BFEvW6W'BuFEw6'EFW67&Furrw7E7FGW2rG7FGW2w7EGRrG7EGRw7EWF"rGfVF%BvWE7W'&VEW6W%BӰbFW7FuBG7E'%tBuFW7FuCG7EBwWFFU7BG7E'"G'VRb5wW'&"G7EBG&W7VEvW'&'2uյ%&r"FR#"G7EBvWEW'&%W76vR6FVSТG&W7VEwWFFVBuҲV6RG7EBw6W'E7BG7E'"G'VRb5wW'&"G7EBG&W7VEvW'&'2uյ%&r"FR#"G7EBvWEW'&&W76vR6FVSТG&W7VEv7&VFVBuҲР7vF6G7EGR66RvgvE'G2sgvE'E'G56bFBG7EB'&V66Rw&VFsgvE'E&VF6bFBG7EBbVGFEv6FVv&W2uF6G2'&fFW"'&wG&rWFRwrFEv6FVv&W2ubF6G2w6WE7EFW&2G7EBF6G2w&VF6FVv'rf6RТ'&V66RvƗ7FrsgvE'EƗ7Fu6bFBG7EBbVGFEv6VG'uw6WE7EFW&2G7EBG&҂FEv6VG'uvgvE6VG'rf6RТ'&V66RvG&fRsgvE'EG&fU6bFBG7EBbVGFEv6VG'uw6WE7EFW&2G7EBG&҂FEv6VG'uvgvE6VG'rf6RТbVGFEvG&fUGRuFGBG&҂FEvG&fUGRuGFW&vWEFW&'vRrFGBvG&fUGRrvWEFW&'w6Vrr6FUFFRFGBvG&fUGRrbGFW&w6WE7EFW&2G7EBGFW&FW&BvG&fUGRrf6RТ'&V66Rw&W6W&6RsgvE'E&W6W&6U6bFBG7EBbVGFEw&W6W&6U6BuF6G2'&fFW"'&wG&rWFRwrFEw&W6W&6U6BubF6G2w6WE7EFW&2G7EBF6G2w&W6W&6U6Brf6RТ'&VРbVGFEvvW2uVGFEvfVGW&VEvRuFu7G"FEvvW2u7E6BrbGFW&GFW&G5GFW&FW&CТbGFW&G2w6WE7EFW&2G7EBGFW&G2w&GV7E6Brf6RРbVGFEwFw2uGFw2'&fFW"'&wG&rWFRwrFEwFw2ubGFw2w6WE7EFW&2G7EBGFw2w&GV7EFrrf6RРbVGFEvvW2uGW&2'&fFW"'&wG&rWFRwrFEvvW2ugvE'EGF6vW2G7EBGW&2ТР&WGW&G&W7VCРТtTU$25B%DU gV7FgvE'E7B7G&rG7EGR'&FVFW'2'&G&w2BGfVF%BV'&G&W7VBv7&VFVBrwWFFVBrw6VBrvW'&'2rӰf&V6G&w22FG&rbVG'&fFW"G&r6FVSFBgvE'EFVFW'2G&rGFFRG&҂FEwFFRurrbGFFRG&W7VEw6VBuҲ6FVSРGWruVW'w7EGRrG7EGRw7E7FGW2rvrwFFRrGFFRw7G5W%vRrvfVG2rvG2rғFW7FuBG7G5bFW7FuBbbGfVF%BG7BvWE7BFW7FuBbG7BbbBG7B7EWF"GfVF%BG&W7VEvW'&'2uյ%&r"FR#7B&Vw2FFW"W6W"( B6VB#G&W7VEw6VBuҲ6FVSТРG&u7FGW27G'FvW"FEw7FGW2uwV&Ɨ6r66WB'V&Ɨ6VB"2Ɩ2f"'V&Ɨ6 bG&u7FGW2wV&Ɨ6VBrG&u7FGW2wV&Ɨ6sG7FGW2'&G&u7FGW2vG&gBrwVFrrw&fFRrG'VRG&u7FGW2wV&Ɨ6sG7E'"w7EFFRrGFFRw7E6FVBrw6W57BFEvFW67&FuFEv6FVBurrw7EW6W'Brw6W57BFEvW6W'BuFEw6'EFW67&Furrw7E7FGW2rG7FGW2w7EGRrG7EGRw7EWF"rGfVF%BvWE7W'&VEW6W%BӰbFW7FuBG7E'%tBuFW7FuCG7EBwWFFU7BG7E'"G'VRb5wW'&"G7EBG&W7VEvW'&'2uյ%&r"FR#"G7EBvWEW'&%W76vR6FVSТG&W7VEwWFFVBuҲV6RG7EBw6W'E7BG7E'"G'VRb5wW'&"G7EBG&W7VEvW'&'2uյ%&r"FR#"G7EBvWDW'&$W76vR6FVSТG&W7VEv7&VFVBuҲР7vF6G7EGR66RvgvE'G2sgvE'E'G56bFBG7EB'&V66Rw&VFsgvE'E&VF6bFBG7EBbVGFEv6FVv&W2uF6G2'&fFW"'&wG&rWFRwrFEv6FVv&W2ubF6G2w6WE7EFW&2G7EBF6G2w&VF6FVv'rf6RТ'&V66RvƗ7FrsgvE'EƗ7Fu6bFBG7EBbVGFEv6VG'uw6WE7EFW&2G7EBG&҂FEv6VG'uvgvE6VG'rf6RТ'&V66RvG&fRsgvE'EG&fU6bFBG7EBbVGFEv6VG'uw6WE7EFW&2G7EBG&҂FEv6VG'uvgvE6VG'rf6RТbVGFEvG&fUGRuFGBG&҂FEvG&fUGRuGFW&vWEFW&'vRrFGBvG&fUGRrvWEFW&'w6Vrr6FUFFRFGBvG&fUGRrbGFW&w6WE7EFW&2G7EBGFW&FW&BvG&fUGRrf6RТ'&V66Rw&W6W&6RsgvE'E&W6W&6U6bFBG7EBbVGFEw&W6W&6U6BuF6G2'&fFW"'&wG&rWFRwrFEw&W6W&6U6BubF6G2w6WE7EFW&2G7EBF6G2w&W6W&6U6Brf6RТ'&VРbVGFEvvW2uVGFEvfVGW&VEvRuFu7G"FEvvW2uFEvfVGW&VEvRursGW&2'&fFW"'&wG&rWFRwrFu7G"bGW&2gvE'EGF6vW2G7EBGW&2ТР&WGW&G&W7VCРТ4bdTBTU%0gV7FgvE'E'G56b'&FBBG7EBfBG66'2w&6Rrv6FFrv6F&UvFrv'&Brw'EV&W"rw7F6rw6Rrv6FrwvVvBrvFV62rӰf&V6G66'22FWb76WBFEFWbbFEFWrrWFFU7EWFG7EBFW6FUFWEfVBFEFWТbVGFEv6FVv'uw6WE7EFW&2G7EB'&fFW"'&wG&rWFRwrFEv6FVv'uw'G56Brf6RЧРgV7FgvE'E&VF6b'&FBBG7EBfB&FUW%F2FR4bfVBS66WB&6UW%F2Vv7Ɩ0G&FRFEw&FUW%FuFEw&6UW%FursbG&FRrrWFFU7EWFG7EBw&FUW%Fr6FUFWEfVBG&FRG66'2vFW6BrwVG5f&Rrv6Frv66Grw&VFGRrӰf&V6G66'22FWb76WBFEFWbbFEFWrrWFFU7EWFG7EBFW6FUFWEfVBFEFWРFVƗfW'f&SW2(i"b76WBFEvFVƗfW'f&RuWFFU7EWFG7EBvFVƗfW'f&Rr'&7G'FvW"FEvFVƗfW'f&RuwW2rsrwG'VRrG'VRРWG&3R6W$&Vå&6R"Rr$u3#W&b&6S"(i"&WVFW"&w0bVGFEvWG&2uG&w2Ӱf&V6'&fFW"'&wG&rWFRwrFEvWG&2u2FFVGWFRsrFFV"G&w5v&Vr6FUFWEfVBG&҂Gw&6Rr76WBGfBG&҂GӰТbG&w2WFFU7EWFG7EBvWG&2rG&w2Р7V73R6W$WfVR"Rr%6VG3WgVVäFW6V"(i"&WVFW"&w0bVGFEw7V72uG&w2Ӱf&V6'&fFW"'&wG&rWFRwrFEw7V72u2FFVGWFRsrFFV"G&w5vr6FUFWEfVBG&҂Gwbr76WBG6FUFWEfVBG&҂GrrӰТbG&w2WFFU7EWFG7EBw7V72rG&w2ЧРgV7FgvE'EƗ7Fu6b'&FBBG7EBfBG66'2w&6Rrv6FFrw6VW%GRrw6UGRrvRrvFVrwV"rv֖VvRrvVvRrv&GGRrvgVVGRrwG&6֗76rv6W"rw&VuFRrv6FrvV֗&FRrwvG6rw6VW"rve6FVv'rve'&Brve6FFrve6F&RrwUV&W"rӰf&V6G66'22FWb76WBFEFWbbFEFWrrWFFU7EWFG7EBFW6FUFWEfVBFEFWР&6v&B6BƖ6W0bVGFEv6W"ubbVGFEv6"uWFFU7EWFG7EBv6W"r6FUFWEfVBFEv6"uMN DEFINITIONS ============================================================ */ function fwd_import_get_template_columns( string $type ): array { switch ( $type ) { case 'products': return [ 'title' => 'Product name (required)', 'sku' => 'Unique SKU — used to match existing products for update', 'regular_price' => 'Full price (AED)', 'sale_price' => 'Sale price — leave blank if not on sale', 'description' => 'Full product description (HTML allowed)', 'short_description' => 'Brief summary shown on category pages', 'categories' => 'Pipe-sep: 4x4 Parts|Recovery & Safety|Accessories & Gear|Camping & Overland', 'tags' => 'Pipe-separated tags', 'weight' => 'Weight in kg', 'stock' => 'Stock quantity (leave blank = unlimited)', 'virtual' => 'yes / no', 'images' => 'Pipe-separated public image URLs (first = featured)', 'status' => 'publish / draft / private', 'vendor_email' => 'Vendor email to assign post to (admin import only)', ]; case 'parts': return [ 'title' => 'Part name (required)', 'description' => 'Full description', 'price' => 'Price (AED)', 'condition' => 'new / used / refurbished', 'brand' => 'Manufacturer brand', 'part_number' => 'OEM or aftermarket part number', 'compatible_with' => 'Pipe-sep compatible makes/models e.g. Land Cruiser 79|Patrol Y61', 'category' => 'Pipe-sep parts categories', 'stock' => 'Stock quantity', 'sku' => 'Your reference SKU', 'location' => 'Emirate / city', 'weight' => 'Weight in kg', 'dimensions' => 'L × W × H cm', 'images' => 'Pipe-separated public image URLs', 'status' => 'publish / draft', 'vendor_email' => 'Vendor email (admin import only)', ]; case 'rentals': return [ 'title' => 'Rental item name (required)', 'description' => 'Full description', 'rate_per_day' => 'Daily rate (AED)', 'deposit' => 'Security deposit (AED)', 'units_available' => 'Number of units in stock', 'categories' => 'Pipe-sep rental categories (e.g. Vehicle|Rooftop Tent|Fridge)', 'extras' => 'Pipe-sep add-ons Label:Price e.g. GPS:25|Roof Rack:50|Cooler:15', 'specs' => 'Pipe-sep specs Key:Value e.g. Seats:5|Fuel:Diesel|Year:2023', 'delivery_available' => 'yes / no', 'images' => 'Pipe-separated public image URLs', 'status' => 'publish / draft', ]; case 'classifieds': case 'market': return [ 'title' => 'Listing title (required)', 'description' => 'Full description (HTML allowed)', 'listing_type' => 'vehicle / non_vehicle', 'price' => 'Asking price (AED)', 'condition' => 'used / new', 'seller_type' => 'member / dealer', 'sale_type' => 'local / export / both', // Vehicle-specific columns 'make' => '[Vehicle] e.g. Toyota', 'model' => '[Vehicle] e.g. Land Cruiser 79', 'year' => '[Vehicle] 4-digit year', 'mileage' => '[Vehicle] Odometer reading (km)', 'body_type' => '[Vehicle] suv / pickup / wagon / coupe / sedan / other', 'fuel_type' => '[Vehicle] petrol / diesel / hybrid / electric', 'transmission' => '[Vehicle] Manual / Auto', 'vehicle_drive_type' => '[Vehicle] 4wd / awd / 2wd', 'engine' => '[Vehicle] Engine size / code e.g. 4.0L V6', 'colour' => '[Vehicle] Exterior colour', 'reg_plate' => '[Vehicle] Registration plate (optional)', 'mods' => '[Vehicle] Pipe-sep mods e.g. Lift|Snorkel|ARB Bullbar|Lockers', // Non-vehicle columns 'nv_category' => '[Non-vehicle] parts / accessories / camping / recovery / electronics / apparel / other', 'nv_brand' => '[Non-vehicle] Brand name', 'nv_condition' => '[Non-vehicle] new / like_new / good / fair', 'nv_compatible' => '[Non-vehicle] Compatible vehicles/makes', // Contact & location 'phone_number' => 'Contact phone number', 'show_phone' => 'yes / no — display phone on listing', 'whatsapp' => 'WhatsApp with country code e.g. 971501234567', 'seller' => 'Seller display name', 'emirate' => 'Dubai / Abu Dhabi / Sharjah / RAK / etc.', 'country' => 'UAE / Oman', 'images' => 'Pipe-separated image URLs (min 3, first = featured)', 'status' => 'publish / draft', 'featured' => 'yes / no — pin to top of listings', ]; case 'drives': return [ 'title' => 'Drive title (required)', 'description' => 'Full drive description', 'drive_type' => 'Day Drive / Multi-Day Expedition', 'difficulty' => 'Easy / Moderate / Intermediate / Hard / Extreme', 'capacity' => 'Max vehicles', 'price' => 'Price per vehicle (AED)', 'distance' => 'Total distance e.g. 42 km loop', 'duration' => 'e.g. Full Day / 3 Days / 5 Days', 'date' => 'Drive date (YYYY-MM-DD)', 'meeting_point' => 'Meeting point description', 'what3words' => '///word.word.word', 'gps' => 'Decimal coordinates: lat,lon e.g. 24.7681,56.1112', 'region' => 'e.g. Hatta / Liwa / Musandam / Wadi Bih', 'country' => 'UAE / Oman', 'included' => 'Pipe-sep included items e.g. Lunch|Recovery gear|Trail guide', 'vehicle_specs' => 'Pipe-sep spec:value e.g. Min Clearance:200mm|Tyres:32 inch', 'images' => 'Pipe-separated public image URLs', 'status' => 'publish / draft', ]; case 'resources': return [ 'title' => 'Article title (required)', 'content' => 'Full article body (HTML allowed)', 'excerpt' => 'Short summary', 'resource_cat' => 'Pipe-sep: Guides / Safety / Trip Reports / Downloads', 'tags' => 'Pipe-separated tags', 'featured_image' => 'URL of featured image', 'status' => 'publish / draft', ]; default: return []; } } https://4wdauthority.com/wp-sitemap-posts-post-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-page-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-forum-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-topic-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-reply-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-product-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-drive-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-rental-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-listing-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-build-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-garage-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-partner-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-resource-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-advisory-1.xmlhttps://4wdauthority.com/wp-sitemap-posts-legal_doc-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-category-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-product_cat-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-drive_type-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-region-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-rental_kind-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-build_type-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-resource_cat-1.xmlhttps://4wdauthority.com/wp-sitemap-taxonomies-fwd_country-1.xml