{"id":366308,"date":"2026-09-15T10:26:18","date_gmt":"2026-09-15T10:26:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/vanquish-attach-me-for-woocommerce\/"},"modified":"2026-09-15T11:17:00","modified_gmt":"2026-09-15T11:17:00","slug":"vanquish-attach-me-for-woocommerce","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/vanquish-attach-me-for-woocommerce\/","author":14329766,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.1","stable_tag":"1.0.1","tested":"7.1","requires":"5.8","requires_php":"7.4","requires_plugins":null,"header_name":"Vanquish Attach Me for WooCommerce","header_author":"Vanquish","header_description":"Attach any file to any WooCommerce order or product, show it to the customer and send it with the order emails. Premium adds bulk product rules, customer approval, expiring files and more.","assets_banners_color":"e4dcee","last_updated":"2026-09-15 11:17:00","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/vanquish-attach-me-for-woocommerce\/","header_author_uri":"https:\/\/vanquishplugins.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":56,"num_ratings":0,"support_threads":1,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"vanquish83","date":"2026-09-15 10:25:56","revision":3696741},"1.0.1":{"tag":"1.0.1","author":"vanquish83","date":"2026-09-15 11:17:00","revision":3696853}},"upgrade_notice":{"1.0.1":"<p>Fixes the legacy data importer on stores that do not use HPOS: it could report data that is not there and run without finishing. Recommended for everyone.<\/p>","1.0.0":"<p>First release. If you are coming from the CodeCanyon &quot;WooCommerce Attach Me!&quot; plugin, install this one alongside it and run the importer from Attach Me \u2192 Settings \u2192 Import old data; nothing is deleted from the old plugin.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3696741,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3696741,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3696741,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3696741,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3696853,"resolution":false,"location":"assets","locale":"","contents":"{\"$schema\":\"https:\\\/\\\/playground.wordpress.net\\\/blueprint-schema.json\",\"landingPage\":\"\\\/wp-admin\\\/admin.php?page=wc-orders\",\"preferredVersions\":{\"php\":\"8.2\",\"wp\":\"latest\"},\"phpExtensionBundles\":[\"kitchen-sink\"],\"features\":{\"networking\":true},\"steps\":[{\"step\":\"login\",\"username\":\"admin\",\"password\":\"password\"},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"woocommerce\"},\"options\":{\"activate\":true}},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"vanquish-attach-me-for-woocommerce\"},\"options\":{\"activate\":true}},{\"step\":\"installTheme\",\"themeData\":{\"resource\":\"wordpress.org\\\/themes\",\"slug\":\"emoza-woocommerce\"},\"options\":{\"activate\":true}},{\"step\":\"runPHP\",\"code\":\"<?php\\n\\\/**\\n * Live Preview seeding for WordPress Playground.\\n *\\n * This is the SOURCE of the runPHP step in blueprint.json (see build.py). It runs\\n * AFTER WooCommerce and the FREE build of the plugin are active.\\n *\\n * What it has to solve: a fresh store has no orders, and a plugin that attaches\\n * files to orders has nothing to show on a store with no orders. So the seed\\n * builds a small print shop -- the kind of business that sends proofs, invoices\\n * and certificates -- with three orders in different states, real files attached\\n * to two of them, and product files on every product.\\n *\\n * The landing page is the admin orders list, where the Attachments column shows\\n * which orders carry files and its Manage button opens them without leaving the\\n * list. The customer's side is one click away: the orders belong to the signed-in\\n * account, so My account -> Orders shows the same files as the buyer sees them.\\n *\\n * Every attachment goes through the plugin's own services -- Storage::adopt_for()\\n * for the file, OrderAttachments and ProductAttachments for the record -- rather\\n * than being written into meta by hand. The demo data then passes the same\\n * sanitising and lands in the same protected folders as a real upload, and if\\n * the storage format ever changes the seed follows it instead of quietly\\n * producing records the plugin no longer reads.\\n *\\n * Landing on \\\/wp-admin\\\/admin.php?page=wc-orders assumes HPOS. WooCommerce makes\\n * it the default on new installs and Playground always installs the latest, so\\n * that route exists. The option is deliberately not toggled here: the data stores\\n * are chosen when WooCommerce boots, before this script runs, and switching mid-\\n * request would create the orders in one store and list them from the other.\\n *\\n * Closures, not named functions: PHP binds a top-level function declaration when\\n * the file is compiled, so a guard that returns early does not stop it being\\n * declared -- and this file must be safe to run twice.\\n *\\n * Idempotent: guarded by the vanam_demo_seeded option.\\n *\\\/\\n\\nrequire_once '\\\/wordpress\\\/wp-load.php';\\n\\nif ( get_option( 'vanam_demo_seeded' ) ) {\\n\\treturn;\\n}\\n\\nuse Vanquish\\\\AttachMe\\\\Com\\\\Attachment;\\nuse Vanquish\\\\AttachMe\\\\Com\\\\OrderAttachments;\\nuse Vanquish\\\\AttachMe\\\\Com\\\\ProductAttachments;\\nuse Vanquish\\\\AttachMe\\\\Com\\\\Settings;\\nuse Vanquish\\\\AttachMe\\\\Com\\\\Storage;\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 1. Store scaffolding\\n * ------------------------------------------------------------------------ *\\\/\\n\\nupdate_option( 'blogname', 'Vanquish Attach Me for WooCommerce' );\\n\\nif ( class_exists( 'WC_Install' ) ) {\\n\\tWC_Install::create_pages();\\n}\\n\\n\\\/* Recent WooCommerce hides a new store behind a \\\"coming soon\\\" page, which would\\n * put a splash screen between the visitor and the shop. *\\\/\\nupdate_option( 'woocommerce_coming_soon', 'no' );\\n\\nupdate_option( 'woocommerce_store_address', 'Via Roma 1' );\\nupdate_option( 'woocommerce_store_city', 'Pisa' );\\nupdate_option( 'woocommerce_default_country', 'IT:PI' );\\nupdate_option( 'woocommerce_store_postcode', '56100' );\\nupdate_option( 'woocommerce_currency', 'EUR' );\\n\\n\\\/* Tidy the front-end navigation: drop the default Sample Page and build a real\\n * menu, which also removes the theme's automatic \\\"Home\\\" fallback entry. *\\\/\\n$vanam_sample = get_page_by_path( 'sample-page' );\\nif ( $vanam_sample ) {\\n\\twp_delete_post( $vanam_sample->ID, true );\\n}\\n\\nif ( function_exists( 'wc_get_page_id' ) && ! wp_get_nav_menu_object( 'vanam-demo-menu' ) ) {\\n\\t$vanam_menu_id = wp_create_nav_menu( 'vanam-demo-menu' );\\n\\n\\tforeach ( array(\\n\\t\\t'Shop'       => wc_get_page_id( 'shop' ),\\n\\t\\t'Cart'       => wc_get_page_id( 'cart' ),\\n\\t\\t'Checkout'   => wc_get_page_id( 'checkout' ),\\n\\t\\t'My account' => wc_get_page_id( 'myaccount' ),\\n\\t) as $vanam_label => $vanam_page_id ) {\\n\\t\\tif ( $vanam_page_id && $vanam_page_id > 0 ) {\\n\\t\\t\\twp_update_nav_menu_item(\\n\\t\\t\\t\\t$vanam_menu_id,\\n\\t\\t\\t\\t0,\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'menu-item-title'     => $vanam_label,\\n\\t\\t\\t\\t\\t'menu-item-object'    => 'page',\\n\\t\\t\\t\\t\\t'menu-item-object-id' => $vanam_page_id,\\n\\t\\t\\t\\t\\t'menu-item-type'      => 'post_type',\\n\\t\\t\\t\\t\\t'menu-item-status'    => 'publish',\\n\\t\\t\\t\\t)\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n\\n\\t$vanam_locations = get_theme_mod( 'nav_menu_locations' );\\n\\tif ( ! is_array( $vanam_locations ) ) {\\n\\t\\t$vanam_locations = array();\\n\\t}\\n\\tforeach ( array_keys( (array) get_registered_nav_menus() ) as $vanam_location ) {\\n\\t\\t$vanam_locations[ $vanam_location ] = $vanam_menu_id;\\n\\t}\\n\\tset_theme_mod( 'nav_menu_locations', $vanam_locations );\\n}\\n\\n\\\/* Payments and shipping, so the demo checkout can actually be completed:\\n * cash on delivery needs no keys, free shipping needs no configuration. *\\\/\\n$vanam_cod = get_option( 'woocommerce_cod_settings', array() );\\nif ( ! is_array( $vanam_cod ) ) {\\n\\t$vanam_cod = array();\\n}\\nif ( empty( $vanam_cod['enabled'] ) || 'yes' !== $vanam_cod['enabled'] ) {\\n\\t$vanam_cod['enabled']            = 'yes';\\n\\t$vanam_cod['title']              = 'Cash on delivery';\\n\\t$vanam_cod['enable_for_virtual'] = 'yes';\\n\\tupdate_option( 'woocommerce_cod_settings', $vanam_cod );\\n}\\n\\nif ( class_exists( 'WC_Shipping_Zone' ) ) {\\n\\t$vanam_zone     = new WC_Shipping_Zone( 0 ); \\\/\\\/ Anything not matched by another zone.\\n\\t$vanam_has_free = false;\\n\\tforeach ( $vanam_zone->get_shipping_methods() as $vanam_method ) {\\n\\t\\tif ( 'free_shipping' === $vanam_method->id ) {\\n\\t\\t\\t$vanam_has_free = true;\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t}\\n\\tif ( ! $vanam_has_free ) {\\n\\t\\t$vanam_zone->add_shipping_method( 'free_shipping' );\\n\\t\\t$vanam_zone->save();\\n\\t}\\n}\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 2. Plugin settings\\n *\\n * Image previews on: off is the right default for a real shop, where a file is\\n * often a PDF and a thumbnail adds nothing, but the demo carries a design proof,\\n * and seeing it is the fastest way to understand what the customer gets.\\n * ------------------------------------------------------------------------ *\\\/\\n\\nif ( class_exists( Settings::class ) ) {\\n\\tSettings::update( array( 'image_preview' => true ) );\\n}\\n\\n\\\/* The plugin is not there -- a failed install, a renamed class. Leave a working\\n * store rather than a fatal error in the middle of the preview. *\\\/\\nif ( ! class_exists( Storage::class ) || ! function_exists( 'wc_create_order' ) ) {\\n\\tupdate_option( 'vanam_demo_seeded', 1 );\\n\\treturn;\\n}\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 3. The files\\n *\\n * Generated rather than shipped: a blueprint is one JSON file, and nothing in it\\n * can point at a binary. Real, valid files, so that downloading one from the\\n * preview opens a document rather than an error.\\n * ------------------------------------------------------------------------ *\\\/\\n\\n\\\/**\\n * A one-page PDF with a heading and a few lines, in the base Helvetica every\\n * reader has. The cross-reference offsets are measured, not hard-coded, so the\\n * file stays valid whatever the text is.\\n *\\\/\\n$vanam_pdf = function ( $title, array $lines ) {\\n\\t$escape = function ( $text ) {\\n\\t\\treturn str_replace( array( '\\\\\\\\', '(', ')' ), array( '\\\\\\\\\\\\\\\\', '\\\\\\\\(', '\\\\\\\\)' ), $text );\\n\\t};\\n\\n\\t$content = 'BT \\\/F1 22 Tf 64 740 Td (' . $escape( $title ) . \\\") Tj ET\\\\n\\\";\\n\\t$y       = 700;\\n\\n\\tforeach ( $lines as $line ) {\\n\\t\\t$content .= 'BT \\\/F1 12 Tf 64 ' . $y . ' Td (' . $escape( $line ) . \\\") Tj ET\\\\n\\\";\\n\\t\\t$y       -= 22;\\n\\t}\\n\\n\\t$objects = array(\\n\\t\\t'<< \\\/Type \\\/Catalog \\\/Pages 2 0 R >>',\\n\\t\\t'<< \\\/Type \\\/Pages \\\/Kids [3 0 R] \\\/Count 1 >>',\\n\\t\\t'<< \\\/Type \\\/Page \\\/Parent 2 0 R \\\/MediaBox [0 0 612 792] \\\/Resources << \\\/Font << \\\/F1 4 0 R >> >> \\\/Contents 5 0 R >>',\\n\\t\\t'<< \\\/Type \\\/Font \\\/Subtype \\\/Type1 \\\/BaseFont \\\/Helvetica >>',\\n\\t\\t'<< \\\/Length ' . strlen( $content ) . \\\" >>\\\\nstream\\\\n\\\" . $content . 'endstream',\\n\\t);\\n\\n\\t$pdf     = \\\"%PDF-1.4\\\\n\\\";\\n\\t$offsets = array();\\n\\n\\tforeach ( $objects as $index => $body ) {\\n\\t\\t$offsets[] = strlen( $pdf );\\n\\t\\t$pdf      .= ( $index + 1 ) . \\\" 0 obj\\\\n\\\" . $body . \\\"\\\\nendobj\\\\n\\\";\\n\\t}\\n\\n\\t$xref = strlen( $pdf );\\n\\t$pdf .= \\\"xref\\\\n0 \\\" . ( count( $objects ) + 1 ) . \\\"\\\\n0000000000 65535 f \\\\n\\\";\\n\\n\\tforeach ( $offsets as $offset ) {\\n\\t\\t$pdf .= sprintf( \\\"%010d 00000 n \\\\n\\\", $offset );\\n\\t}\\n\\n\\treturn $pdf . 'trailer << \\\/Size ' . ( count( $objects ) + 1 ) . \\\" \\\/Root 1 0 R >>\\\\nstartxref\\\\n\\\" . $xref . \\\"\\\\n%%EOF\\\\n\\\";\\n};\\n\\n\\\/**\\n * A mock business-card proof, drawn with GD. Empty when GD is missing, and the\\n * caller falls back to a PDF: a proof that cannot be previewed is better than no\\n * proof.\\n *\\\/\\n$vanam_png = function () {\\n\\tif ( ! function_exists( 'imagecreatetruecolor' ) ) {\\n\\t\\treturn '';\\n\\t}\\n\\n\\t$width  = 700;\\n\\t$height = 400;\\n\\t$image  = imagecreatetruecolor( $width, $height );\\n\\n\\t$paper  = imagecolorallocate( $image, 247, 243, 236 );\\n\\t$ink    = imagecolorallocate( $image, 40, 40, 40 );\\n\\t$muted  = imagecolorallocate( $image, 120, 120, 120 );\\n\\t$accent = imagecolorallocate( $image, 127, 84, 179 );\\n\\t$card   = imagecolorallocate( $image, 255, 255, 255 );\\n\\n\\timagefilledrectangle( $image, 0, 0, $width, $height, $paper );\\n\\n\\t\\\/\\\/ The card itself, with a bleed line around it, which is what a proof shows.\\n\\timagefilledrectangle( $image, 120, 90, 580, 330, $card );\\n\\timagerectangle( $image, 110, 80, 590, 340, $muted );\\n\\timagefilledrectangle( $image, 120, 90, 136, 330, $accent );\\n\\n\\timagestring( $image, 5, 170, 150, 'ANNA ROSSI', $ink );\\n\\timagestring( $image, 3, 170, 175, 'Graphic designer', $muted );\\n\\timagestring( $image, 3, 170, 250, 'anna@example.com', $ink );\\n\\timagestring( $image, 3, 170, 270, '+39 050 123456', $ink );\\n\\n\\timagestring( $image, 4, 24, 20, 'DESIGN PROOF - front - 85 x 55 mm', $accent );\\n\\timagestring( $image, 2, 24, 370, 'Grey line = bleed. Check spelling before approving.', $muted );\\n\\n\\tob_start();\\n\\timagepng( $image );\\n\\t$bytes = ob_get_clean();\\n\\timagedestroy( $image );\\n\\n\\treturn (string) $bytes;\\n};\\n\\n\\\/**\\n * Put generated bytes into an owner's protected folder, through the plugin.\\n *\\n * Written to the plugin's own temporary folder first and then adopted, which is\\n * exactly the route a chunked upload takes once its last piece has arrived.\\n *\\n * @return array|null The file fields of an attachment record.\\n *\\\/\\n$vanam_store = function ( $owner_type, $owner_id, $file_name, $bytes, $mime ) {\\n\\t$storage = new Storage();\\n\\t$dir     = $storage->temp_dir();\\n\\n\\tif ( '' === $dir || '' === $bytes ) {\\n\\t\\treturn null;\\n\\t}\\n\\n\\t$temp = $dir . 'demo-' . wp_generate_password( 12, false ) . '.part';\\n\\n\\tif ( false === file_put_contents( $temp, $bytes ) ) {\\n\\t\\treturn null;\\n\\t}\\n\\n\\t$stored = $storage->adopt_for( $owner_type, $owner_id, $temp, $file_name );\\n\\n\\tif ( is_wp_error( $stored ) ) {\\n\\t\\twp_delete_file( $temp );\\n\\t\\treturn null;\\n\\t}\\n\\n\\treturn array(\\n\\t\\t'source'    => Attachment::SOURCE_UPLOAD,\\n\\t\\t'file_path' => $stored,\\n\\t\\t'file_name' => $file_name,\\n\\t\\t'file_size' => strlen( $bytes ),\\n\\t\\t'mime'      => $mime,\\n\\t);\\n};\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 4. Products, each with a file of its own\\n *\\n * One of each visibility, so the three places a product file can appear are all\\n * demonstrated: the product page before buying, the order after buying, both.\\n * ------------------------------------------------------------------------ *\\\/\\n\\n$vanam_catalog = array(\\n\\t'business-cards' => array(\\n\\t\\t'name'  => 'Custom Business Cards',\\n\\t\\t'price' => '39',\\n\\t\\t'file'  => array(\\n\\t\\t\\t'title'       => 'Artwork guidelines',\\n\\t\\t\\t'description' => 'Sizes, bleed and colour profile for the file you send us.',\\n\\t\\t\\t'name'        => 'artwork-guidelines.pdf',\\n\\t\\t\\t'visibility'  => ProductAttachments::VISIBLE_BOTH,\\n\\t\\t\\t'lines'       => array(\\n\\t\\t\\t\\t'Card size: 85 x 55 mm, plus 3 mm bleed on every side.',\\n\\t\\t\\t\\t'Colour: CMYK, FOGRA39. Black text as 100% K.',\\n\\t\\t\\t\\t'Resolution: 300 dpi. Fonts outlined or embedded.',\\n\\t\\t\\t\\t'Keep text at least 4 mm inside the trim line.',\\n\\t\\t\\t),\\n\\t\\t),\\n\\t),\\n\\t'wedding-invitations' => array(\\n\\t\\t'name'  => 'Wedding Invitation Set',\\n\\t\\t'price' => '120',\\n\\t\\t'file'  => array(\\n\\t\\t\\t'title'       => 'Paper and finish samples',\\n\\t\\t\\t'description' => 'The papers, weights and finishes the set can be printed on.',\\n\\t\\t\\t'name'        => 'paper-and-finishes.pdf',\\n\\t\\t\\t'visibility'  => ProductAttachments::VISIBLE_PRODUCT,\\n\\t\\t\\t'lines'       => array(\\n\\t\\t\\t\\t'Cotton 600 g - soft, textured, takes letterpress well.',\\n\\t\\t\\t\\t'Pearl 300 g - light shimmer, best with foil.',\\n\\t\\t\\t\\t'Recycled kraft 350 g - natural, rustic.',\\n\\t\\t\\t\\t'Finishes: gold foil, blind emboss, deckled edge.',\\n\\t\\t\\t),\\n\\t\\t),\\n\\t),\\n\\t'poster-a2' => array(\\n\\t\\t'name'  => 'Poster Print A2',\\n\\t\\t'price' => '25',\\n\\t\\t'file'  => array(\\n\\t\\t\\t'title'       => 'Framing and care guide',\\n\\t\\t\\t'description' => 'How to hang the poster and keep the colours from fading.',\\n\\t\\t\\t'name'        => 'framing-and-care.pdf',\\n\\t\\t\\t'visibility'  => ProductAttachments::VISIBLE_ORDER,\\n\\t\\t\\t'lines'       => array(\\n\\t\\t\\t\\t'Let the print rest flat for 24 hours before framing.',\\n\\t\\t\\t\\t'Use UV-filtering glass away from direct sunlight.',\\n\\t\\t\\t\\t'Handle by the edges; dust with a dry, soft cloth.',\\n\\t\\t\\t),\\n\\t\\t),\\n\\t),\\n);\\n\\n$vanam_product_ids = array();\\n\\nforeach ( $vanam_catalog as $vanam_slug => $vanam_entry ) {\\n\\t$vanam_existing = get_page_by_path( $vanam_slug, OBJECT, 'product' );\\n\\n\\tif ( $vanam_existing ) {\\n\\t\\t$vanam_product_ids[ $vanam_slug ] = $vanam_existing->ID;\\n\\t\\tcontinue;\\n\\t}\\n\\n\\tif ( ! class_exists( 'WC_Product_Simple' ) ) {\\n\\t\\tcontinue;\\n\\t}\\n\\n\\t$vanam_product = new WC_Product_Simple();\\n\\t$vanam_product->set_name( $vanam_entry['name'] );\\n\\t$vanam_product->set_slug( $vanam_slug );\\n\\t$vanam_product->set_status( 'publish' );\\n\\t$vanam_product->set_catalog_visibility( 'visible' );\\n\\t$vanam_product->set_regular_price( $vanam_entry['price'] );\\n\\t$vanam_product->save();\\n\\n\\t$vanam_product_id                 = $vanam_product->get_id();\\n\\t$vanam_product_ids[ $vanam_slug ] = $vanam_product_id;\\n\\n\\t$vanam_file = $vanam_store(\\n\\t\\tStorage::OWNER_PRODUCT,\\n\\t\\t$vanam_product_id,\\n\\t\\t$vanam_entry['file']['name'],\\n\\t\\t$vanam_pdf( $vanam_entry['file']['title'], $vanam_entry['file']['lines'] ),\\n\\t\\t'application\\\/pdf'\\n\\t);\\n\\n\\tif ( $vanam_file ) {\\n\\t\\t( new ProductAttachments() )->save_all(\\n\\t\\t\\t$vanam_product_id,\\n\\t\\t\\tarray(\\n\\t\\t\\t\\tarray_merge(\\n\\t\\t\\t\\t\\t$vanam_file,\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'title'       => $vanam_entry['file']['title'],\\n\\t\\t\\t\\t\\t\\t'description' => $vanam_entry['file']['description'],\\n\\t\\t\\t\\t\\t\\t'visibility'  => $vanam_entry['file']['visibility'],\\n\\t\\t\\t\\t\\t\\t'created'     => current_time( 'mysql' ),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t);\\n\\t}\\n}\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 5. Orders, with files\\n *\\n * All three belong to the signed-in account, so the visitor can open My account\\n * and see them as the customer does. The last one has no files of its own, on\\n * purpose: the Attachments column is easier to read with a zero next to the\\n * other counts.\\n * ------------------------------------------------------------------------ *\\\/\\n\\nwp_update_user(\\n\\tarray(\\n\\t\\t'ID'         => 1,\\n\\t\\t'first_name' => 'Anna',\\n\\t\\t'last_name'  => 'Rossi',\\n\\t)\\n);\\n\\n$vanam_orders = array(\\n\\tarray(\\n\\t\\t'product' => 'business-cards',\\n\\t\\t'status'  => 'processing',\\n\\t\\t'days'    => 1,\\n\\t\\t'files'   => array(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'kind'        => 'proof',\\n\\t\\t\\t\\t'title'       => 'Design proof - front',\\n\\t\\t\\t\\t'description' => 'Please check <strong>spelling and phone number<\\\/strong> before we print. Reply to the order email with any change.',\\n\\t\\t\\t\\t'emails'      => array( 'customer_processing_order', 'customer_invoice' ),\\n\\t\\t\\t),\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'kind'        => 'pdf',\\n\\t\\t\\t\\t'title'       => 'Invoice',\\n\\t\\t\\t\\t'name'        => 'invoice-1001.pdf',\\n\\t\\t\\t\\t'description' => '',\\n\\t\\t\\t\\t'emails'      => array( 'customer_invoice', 'customer_completed_order' ),\\n\\t\\t\\t\\t'lines'       => array(\\n\\t\\t\\t\\t\\t'Invoice 1001 - Custom Business Cards x 1',\\n\\t\\t\\t\\t\\t'Subtotal: EUR 39.00',\\n\\t\\t\\t\\t\\t'VAT (22%): EUR 8.58',\\n\\t\\t\\t\\t\\t'Total: EUR 47.58',\\n\\t\\t\\t\\t),\\n\\t\\t\\t),\\n\\t\\t),\\n\\t\\t'email_block' => 'Hi [customer_name], your files for order [order_number] are ready. You can also find them any time on [order_page_link].',\\n\\t),\\n\\tarray(\\n\\t\\t'product' => 'poster-a2',\\n\\t\\t'status'  => 'completed',\\n\\t\\t'days'    => 6,\\n\\t\\t'files'   => array(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'kind'        => 'pdf',\\n\\t\\t\\t\\t'title'       => 'Certificate of authenticity',\\n\\t\\t\\t\\t'name'        => 'certificate-of-authenticity.pdf',\\n\\t\\t\\t\\t'description' => 'Signed and numbered. Keep it with the print.',\\n\\t\\t\\t\\t'emails'      => array( 'customer_completed_order' ),\\n\\t\\t\\t\\t'lines'       => array(\\n\\t\\t\\t\\t\\t'This print is number 12 of a limited run of 50.',\\n\\t\\t\\t\\t\\t'Printed on archival cotton paper with pigment inks.',\\n\\t\\t\\t\\t\\t'Signed by the artist.',\\n\\t\\t\\t\\t),\\n\\t\\t\\t),\\n\\t\\t),\\n\\t\\t'email_block' => '',\\n\\t),\\n\\tarray(\\n\\t\\t'product'     => 'wedding-invitations',\\n\\t\\t'status'      => 'on-hold',\\n\\t\\t'days'        => 0,\\n\\t\\t'files'       => array(),\\n\\t\\t'email_block' => '',\\n\\t),\\n);\\n\\n$vanam_attachments = new OrderAttachments();\\n\\nforeach ( $vanam_orders as $vanam_data ) {\\n\\tif ( empty( $vanam_product_ids[ $vanam_data['product'] ] ) ) {\\n\\t\\tcontinue;\\n\\t}\\n\\n\\t$vanam_order = wc_create_order( array( 'customer_id' => 1 ) );\\n\\n\\tif ( is_wp_error( $vanam_order ) ) {\\n\\t\\tcontinue;\\n\\t}\\n\\n\\t$vanam_product = wc_get_product( $vanam_product_ids[ $vanam_data['product'] ] );\\n\\tif ( $vanam_product ) {\\n\\t\\t$vanam_order->add_product( $vanam_product, 1 );\\n\\t}\\n\\n\\t$vanam_address = array(\\n\\t\\t'first_name' => 'Anna',\\n\\t\\t'last_name'  => 'Rossi',\\n\\t\\t'email'      => 'anna@example.com',\\n\\t\\t'address_1'  => 'Via Roma 1',\\n\\t\\t'city'       => 'Pisa',\\n\\t\\t'postcode'   => '56100',\\n\\t\\t'country'    => 'IT',\\n\\t);\\n\\t$vanam_order->set_address( $vanam_address, 'billing' );\\n\\tunset( $vanam_address['email'] );\\n\\t$vanam_order->set_address( $vanam_address, 'shipping' );\\n\\n\\t$vanam_order->set_payment_method( 'cod' );\\n\\t$vanam_order->set_payment_method_title( 'Cash on delivery' );\\n\\t$vanam_order->set_date_created( time() - (int) $vanam_data['days'] * DAY_IN_SECONDS );\\n\\t$vanam_order->calculate_totals();\\n\\t$vanam_order->set_status( $vanam_data['status'] );\\n\\t$vanam_order->save();\\n\\n\\t$vanam_order_id = $vanam_order->get_id();\\n\\n\\tforeach ( $vanam_data['files'] as $vanam_spec ) {\\n\\t\\t$vanam_file = null;\\n\\n\\t\\tif ( 'proof' === $vanam_spec['kind'] ) {\\n\\t\\t\\t$vanam_file = $vanam_store( Storage::OWNER_ORDER, $vanam_order_id, 'business-card-proof.png', $vanam_png(), 'image\\\/png' );\\n\\t\\t}\\n\\n\\t\\t\\\/\\\/ A PDF when asked for one, and also when the proof could not be drawn.\\n\\t\\tif ( ! $vanam_file ) {\\n\\t\\t\\t$vanam_name  = isset( $vanam_spec['name'] ) ? $vanam_spec['name'] : 'business-card-proof.pdf';\\n\\t\\t\\t$vanam_lines = isset( $vanam_spec['lines'] ) ? $vanam_spec['lines'] : array( 'Anna Rossi - Graphic designer', 'anna@example.com - +39 050 123456' );\\n\\t\\t\\t$vanam_file  = $vanam_store( Storage::OWNER_ORDER, $vanam_order_id, $vanam_name, $vanam_pdf( $vanam_spec['title'], $vanam_lines ), 'application\\\/pdf' );\\n\\t\\t}\\n\\n\\t\\tif ( ! $vanam_file ) {\\n\\t\\t\\tcontinue;\\n\\t\\t}\\n\\n\\t\\t$vanam_attachments->add(\\n\\t\\t\\t$vanam_order,\\n\\t\\t\\tarray_merge(\\n\\t\\t\\t\\t$vanam_file,\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'title'       => $vanam_spec['title'],\\n\\t\\t\\t\\t\\t'description' => $vanam_spec['description'],\\n\\t\\t\\t\\t\\t'emails'      => $vanam_spec['emails'],\\n\\t\\t\\t\\t)\\n\\t\\t\\t)\\n\\t\\t);\\n\\t}\\n\\n\\tif ( '' !== $vanam_data['email_block'] ) {\\n\\t\\t$vanam_attachments->save_options(\\n\\t\\t\\t$vanam_order,\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'embed_enabled' => true,\\n\\t\\t\\t\\t'embed_text'    => $vanam_data['email_block'],\\n\\t\\t\\t)\\n\\t\\t);\\n\\t}\\n}\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 6. Make the customer's pages reachable\\n *\\n * The visitor will click through to My account -> Orders -> View order, and\\n * those endpoints are rewrite rules. They are normally flushed on a later\\n * request; this preview has no later request to wait for.\\n * ------------------------------------------------------------------------ *\\\/\\n\\nflush_rewrite_rules();\\n\\n\\\/* ---------------------------------------------------------------------------\\n * 7. Freemius\\n *\\n * Skip the connection, so no opt-in screen or notice greets a visitor who only\\n * wanted to see the plugin. Guarded: Freemius state must never be able to break\\n * the preview.\\n * ------------------------------------------------------------------------ *\\\/\\n\\nif ( function_exists( 'vanam_fs' ) ) {\\n\\ttry {\\n\\t\\tif ( ! vanam_fs()->is_registered() ) {\\n\\t\\t\\tvanam_fs()->skip_connection();\\n\\t\\t}\\n\\t} catch ( \\\\Exception $e ) {\\n\\t\\t\\\/\\\/ Nothing to do: the preview works without it.\\n\\t}\\n}\\n\\n\\\/* Cancel Freemius' post-activation redirect.\\n *\\n * Freemius marks a fresh activation with a transient and, on the next admin page\\n * load, redirects to the plugin's own first page -- which would hijack the\\n * landing page and drop the visitor on Settings instead of the orders. The\\n * transient is what is_plugin_activation() reads, so removing it is enough;\\n * skip_connection() above does not clear it.\\n *\\\/\\ndelete_transient( 'fs_plugin_vanquish-attach-me-for-woocommerce_activated' );\\n\\nupdate_option( 'vanam_demo_seeded', 1 );\\n\"}]}"}},"all_blocks":[],"tagged_versions":["1.0.0","1.0.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3696741,"resolution":"1","location":"assets","locale":"","width":1654,"height":2173},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3696741,"resolution":"2","location":"assets","locale":"","width":1498,"height":1639},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3696741,"resolution":"3","location":"assets","locale":"","width":1515,"height":1004},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3696741,"resolution":"4","location":"assets","locale":"","width":1345,"height":901},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3696741,"resolution":"5","location":"assets","locale":"","width":1579,"height":1191}},"screenshots":{"1":"Files on a product: where the customer sees each one, which variations it applies to, and which order emails carry it. Availability, roles, download limits and the disclaimer are Premium.","2":"Files on an order, the block of download links that goes into the order emails, and \u2014 in Premium \u2014 a message written by hand with the files to send with it.","3":"The attachments tab on the product page, as a customer sees it before buying.","4":"My account: a \"View attachments\" button on each order that has files.","5":"The customer's order page: the files attached to the order, and the ones that came with the product they bought."}},"plugin_section":[],"plugin_tags":[1346,5440,88,280841,286],"plugin_category":[45,50],"plugin_contributors":[78154,269507],"plugin_business_model":[],"class_list":["post-366308","plugin","type-plugin","status-publish","hentry","plugin_tags-attachments","plugin_tags-downloads","plugin_tags-files","plugin_tags-order-attachments","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_category-media","plugin_contributors-freemius","plugin_contributors-vanquish83","plugin_committers-vanquish83"],"banners":{"banner":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/banner-772x250.png?rev=3696741","banner_2x":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/banner-1544x500.png?rev=3696741","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/icon-128x128.png?rev=3696741","icon_2x":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/icon-256x256.png?rev=3696741","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/screenshot-1.png?rev=3696741","caption":"Files on a product: where the customer sees each one, which variations it applies to, and which order emails carry it. Availability, roles, download limits and the disclaimer are Premium."},{"src":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/screenshot-2.png?rev=3696741","caption":"Files on an order, the block of download links that goes into the order emails, and \u2014 in Premium \u2014 a message written by hand with the files to send with it."},{"src":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/screenshot-3.png?rev=3696741","caption":"The attachments tab on the product page, as a customer sees it before buying."},{"src":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/screenshot-4.png?rev=3696741","caption":"My account: a \"View attachments\" button on each order that has files."},{"src":"https:\/\/ps.w.org\/vanquish-attach-me-for-woocommerce\/assets\/screenshot-5.png?rev=3696741","caption":"The customer's order page: the files attached to the order, and the ones that came with the product they bought."}],"raw_content":"<!--section=description-->\n<p>Vanquish Attach Me for WooCommerce puts files where an order or a product needs them: a proof to approve, an invoice, a manual, a certificate, a design to sign off. You upload the file (or pick one from the media library, or point at a URL), and the customer finds it on their order page, in the order emails, or on the product page \u2014 whichever you choose, per file.<\/p>\n\n<p>Uploaded files are not left where a URL can find them: they sit behind server rules and an unguessable path, and they are served through an endpoint that checks who is asking \u2014 the customer who placed that order, or somebody who can manage the shop. That is not a setting you can turn off \u2014 it is the only correct way to serve a file attached to an order, so it is simply how the plugin works.<\/p>\n\n<p>Large files go up in pieces, so your server's per-request upload limit is not the limit on what you can attach.<\/p>\n\n<h4>Free features<\/h4>\n\n<ul>\n<li>Attach any number of files to an order: upload them, choose them from the media library, or link to an external URL.<\/li>\n<li>A title and a description for each file, shown to the customer.<\/li>\n<li>Attach files to products, with a choice of which variations they apply to.<\/li>\n<li>Show a product's files on the product page, on the order page after buying, or both.<\/li>\n<li>Files attached to the standard WooCommerce emails (processing, completed, invoice, refunded) and to custom emails registered by other plugins, chosen per file.<\/li>\n<li>A block inside the order emails with your own wording and the download links, with placeholders for <code>[order_number]<\/code>, <code>[customer_name]<\/code> and <code>[order_page_link]<\/code>.<\/li>\n<li>Hide a file while the order is in a given status.<\/li>\n<li>Image previews, at a thumbnail size you choose, and a configurable position for the attachments box on the order page.<\/li>\n<li>A \"View attachments\" button in the customer's order list, an attachments tab on the product page.<\/li>\n<li>An attachments column in the admin orders list, a \"Manage\" modal for handling them without opening the order, a filter for orders that have attachments, and a bulk action to delete them.<\/li>\n<li>Every customer-facing text is editable \u2014 and, with WPML or Polylang active, editable per language.<\/li>\n<li>Template overrides from your theme, HPOS (High-Performance Order Storage) support.<\/li>\n<li>Migrates automatically from the legacy \"WooCommerce Attach Me!\" (CodeCanyon) plugin: settings, product attachments and every order's files.<\/li>\n<\/ul>\n\n<h4>Premium features<\/h4>\n\n<ul>\n<li><strong>Bulk product rules<\/strong> \u2014 one rule attaches a file to many products or categories at once, including or excluding what you pick, with or without child categories. No opening a thousand products.<\/li>\n<li><strong>Customer approval<\/strong> \u2014 ask the customer to approve a file from their own order page, with a comment box. Their answer can move the order to another status, email you, and leave an order note. Re-approval and per-file rules for when the comment is offered.<\/li>\n<li><strong>Expiry<\/strong> \u2014 a file that stops being available on a fixed date, or a set time after the order. It disappears from the order page, the download link stops working, and the file can be deleted from the server automatically.<\/li>\n<li><strong>Download limits and a required disclaimer<\/strong> \u2014 a maximum number of downloads per file, and terms the customer must accept before the first one.<\/li>\n<li><strong>Visibility by user role<\/strong>, including visitors who are not signed in, on product attachments and bulk rules.<\/li>\n<li><strong>Automatic email files<\/strong> \u2014 a file that goes out with every copy of a chosen email, whatever the order contains: terms on every invoice, a returns form on every completed order. Any email WooCommerce sends, including new account and new order.<\/li>\n<li><strong>A message written by hand<\/strong> \u2014 send the customer an email from the order screen, with whichever of that order's files you choose attached or linked, in your shop's own email template. It leaves an order note saying what went out.<\/li>\n<li><strong>A library of preset texts<\/strong> \u2014 messages written once and offered under every editor, so a shop that says the same thing on every order writes it once.<\/li>\n<li><strong>CSV import<\/strong> \u2014 one row, one link, one order, for a shop that already produces its files somewhere else.<\/li>\n<li><strong>My Account \u2192 Downloads<\/strong> \u2014 the attachments listed on the page that claims to list everything the customer can download, with a column for files still waiting for approval.<\/li>\n<li><strong>Shortcodes<\/strong> \u2014 put the attachments, or a single download link, on a page of your own. Each shows nothing at all unless the person reading the page is entitled to that order.<\/li>\n<li><strong>Files only in the emails<\/strong> \u2014 attached to the notification but never shown on the site.<\/li>\n<li><strong>Copy the download link<\/strong> with one click, on the customer's side.<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p><strong>The free version does not send any data to external services.<\/strong> Files you upload stay on your own server, and the download links point at your own site.<\/p>\n\n<p>This plugin uses <strong>Freemius<\/strong> to manage licensing and updates for the premium version, and to offer an optional opt-in when you first activate it. Nothing is sent unless you opt in or activate a licence; if you do, Freemius receives your site URL, WordPress and PHP versions and your administrator email address, in order to deliver updates and support. See <a href=\"https:\/\/freemius.com\/\">freemius.com<\/a>, its <a href=\"https:\/\/freemius.com\/terms\/\">terms<\/a> and its <a href=\"https:\/\/freemius.com\/privacy\/\">privacy policy<\/a>.<\/p>\n\n<p>The <strong>premium version<\/strong> adds no external services of its own: bulk rules, approval, expiry, automatic emails and the manual notification all run on your site, and the emails go out through WooCommerce.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin files to the <code>\/wp-content\/plugins\/vanquish-attach-me-for-woocommerce<\/code> directory, or install the plugin through the WordPress plugins screen.<\/li>\n<li>Activate the plugin through the 'Plugins' screen in WordPress.<\/li>\n<li>Make sure WooCommerce is installed and active.<\/li>\n<li>Configure the plugin from the \"Attach Me\" menu.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"where%20are%20the%20uploaded%20files%20kept%3F\"><h3>Where are the uploaded files kept?<\/h3><\/dt>\n<dd><p>In a folder inside your uploads directory, three ways round at once. The plugin writes the rules that close a directory to direct access, in the forms Apache and IIS understand. Because nginx honours neither, the path is unguessable as well: each order's files sit under a directory name derived from a secret the plugin generates for your site, rather than from the order number, and every stored file keeps its own name with twelve random characters added.<\/p>\n\n<p>And the way in is the only way in: every download goes through a signed link, which checks whether the person asking placed that order or can manage the shop.<\/p>\n\n<p>There is no switch for any of this. A file attached to an order is private by definition, and an option to serve it insecurely would only ever be turned on by mistake.<\/p><\/dd>\n<dt id=\"can%20i%20attach%20a%20file%20that%20is%20bigger%20than%20my%20server%27s%20upload%20limit%3F\"><h3>Can I attach a file that is bigger than my server's upload limit?<\/h3><\/dt>\n<dd><p>Yes. Files are sent to the server in pieces small enough to clear <code>upload_max_filesize<\/code> and <code>post_max_size<\/code>, so neither caps what you can attach. The screen shows the maximum it will accept.<\/p><\/dd>\n<dt id=\"what%20about%20files%20in%20the%20media%20library%2C%20or%20on%20another%20server%3F\"><h3>What about files in the media library, or on another server?<\/h3><\/dt>\n<dd><p>Both work. A media library file keeps its own public address in <code>wp-content\/uploads<\/code> \u2014 that is how the media library works \u2014 so if a file must not be reachable by anyone holding its URL, upload it through the plugin instead of adding it to the library. An external URL is only ever a link: the plugin does not fetch somebody else's file to attach it to your emails.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20hpos%20%28high-performance%20order%20storage%29%3F\"><h3>Does it work with HPOS (High-Performance Order Storage)?<\/h3><\/dt>\n<dd><p>Yes, with HPOS and with the classic order storage.<\/p><\/dd>\n<dt id=\"i%20am%20migrating%20from%20the%20codecanyon%20%22woocommerce%20attach%20me%21%22%20plugin.%20do%20i%20lose%20anything%3F\"><h3>I am migrating from the CodeCanyon \"WooCommerce Attach Me!\" plugin. Do I lose anything?<\/h3><\/dt>\n<dd><p>No. Your settings, your texts, the files on your products and the files on every order are converted for you. The importer runs from <strong>Attach Me \u2192 Settings \u2192 Import old data<\/strong>, shows how much is left as it goes, and finishes in the background if you close the tab. An order is also converted the first time somebody opens it, whatever happened before.<\/p>\n\n<p>Your files stay where they are on disk and keep working, and the old plugin's download links are still understood. A customer with an account follows one after signing in, and so do you.<\/p>\n\n<p>A link to a <strong>guest<\/strong> order's file needs one thing more than the link. Those old URLs were built as <code>?wcam_id=&lt;order number&gt;-&lt;0, 1, 2...&gt;<\/code>, which anybody can type out, and a guest order has no account to check the visitor against \u2014 so on its own such a link is not proof of anything, and is refused. It works when the request also carries the order key, which is the token WooCommerce puts in the order links it emails: following the file from the customer's own order page works, pasting the bare old URL does not.<\/p>\n\n<p>The old plugin's data is left in place rather than deleted, so nothing is destroyed by importing. You can keep both installed while you check the result, then deactivate the old one.<\/p><\/dd>\n<dt id=\"do%20the%20premium%20features%20change%20how%20the%20free%20ones%20behave%3F\"><h3>Do the premium features change how the free ones behave?<\/h3><\/dt>\n<dd><p>No. The premium package is the same plugin with more in it. Everything described above under \"free features\" works the same either way, and the settings you have already made are untouched by activating a licence.<\/p><\/dd>\n<dt id=\"can%20i%20change%20the%20wording%20the%20customer%20sees%3F\"><h3>Can I change the wording the customer sees?<\/h3><\/dt>\n<dd><p>Yes, all of it, under <strong>Attach Me \u2192 Settings<\/strong>: the box title, the button, the empty message, the email block. With WPML or Polylang active, each text has one input per language.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20uninstall%20the%20plugin%3F\"><h3>What happens if I uninstall the plugin?<\/h3><\/dt>\n<dd><p>Nothing of yours is removed. Your settings and your wording stay, the files attached to your orders and products stay, and the files on disk are left alone \u2014 so reinstalling puts you back exactly where you were. Only two things go: the plugin's scheduled events, which would otherwise keep firing for a plugin that is no longer installed, and its caches, which would expire on their own anyway.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Fixed: on stores using the classic order storage (HPOS switched off), the importer counted every order as legacy data, showed the import notice on sites that never had the old plugin, and could keep running without finishing.<\/li>\n<li>Fixed: the automatic deletion of expired files (Premium) stopped after the first 200 orders with attachments.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release. A rewrite from scratch of the CodeCanyon \"WooCommerce Attach Me!\" plugin, with an automatic importer for its settings, product attachments and order files.<\/li>\n<li>Uploaded files are served from a protected folder through a signed, access-checked endpoint, always \u2014 not as an option.<\/li>\n<li>Chunked uploads, so the server's per-request limit is not the limit on attachment size.<\/li>\n<li>HPOS support, template overrides, and every customer-facing text editable per language with WPML or Polylang.<\/li>\n<\/ul>","raw_excerpt":"Attach files to WooCommerce orders and products, show them to the customer and send them with the order emails.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/366308","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=366308"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/vanquish83"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=366308"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=366308"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=366308"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=366308"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=366308"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=366308"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}