{"id":399214,"date":"2026-11-10T11:09:33","date_gmt":"2026-11-10T11:09:33","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/wpreturns\/"},"modified":"2026-11-10T11:31:13","modified_gmt":"2026-11-10T11:31:13","slug":"devdiggers-returns-for-woocommerce","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/devdiggers-returns-for-woocommerce\/","author":20777317,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1.4","requires":"6.5","requires_php":"7.4","requires_plugins":null,"header_name":"DevDiggers Returns for WooCommerce","header_author":"DevDiggers","header_description":"Let customers request returns and cancellations from My Account or a guest returns portal, add the EU \"Withdraw from contract here\" button, and handle every request, photo, message and refund from one screen.","last_updated":"2026-11-10 11:31:13","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wpreturns.com\/","header_author_uri":"https:\/\/devdiggers.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":100,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"devdiggers","date":"2026-11-10 11:31:13","revision":3794245}},"upgrade_notice":{"1.0.0":"<p>First release. After activating, run the setup wizard and check the Return Policy and EU Withdrawal tabs.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.gif":{"filename":"icon-128x128.gif","revision":3794198,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.gif":{"filename":"icon-256x256.gif","revision":3794198,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500-rtl.png":{"filename":"banner-1544x500-rtl.png","revision":3794198,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3794198,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250-rtl.png":{"filename":"banner-772x250-rtl.png","revision":3794198,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3794198,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3794245,"resolution":false,"location":"assets","locale":"","contents":"{\"$schema\":\"https:\\\/\\\/playground.wordpress.net\\\/blueprint-schema.json\",\"meta\":{\"title\":\"DevDiggers Returns for WooCommerce demo\",\"description\":\"An apparel shop handling returns, cancellations and EU withdrawals, with requests in every status, the customer returns page and the guest returns portal.\",\"author\":\"devdiggers\",\"categories\":[\"WooCommerce\"]},\"landingPage\":\"\\\/wp-admin\\\/admin.php?page=ddwcwr-dashboard&menu=requests\",\"preferredVersions\":{\"php\":\"8.3\",\"wp\":\"latest\"},\"features\":{\"networking\":true},\"steps\":[{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"woocommerce\"},\"options\":{\"activate\":true}},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"devdiggers-returns-for-woocommerce\"},\"options\":{\"activate\":true}},{\"step\":\"installTheme\",\"themeData\":{\"resource\":\"wordpress.org\\\/themes\",\"slug\":\"kadence\"},\"options\":{\"activate\":true}},{\"step\":\"setSiteOptions\",\"options\":{\"woocommerce_onboarding_profile\":{\"skipped\":true},\"woocommerce_task_list_hidden\":\"yes\",\"woocommerce_task_list_complete\":\"yes\",\"woocommerce_show_marketplace_suggestions\":\"no\",\"woocommerce_allow_tracking\":\"no\",\"woocommerce_coming_soon\":\"no\",\"ddfw_setup_wizard_completed_devdiggers-returns-for-woocommerce\":true,\"ddwcwr_enabled\":\"yes\"}},{\"step\":\"runPHP\",\"code\":\"<?php\\nrequire '\\\/wordpress\\\/wp-load.php';\\nrequire_once ABSPATH . 'wp-admin\\\/includes\\\/image.php';\\n\\nuse DDWCWPReturns\\\\Helper\\\\Request\\\\DDWCWR_Request_Helper;\\nuse DDWCWPReturns\\\\Helper\\\\Resolution\\\\DDWCWR_Resolution_Helper;\\nuse DDWCWPReturns\\\\Helper\\\\Label\\\\DDWCWR_Label_Helper;\\nuse DDWCWPReturns\\\\Helper\\\\Upload\\\\DDWCWR_Upload_Helper;\\n\\ndelete_transient( '_wc_activation_redirect' );\\ndelete_transient( 'ddfw_activation_redirect_devdiggers-returns-for-woocommerce' );\\nadd_filter( 'pre_wp_mail', '__return_true' ); \\\/\\\/ The seed sends no mail.\\nwp_set_current_user( 1 );\\n\\nupdate_option( 'blogname', 'Loom & Field' );\\nupdate_option( 'blogdescription', 'Everyday clothing in linen, cotton and wool' );\\nupdate_option( 'woocommerce_currency', 'USD' );\\nupdate_option( 'woocommerce_store_address', '1220 SW Morrison Street' );\\nupdate_option( 'woocommerce_store_city', 'Portland' );\\nupdate_option( 'woocommerce_default_country', 'US:OR' );\\nupdate_option( 'woocommerce_store_postcode', '97205' );\\nupdate_option( 'woocommerce_email_from_name', 'Loom & Field' );\\nupdate_option( 'woocommerce_email_auto_sync_with_theme', 'no' );\\nupdate_option( 'woocommerce_email_base_color', '#2F4BE8' );\\nwp_update_user( [ 'ID' => 1, 'display_name' => 'Tillie Warren', 'first_name' => 'Tillie', 'last_name' => 'Warren', 'user_email' => 'admin@localhost.com' ] );\\n\\n\\\/\\\/ ---- Products: the WooCommerce fashion sample photos (bundled pattern photos if a download fails) ----\\n$wc_img  = 'https:\\\/\\\/woocommerce.com\\\/wp-content\\\/plugins\\\/wccom-plugins\\\/sample-products\\\/images\\\/';\\n$catalog = [\\n\\t'overshirt' => [ 'Linen Overshirt', 84, '167113864-14d59cf5-1233-4053-8193-070413ea3434', 'Washed linen in ecru with two chest pockets.', 'Shirts' ],\\n\\t'cord'      => [ 'Cord Overshirt in Moss', 78, '167113801-fd8243b7-8465-4f82-86c1-2c54797fe296', 'Soft needlecord in moss green.', 'Shirts' ],\\n\\t'sweater'   => [ 'Mohair Crew Sweater', 96, '167113823-3f0757ff-c7c2-44d0-a1e9-0b006772b39a', 'Brushed mohair blend in sage.', 'Knitwear' ],\\n\\t'dress'     => [ 'Chambray Shirt Dress', 88, '167113836-efdbde32-7863-4a24-9d2d-979025b51260', 'Midi chambray with a tie belt.', 'Dresses' ],\\n\\t'jacket'    => [ 'Boxy Twill Jacket', 118, '167113817-0fd3751e-b81b-4def-be53-040d8fa049f2', 'Cropped black cotton twill.', 'Outerwear' ],\\n\\t'poplin'    => [ 'Garment-Dyed Poplin Shirt', 64, '167113854-b669deff-4c3e-4bb0-b00f-96cfbdc4087e', 'Cotton poplin, dyed after sewing.', 'Shirts' ],\\n\\t'cardigan'  => [ 'Oat Wool Cardigan', 92, '167113851-84b1da86-5c2a-4cce-9deb-4444848778d4', 'Chunky lambswool knit in oat.', 'Knitwear' ],\\n\\t'derby'     => [ 'Lug Sole Derby', 140, '167113861-531ebbcd-f9b5-4c18-b5c7-a878d5017ca2', 'Leather derby on a light lug sole.', 'Shoes' ],\\n\\t'hat'       => [ 'Canvas Bucket Hat', 32, '167113811-0be977aa-edfe-4a09-b36d-a62f02de4a29', 'Washed navy canvas.', 'Accessories' ],\\n\\t'socks'     => [ 'Rib Socks, Set of Two', 18, '167113857-839785e4-d25a-45f0-b647-cd8d9be8bc2d', 'Cotton rib socks.', 'Socks' ],\\n];\\n$fallback = WP_PLUGIN_DIR . '\\\/woocommerce\\\/assets\\\/images\\\/pattern-placeholders\\\/man-person-winter-photography-statue-coat.png';\\n$ids      = [];\\n$photos   = [];\\nforeach ( $catalog as $key => $c ) {\\n\\t$res  = wp_remote_get( $wc_img . $c[2] . '.jpeg', [ 'timeout' => 30 ] );\\n\\t$body = 200 === wp_remote_retrieve_response_code( $res ) ? wp_remote_retrieve_body( $res ) : '';\\n\\t$file = $body ? sanitize_title( $c[0] ) . '.jpg' : 'placeholder.png';\\n\\t$up   = wp_upload_bits( $file, null, $body ? $body : file_get_contents( $fallback ) );\\n\\t$att  = wp_insert_attachment( [ 'post_mime_type' => $body ? 'image\\\/jpeg' : 'image\\\/png', 'post_title' => $c[0], 'post_status' => 'inherit' ], $up['file'] );\\n\\twp_update_attachment_metadata( $att, wp_generate_attachment_metadata( $att, $up['file'] ) );\\n\\t$term = term_exists( $c[4], 'product_cat' ) ?: wp_insert_term( $c[4], 'product_cat' );\\n\\t$prod = new WC_Product_Simple();\\n\\t$prod->set_name( $c[0] );\\n\\t$prod->set_regular_price( $c[1] );\\n\\t$prod->set_short_description( $c[3] );\\n\\t$prod->set_description( $c[3] );\\n\\t$prod->set_image_id( $att );\\n\\t$prod->set_category_ids( [ (int) $term['term_id'] ] );\\n\\t$prod->set_status( 'publish' );\\n\\t$ids[ $key ]    = $prod->save();\\n\\t$photos[ $key ] = $up['file'];\\n}\\n\\n\\\/\\\/ ---- Free plugin settings (every free feature on) ----\\n$policy = wp_insert_post( [ 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => 'Return policy', 'post_content' => '<!-- wp:paragraph --><p>Send anything back within 30 days of delivery for a full refund, unworn and with its tags. Socks are final sale. In the EU and EEA you can also withdraw within 14 days with the button in our footer.<\\\/p><!-- \\\/wp:paragraph -->' ] );\\n$on = [ 'enabled', 'allow_refund', 'allow_cancellation', 'allow_uploads', 'show_policy_product', 'show_policy_checkout', 'restock_on_receive', 'withdrawal_enabled', 'withdrawal_footer_link', 'withdrawal_in_emails', 'withdrawal_model_form' ];\\nforeach ( array_fill_keys( $on, 'yes' ) + [ 'return_window_days' => 30, 'window_from' => 'completed', 'withdrawal_scope' => 'eu', 'withdrawal_days' => 14, 'refund_via_gateway' => '', 'policy_page_id' => $policy, 'final_sale_categories' => [ get_term_by( 'name', 'Socks', 'product_cat' )->term_id ] ] as $k => $v ) {\\n\\tupdate_option( 'ddwcwr_' . $k, $v );\\n}\\nDDWCWR_Install::ddwcwr_create_pages();\\ninclude DDWCWR_PLUGIN_FILE . 'includes\\\/globals-variables.php';\\n\\n\\\/\\\/ ---- Customers: Amara has the richest history; EU shoppers can withdraw ----\\n\\\/\\\/ key => [ login ('' = guest), first, last, country, city, postcode, street, state, portrait ].\\n$people = [\\n\\t'amara'   => [ 'amara', 'Amara', 'Okafor', 'US', 'Portland', '97209', '418 NW Larch Street', 'OR', 'women\\\/44' ],\\n\\t'amarade' => [ 'amara', 'Amara', 'Okafor', 'DE', 'Berlin', '10115', 'Invalidenstra\\u00dfe 42', '', 'women\\\/44' ],\\n\\t'lena'    => [ '', 'Lena', 'Fischer', 'DE', 'Munich', '80331', 'Sendlinger Stra\\u00dfe 18', '', 'women\\\/65' ],\\n\\t'lucas'   => [ 'lucas', 'Lucas', 'Martin', 'FR', 'Lyon', '69002', '14 Rue de la R\\u00e9publique', '', 'men\\\/32' ],\\n\\t'sofia'   => [ '', 'Sofia', 'Rossi', 'IT', 'Milan', '20121', 'Via Manzoni 7', 'MI', 'women\\\/24' ],\\n\\t'daan'    => [ '', 'Daan', 'de Vries', 'NL', 'Utrecht', '3511 LX', 'Oudegracht 120', '', 'men\\\/46' ],\\n\\t'maya'    => [ 'maya', 'Maya', 'Patel', 'US', 'Austin', '78701', '501 Congress Avenue', 'TX', 'women\\\/90' ],\\n\\t'ethan'   => [ 'ethan', 'Ethan', 'Brooks', 'US', 'Denver', '80202', '1600 Wynkoop Street', 'CO', 'men\\\/52' ],\\n\\t'olivia'  => [ 'olivia', 'Olivia', 'Chen', 'US', 'Seattle', '98101', '400 Pine Street', 'WA', 'women\\\/12' ],\\n\\t'noah'    => [ 'noah', 'Noah', 'Williams', 'US', 'Chicago', '60607', '900 W Randolph Street', 'IL', 'men\\\/75' ],\\n\\t'grace'   => [ 'grace', 'Grace', 'Kim', 'US', 'Boston', '02116', '230 Newbury Street', 'MA', 'women\\\/33' ],\\n\\t'liam'    => [ 'liam', 'Liam', 'Walsh', 'IE', 'Dublin', 'D02 X285', '12 Grafton Street', '', 'men\\\/22' ],\\n\\t'hannah'  => [ 'hannah', 'Hannah', 'Berg', 'AT', 'Vienna', '1010', 'K\\u00e4rntner Stra\\u00dfe 21', '', 'women\\\/50' ],\\n\\t'james'   => [ '', 'James', 'Carter', 'US', 'Nashville', '37203', '200 Broadway', 'TN', 'men\\\/86' ],\\n];\\n$users = [];\\n$faces = [ 'admin@localhost.com' => 'women\\\/68' ];\\nforeach ( $people as $p ) {\\n\\t$faces[ strtolower( $p[1] . '.' . str_replace( ' ', '', $p[2] ) ) . '@example.com' ] = $p[8];\\n\\tif ( $p[0] && ! isset( $users[ $p[0] ] ) ) {\\n\\t\\t$users[ $p[0] ] = wp_insert_user( [ 'user_login' => $p[0], 'user_pass' => 'password', 'user_email' => strtolower( $p[1] . '.' . str_replace( ' ', '', $p[2] ) ) . '@example.com', 'first_name' => $p[1], 'last_name' => $p[2], 'display_name' => $p[1] . ' ' . $p[2], 'role' => 'customer' ] );\\n\\t}\\n}\\n\\nwp_mkdir_p( WPMU_PLUGIN_DIR );\\nfile_put_contents(\\n\\tWPMU_PLUGIN_DIR . '\\\/demo-avatars.php',\\n\\t\\\"<?php\\\\n\\\/\\\/ Live Preview only: show a portrait for each demo person.\\\\nadd_filter( 'pre_get_avatar_data', function ( \\\\$args, \\\\$id ) {\\\\n\\\\t\\\\$faces = \\\" . var_export( $faces, true ) . \\\";\\\\n\\\\t\\\\$email = '';\\\\n\\\\tif ( is_numeric( \\\\$id ) ) { \\\\$u = get_userdata( (int) \\\\$id ); \\\\$email = \\\\$u ? \\\\$u->user_email : ''; }\\\\n\\\\telseif ( is_string( \\\\$id ) ) { \\\\$email = \\\\$id; }\\\\n\\\\telseif ( \\\\$id instanceof WP_User ) { \\\\$email = \\\\$id->user_email; }\\\\n\\\\telseif ( \\\\$id instanceof WP_Comment ) { \\\\$email = \\\\$id->comment_author_email; }\\\\n\\\\t\\\\$email = strtolower( \\\\$email );\\\\n\\\\tif ( isset( \\\\$faces[ \\\\$email ] ) ) { \\\\$args['url'] = 'https:\\\/\\\/randomuser.me\\\/api\\\/portraits\\\/' . \\\\$faces[ \\\\$email ] . '.jpg'; \\\\$args['found_avatar'] = true; }\\\\n\\\\treturn \\\\$args;\\\\n}, 10, 2 );\\\\n\\\"\\n);\\n\\nfile_put_contents( WPMU_PLUGIN_DIR . '\\\/demo-logout.php', \\\"<?php\\\\n\\\/\\\/ Live Preview: Playground's auto-login cookie covers one path; make it site-wide so logged-out views stay logged out.\\\\nadd_action( 'init', function () { if ( isset( \\\\$_GET['ddwc_demo_view'] ) ) { setcookie( 'playground_auto_login_already_happened', '1', 0, '\\\/' ); } }, 0 );\\\\n\\\" );\\n\\n\\\/\\\/ [ key, person, [ product => qty ], days ago placed, status (default completed, two days after it was placed) ].\\n$orders = [\\n\\t[ 'o2', 'olivia', [ 'overshirt' => 1 ], 45 ], [ 'a5', 'amara', [ 'cardigan' => 1, 'socks' => 1 ], 40 ],\\n\\t[ 'e2', 'ethan', [ 'cardigan' => 1 ], 36 ], [ 'l2', 'lena', [ 'poplin' => 1 ], 30 ],\\n\\t[ 'k2', 'daan', [ 'hat' => 1, 'socks' => 2 ], 28 ], [ 'a2', 'amara', [ 'sweater' => 1, 'hat' => 1 ], 26 ],\\n\\t[ 'g2', 'grace', [ 'hat' => 1 ], 22 ],\\n\\t[ 'j1', 'james', [ 'jacket' => 1, 'hat' => 1 ], 22 ], [ 's1', 'sofia', [ 'sweater' => 1, 'socks' => 1 ], 20 ],\\n\\t[ 'm1', 'maya', [ 'dress' => 1, 'hat' => 1 ], 18 ],\\n\\t[ 'g1', 'grace', [ 'cardigan' => 1 ], 16 ], [ 'lu1', 'lucas', [ 'cord' => 1, 'hat' => 2 ], 15 ],\\n\\t[ 'e1', 'ethan', [ 'cord' => 1 ], 14 ], [ 'h1', 'hannah', [ 'dress' => 1 ], 13 ],\\n\\t[ 'a1', 'amara', [ 'overshirt' => 1 ], 12 ], [ 'd1', 'daan', [ 'jacket' => 1 ], 11 ],\\n\\t[ 'li1', 'liam', [ 'cord' => 1, 'socks' => 1 ], 10 ], [ 'l1', 'lena', [ 'overshirt' => 1, 'socks' => 1 ], 9 ],\\n\\t[ 'a6', 'amara', [ 'dress' => 1, 'poplin' => 1, 'socks' => 1 ], 9 ], [ 'o1', 'olivia', [ 'poplin' => 2 ], 8 ],\\n\\t[ 'n2', 'noah', [ 'derby' => 1 ], 7 ], [ 'a3', 'amarade', [ 'jacket' => 1, 'hat' => 1 ], 6 ],\\n\\t[ 'k4', 'sofia', [ 'cord' => 1 ], 5 ], [ 'j2', 'james', [ 'poplin' => 1 ], 4, 'processing' ],\\n\\t[ 'a4', 'amara', [ 'derby' => 1 ], 2, 'processing' ], [ 'lu2', 'lucas', [ 'dress' => 1 ], 2, 'processing' ],\\n\\t[ 'k5', 'maya', [ 'overshirt' => 1, 'socks' => 1 ], 1, 'processing' ],\\n];\\n\\\/\\\/ Order numbers like a real shop: Amara's Linen Overshirt is #1042.\\n$hold = wp_insert_post( [ 'import_id' => 1041 - array_search( 'a1', array_column( $orders, 0 ), true ), 'post_type' => 'ddwc_seq', 'post_status' => 'draft', 'post_title' => 'seq' ] );\\n$o_ids = [];\\nforeach ( $orders as $row ) {\\n\\tlist( $key, $who, $lines, $days, $status ) = $row + [ 4 => 'completed' ];\\n\\tlist( $login, $first, $last, $country, $city, $postcode, $street, $state ) = $people[ $who ];\\n\\t$email = strtolower( $first . '.' . str_replace( ' ', '', $last ) ) . '@example.com';\\n\\t$addr  = [ 'first_name' => $first, 'last_name' => $last, 'email' => $email, 'phone' => '', 'address_1' => $street, 'city' => $city, 'state' => $state, 'postcode' => $postcode, 'country' => $country ];\\n\\t$order = wc_create_order( [ 'customer_id' => $login ? $users[ $login ] : 0 ] );\\n\\tforeach ( $lines as $pk => $qty ) {\\n\\t\\t$order->add_product( wc_get_product( $ids[ $pk ] ), $qty );\\n\\t}\\n\\t$order->set_address( $addr, 'billing' );\\n\\tunset( $addr['email'], $addr['phone'] );\\n\\t$order->set_address( $addr, 'shipping' );\\n\\t$order->set_payment_method( 'bacs' );\\n\\t$order->set_payment_method_title( 'Credit card' );\\n\\t$order->calculate_totals();\\n\\t$placed = time() - $days * DAY_IN_SECONDS - wp_rand( 1, 9 ) * HOUR_IN_SECONDS;\\n\\t$order->set_date_created( $placed );\\n\\t$order->set_date_paid( $placed + 600 );\\n\\t$order->set_status( $status );\\n\\tif ( 'completed' === $status ) {\\n\\t\\t$order->set_date_completed( $placed + 2 * DAY_IN_SECONDS );\\n\\t}\\n\\t$order->save();\\n\\t$o_ids[ $key ] = $order->get_id();\\n}\\nwp_delete_post( $hold, true );\\n\\n\\\/\\\/ ---- Requests through the plugin's own helpers, then dated over the last 30 days ----\\nglobal $wpdb;\\n$rh  = new DDWCWR_Request_Helper();\\n$rs  = new DDWCWR_Resolution_Helper();\\n$ago = function ( $days, $hour = 11 ) {\\n\\treturn gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) - $days * DAY_IN_SECONDS + ( $hour - 12 ) * HOUR_IN_SECONDS );\\n};\\n\\\/\\\/ A file in the plugin's private upload folder, stored the way its upload helper stores one.\\n$store = function ( $bytes, $name, $type ) {\\n\\t$sub = gmdate( 'Y\\\/m' );\\n\\twp_mkdir_p( DDWCWR_Upload_Helper::get_base_dir() . '\\\/' . $sub );\\n\\t$key = $sub . '\\\/' . wp_generate_password( 32, false, false ) . '.' . pathinfo( $name, PATHINFO_EXTENSION );\\n\\tfile_put_contents( DDWCWR_Upload_Helper::get_base_dir() . '\\\/' . $key, $bytes );\\n\\treturn [ 'key' => $key, 'name' => $name, 'type' => $type, 'size' => strlen( $bytes ) ];\\n};\\n\\\/\\\/ [ order, type, product, qty, reason, condition, customer note, photo, source, steps, created days ago, closed (+) or last activity (-) days ago ].\\n\\\/\\\/ Steps: a approve (a:note), l label, t tracking, r received, d refund, x reject, c cancel, m customer message, n internal note.\\n$requests = [\\n\\t[ 'a5', 'return', 'cardigan', 1, 'changed-mind', 'unopened', 'Bought it in two colors by mistake, this one still has its tags.', '', 'account', [ 'd' ], 28, 24 ],\\n\\t[ 'e2', 'return', 'cardigan', 1, 'changed-mind', 'used', 'Wore it once, not really my style.', '', 'account', [ 'x:We can only take back unworn items. The cardigan shows wear on the cuffs.' ], 26, 24 ],\\n\\t[ 'o2', 'return', 'overshirt', 1, 'wrong-size', 'unopened', '', '', 'account', [ 'd' ], 29, 25 ],\\n\\t[ 's1', 'return', 'sweater', 1, 'wrong-size', 'unopened', 'Too big on the shoulders. Size S would fit better.', '', 'portal', [ 'd' ], 15, 9 ],\\n\\t[ 'm1', 'return', 'dress', 1, 'wrong-size', 'unopened', 'The dress is too long for me.', '', 'account', [ 'a', 't:USPS:9400111899223197428490', 'r' ], 14, -1 ],\\n\\t[ 'g2', 'return', 'hat', 1, 'changed-mind', 'unopened', 'Not sure about the color.', '', 'account', [ 'm:Never mind, it grew on me. I am keeping it.', 'c' ], 12, 11 ],\\n\\t[ 'g1', 'return', 'cardigan', 1, 'wrong-size', 'unopened', 'The knit is lovely but it is too boxy on me.', '', 'account', [ 'a', 't:USPS:9400111899223197428512', 'r' ], 10, -1 ],\\n\\t[ 'e1', 'return', 'cord', 1, 'damaged', 'damaged', 'The side seam came open the first time I wore it.', 'seam.jpg', 'account', [ 'a:Thanks for the photo. Send it back and we refund you in full.' ], 9, -7 ],\\n\\t[ 'l2', 'return', 'poplin', 1, 'not-as-described', 'opened', 'The pink is much paler than on the product page. Photo attached.', 'shirt-color.jpg', 'portal', [ 'a:Sorry about that. Send it back and we refund it in full.', 'n:Second color complaint on this dye batch. Check the product photos.' ], 8, -6 ],\\n\\t[ 'd1', 'withdrawal', 'jacket', 1, '', '', '', '', 'withdrawal', [ 'd' ], 8, 3 ],\\n\\t[ 'li1', 'return', 'cord', 1, 'damaged', 'damaged', 'Two buttons were missing when it arrived.', 'buttons.jpg', 'account', [ 'd' ], 7, 3 ],\\n\\t[ 'a2', 'return', 'sweater', 1, 'wrong-size', 'unopened', 'Lovely knit but the sleeves are much longer than I expected.', '', 'account', [ 'a:Approved. Your prepaid UPS label is ready on this page.', 'l:UPS:1Z999AA10123456784', 'm:Dropped it off at the UPS store this morning.' ], 6, -2 ],\\n\\t[ 'l1', 'withdrawal', 'overshirt', 1, '', '', '', '', 'withdrawal', [ 'd' ], 5, 1 ],\\n\\t[ 'o1', 'return', 'poplin', 2, 'wrong-size', 'unopened', 'Both shirts are too long. I will order a size down.', '', 'account', [ 'a' ], 4, -3 ],\\n\\t[ 'j1', 'return', 'jacket', 1, 'wrong-item', 'unopened', 'I ordered the black twill jacket but got a different one.', 'parcel.jpg', 'portal', [ 'a:Our mistake, sorry. Your label is attached.', 'l:USPS:9400111899223197428533' ], 3, -2 ],\\n\\t[ 'h1', 'withdrawal', 'dress', 1, '', '', '', '', 'withdrawal', [ 'a' ], 3, -2 ],\\n\\t[ 'j2', 'cancellation', '', 0, '', '', 'Ordered by mistake, please cancel.', '', 'portal', [ 'd' ], 3, 3 ],\\n\\t[ 'n2', 'return', 'derby', 1, 'wrong-size', 'opened', 'They pinch at the toe. Half a size up would be right.', '', 'account', [], 2, 0 ],\\n\\t[ 'lu2', 'cancellation', '', 0, '', '', 'Ordered the wrong size, I will place a new order.', '', 'account', [], 1, 0 ],\\n\\t[ 'a1', 'return', 'overshirt', 1, 'wrong-size', 'unopened', 'The linen overshirt runs a size small on me. Could I send it back for a refund?', '', 'account', [], 1, 0 ],\\n\\t[ 'lu1', 'withdrawal', 'cord', 1, '', '', '', '', 'withdrawal', [], 0, 0 ],\\n];\\nforeach ( $requests as $i => list( $ok, $type, $pk, $qty, $reason, $cond, $note, $pic, $source, $steps, $from, $to ) ) {\\n\\t$o     = wc_get_order( $o_ids[ $ok ] );\\n\\t$uid   = $o->get_customer_id();\\n\\t$items = [];\\n\\tforeach ( $o->get_items() as $iid => $it ) {\\n\\t\\tif ( $pk && $it->get_product_id() === $ids[ $pk ] ) {\\n\\t\\t\\t$items[ $iid ] = [ 'qty' => $qty, 'reason' => $reason, 'condition' => $cond ];\\n\\t\\t}\\n\\t}\\n\\t$created = $ago( $from, 9 + $i * 5 % 9 );\\n\\t$args    = [ 'order' => $o, 'type' => $type, 'items' => $items, 'note' => $note, 'source' => $source, 'attachments' => $pic ? [ $store( file_get_contents( $photos[ $pk ] ), $pic, 'image\\\/jpeg' ) ] : [] ];\\n\\tif ( 'withdrawal' === $type ) {\\n\\t\\t$args += [ 'email' => $o->get_billing_email(), 'meta' => [ 'statement_name' => $o->get_formatted_billing_full_name(), 'statement_email' => $o->get_billing_email(), 'statement_utc' => $created ] ];\\n\\t}\\n\\twp_set_current_user( $uid ); \\\/\\\/ The customer writes their own note.\\n\\t$id = $rh->create_request( $args );\\n\\twp_set_current_user( 1 );\\n\\tif ( is_wp_error( $id ) ) { \\\/\\\/ Past the return window today: staff create it, the note stays the customer's.\\n\\t\\t$id = $rh->create_request( [ 'by_admin' => true, 'note' => '' ] + $args );\\n\\t\\t$note && $rh->add_message( $id, $note, 'message', 'customer', $uid, $args['attachments'], false );\\n\\t}\\n\\tforeach ( $steps as $step ) {\\n\\t\\t$s = explode( ':', $step, 3 );\\n\\t\\tswitch ( $s[0] ) {\\n\\t\\t\\tcase 'a':\\n\\t\\t\\tcase 'x':\\n\\t\\t\\t\\t$rh->change_status( $id, 'a' === $s[0] ? 'approved' : 'rejected', [ 'author_id' => 1, 'note' => $s[1] ?? '', 'notify' => false ] );\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase 'l':\\n\\t\\t\\t\\t( new DDWCWR_Label_Helper() )->attach_label( $id, $store( \\\"%PDF-1.4\\\\n%%EOF\\\", 'return-label.pdf', 'application\\\/pdf' ) );\\n\\t\\t\\t\\t\\\/\\\/ Fall through: a label comes with tracking.\\n\\t\\t\\tcase 't':\\n\\t\\t\\t\\t$rh->update_request( $id, [ 'carrier' => $s[1], 'tracking_number' => $s[2] ], false );\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase 'd':\\n\\t\\t\\t\\t$rh->change_status( $id, 'approved', [ 'author_id' => 1, 'notify' => false ] );\\n\\t\\t\\t\\t'cancellation' === $type || $rs->mark_received( $id, true, 1 );\\n\\t\\t\\t\\t$rs->process( $id, [ 'refund_method' => 'manual', 'author_id' => 1 ] );\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase 'r':\\n\\t\\t\\t\\t$rs->mark_received( $id, true, 1 );\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase 'c':\\n\\t\\t\\t\\t$rh->change_status( $id, 'cancelled', [ 'notify' => false ] );\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase 'm':\\n\\t\\t\\t\\t$rh->add_message( $id, $s[1], 'message', 'customer', $uid, [], false );\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase 'n':\\n\\t\\t\\t\\t$rh->add_message( $id, $s[1], 'note', 'staff', 1, [], false );\\n\\t\\t}\\n\\t}\\n\\t\\\/\\\/ Date the request and spread its history between created and closed (or last activity).\\n\\t$closed = $to > 0 || ( $to === $from && $steps ) ? $ago( $to, 9 + $i * 5 % 9 + ( $to === $from ? 1 : 0 ) ) : null;\\n\\t$end    = $closed ? $closed : ( $to < 0 ? $ago( -$to ) : $created );\\n\\t$wpdb->update( \\\"{$wpdb->prefix}ddwcwr_requests\\\", [ 'created' => $created, 'updated' => $end, 'closed' => $closed ], [ 'id' => $id ] );\\n\\t$mids = $wpdb->get_col( $wpdb->prepare( \\\"SELECT id FROM {$wpdb->prefix}ddwcwr_messages WHERE request_id = %d ORDER BY id\\\", $id ) );\\n\\t$span = max( 600, strtotime( $end ) - strtotime( $created ) );\\n\\tforeach ( $mids as $n => $mid ) {\\n\\t\\t$wpdb->update( \\\"{$wpdb->prefix}ddwcwr_messages\\\", [ 'created' => gmdate( 'Y-m-d H:i:s', strtotime( $created ) + (int) ( $span * ( count( $mids ) > 1 ? $n \\\/ ( count( $mids ) - 1 ) : 0 ) ) ) ], [ 'id' => $mid ] );\\n\\t}\\n\\t$meta = $rh->get_request( $id )['meta'];\\n\\tforeach ( [ 'processed' => $end, 'label_created' => gmdate( 'Y-m-d H:i:s', strtotime( $created ) + DAY_IN_SECONDS ) ] as $k => $v ) {\\n\\t\\tisset( $meta[ $k ] ) && $meta[ $k ] = $v;\\n\\t}\\n\\t$rh->update_request( $id, [ 'meta' => $meta ], false );\\n}\\n\\\/\\\/ A withdrawal statement whose order number matched nothing, kept for staff.\\nupdate_option( 'ddwcwr_unmatched_withdrawals', [ [ 'name' => 'Marie Dubois', 'order' => '12880', 'email' => 'marie.dubois@example.com', 'date' => gmdate( 'Y-m-d H:i:s', time() - 2 * DAY_IN_SECONDS ), 'ip_hash' => '' ] ], false );\\n\\n\\\/\\\/ ---- Storefront (Kadence + DevDiggers demo kit) ----\\n\\\/\\\/ ---- DevDiggers Live Preview demo kit (Apple design language on Kadence) ----\\n\\\/**\\n * Inserted by build.py where a seed says \\\/\\\/ @kit. Call, after products and users exist:\\n *   ddwc_demo_kit_style( [ 'accent' => '#0071e3', 'css' => '' ] )  Kadence + global CSS.\\n *   ddwc_demo_kit_home( [...] )                                     Home page, set as front page.\\n *   ddwc_demo_kit_menu( [ 'Shop' => url, ... ] )                    Primary menu.\\n *   ddwc_demo_kit_switcher( $views_php )                            \\\"View as\\\" switcher mu-plugin.\\n *   ddwc_demo_kit_icon( 'chat' )                                    SVG line icon (names in the list below).\\n * Widget classes for the hero showcase: dk-widget, dk-w-head, dk-w-app, dk-w-label, dk-w-title,\\n * dk-w-big, dk-w-row, dk-w-pill, dk-w-avatar, dk-w-bubble, dk-w-note.\\n *\\\/\\n\\nfunction ddwc_demo_kit_icon( $name, $size = 24 ) {\\n\\t$paths = [\\n\\t\\t'admin'    => '<rect x=\\\"3\\\" y=\\\"3\\\" width=\\\"7\\\" height=\\\"9\\\" rx=\\\"1.5\\\"\\\/><rect x=\\\"14\\\" y=\\\"3\\\" width=\\\"7\\\" height=\\\"5\\\" rx=\\\"1.5\\\"\\\/><rect x=\\\"14\\\" y=\\\"12\\\" width=\\\"7\\\" height=\\\"9\\\" rx=\\\"1.5\\\"\\\/><rect x=\\\"3\\\" y=\\\"16\\\" width=\\\"7\\\" height=\\\"5\\\" rx=\\\"1.5\\\"\\\/>',\\n\\t\\t'customer' => '<circle cx=\\\"12\\\" cy=\\\"8\\\" r=\\\"4\\\"\\\/><path d=\\\"M4 21c0-4 3.6-7 8-7s8 3 8 7\\\"\\\/>',\\n\\t\\t'store'    => '<path d=\\\"M3 9l1.5-5h15L21 9\\\"\\\/><path d=\\\"M3 9h18v2a3 3 0 0 1-6 0 3 3 0 0 1-6 0 3 3 0 0 1-6 0z\\\"\\\/><path d=\\\"M5 13v8h14v-8\\\"\\\/><path d=\\\"M10 21v-5h4v5\\\"\\\/>',\\n\\t\\t'product'  => '<path d=\\\"M20.6 13.4 13.4 20.6a2 2 0 0 1-2.8 0L3 13V3h10l7.6 7.6a2 2 0 0 1 0 2.8z\\\"\\\/><circle cx=\\\"7.5\\\" cy=\\\"7.5\\\" r=\\\"1.5\\\"\\\/>',\\n\\t\\t'cart'     => '<circle cx=\\\"9\\\" cy=\\\"20\\\" r=\\\"1.5\\\"\\\/><circle cx=\\\"18\\\" cy=\\\"20\\\" r=\\\"1.5\\\"\\\/><path d=\\\"M2 3h3l2.7 12.4a2 2 0 0 0 2 1.6h8.6a2 2 0 0 0 2-1.5L22 7H6\\\"\\\/>',\\n\\t\\t'chat'     => '<path d=\\\"M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z\\\"\\\/>',\\n\\t\\t'wallet'   => '<path d=\\\"M3 7a2 2 0 0 1 2-2h13v4\\\"\\\/><rect x=\\\"3\\\" y=\\\"7\\\" width=\\\"18\\\" height=\\\"13\\\" rx=\\\"2\\\"\\\/><circle cx=\\\"16.5\\\" cy=\\\"13.5\\\" r=\\\"1.3\\\"\\\/>',\\n\\t\\t'star'     => '<path d=\\\"m12 3 2.8 5.7 6.2.9-4.5 4.4 1.1 6.2L12 17.3 6.4 20.2l1.1-6.2L3 9.6l6.2-.9z\\\"\\\/>',\\n\\t\\t'register' => '<rect x=\\\"3\\\" y=\\\"4\\\" width=\\\"18\\\" height=\\\"12\\\" rx=\\\"2\\\"\\\/><path d=\\\"M7 20h10M12 16v4M7 8h4M7 11h2\\\"\\\/>',\\n\\t\\t'link'     => '<path d=\\\"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1\\\"\\\/><path d=\\\"M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1\\\"\\\/>',\\n\\t\\t'cube'     => '<path d=\\\"M12 2 21 7v10l-9 5-9-5V7z\\\"\\\/><path d=\\\"m3 7 9 5 9-5M12 12v10\\\"\\\/>',\\n\\t\\t'ar'       => '<path d=\\\"M3 7V4h3M21 7V4h-3M3 17v3h3M21 17v3h-3\\\"\\\/><rect x=\\\"8\\\" y=\\\"8\\\" width=\\\"8\\\" height=\\\"8\\\" rx=\\\"1.5\\\"\\\/>',\\n\\t\\t'rx'       => '<path d=\\\"M9 3h6v4H9z\\\"\\\/><path d=\\\"M7 5H5v16h14V5h-2\\\"\\\/><path d=\\\"M9 12h6M9 16h4\\\"\\\/>',\\n\\t\\t'phone'    => '<rect x=\\\"6\\\" y=\\\"2\\\" width=\\\"12\\\" height=\\\"20\\\" rx=\\\"3\\\"\\\/><path d=\\\"M11 18h2\\\"\\\/>',\\n\\t\\t'orders'   => '<path d=\\\"M4 7 12 3l8 4v10l-8 4-8-4z\\\"\\\/><path d=\\\"m4 7 8 4 8-4M12 11v10\\\"\\\/>',\\n\\t\\t'calendar' => '<rect x=\\\"3\\\" y=\\\"5\\\" width=\\\"18\\\" height=\\\"16\\\" rx=\\\"2\\\"\\\/><path d=\\\"M3 10h18M8 3v4M16 3v4\\\"\\\/>',\\n\\t\\t'clock'    => '<circle cx=\\\"12\\\" cy=\\\"13\\\" r=\\\"8\\\"\\\/><path d=\\\"M12 9v4l2.5 2.5M9 2h6\\\"\\\/>',\\n\\t\\t'mail'     => '<rect x=\\\"3\\\" y=\\\"5\\\" width=\\\"18\\\" height=\\\"14\\\" rx=\\\"2\\\"\\\/><path d=\\\"m3 7 9 6 9-6\\\"\\\/>',\\n\\t\\t'chart'    => '<path d=\\\"M3 3v18h18\\\"\\\/><path d=\\\"m7 15 4-4 3 3 5-6\\\"\\\/>',\\n\\t\\t'card'     => '<rect x=\\\"2\\\" y=\\\"5\\\" width=\\\"20\\\" height=\\\"14\\\" rx=\\\"2\\\"\\\/><path d=\\\"M2 10h20M6 15h4\\\"\\\/>',\\n\\t\\t'scan'     => '<path d=\\\"M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2M7 8v8M11 8v8M14 8v8M17 8v8\\\"\\\/>',\\n\\t\\t'receipt'  => '<path d=\\\"M5 3h14v18l-3-2-2 2-2-2-2 2-2-2-3 2z\\\"\\\/><path d=\\\"M9 8h6M9 12h6\\\"\\\/>',\\n\\t\\t'heart'    => '<path d=\\\"M12 21s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 11c0 5.6-7 10-7 10z\\\"\\\/>',\\n\\t\\t'upload'   => '<path d=\\\"M12 16V4M7 9l5-5 5 5\\\"\\\/><path d=\\\"M4 16v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3\\\"\\\/>',\\n\\t\\t'lock'     => '<rect x=\\\"4\\\" y=\\\"11\\\" width=\\\"16\\\" height=\\\"10\\\" rx=\\\"2\\\"\\\/><path d=\\\"M8 11V7a4 4 0 0 1 8 0v4\\\"\\\/>',\\n\\t\\t'shield'   => '<path d=\\\"M12 3 4 6v6c0 4.5 3.4 8 8 9 4.6-1 8-4.5 8-9V6z\\\"\\\/><path d=\\\"m8.5 12 2.5 2.5 4.5-5\\\"\\\/>',\\n\\t\\t'wifi'     => '<path d=\\\"M2 8.8a15 15 0 0 1 20 0M5 12.5a10 10 0 0 1 14 0M8.5 16a5 5 0 0 1 7 0\\\"\\\/><circle cx=\\\"12\\\" cy=\\\"19.5\\\" r=\\\"1\\\"\\\/>',\\n\\t\\t'bell'     => '<path d=\\\"M6 8a6 6 0 0 1 12 0c0 7 3 8 3 8H3s3-1 3-8\\\"\\\/><path d=\\\"M10.3 21a1.9 1.9 0 0 0 3.4 0\\\"\\\/>',\\n\\t\\t'gift'     => '<rect x=\\\"3\\\" y=\\\"8\\\" width=\\\"18\\\" height=\\\"13\\\" rx=\\\"2\\\"\\\/><path d=\\\"M3 12h18M12 8v13M12 8C10 5 7 5 7 7s3 1 5 1c2 0 5 1 5-1s-3-2-5 1\\\"\\\/>',\\n\\t\\t'bolt'     => '<path d=\\\"M13 2 4 14h7l-1 8 9-12h-7z\\\"\\\/>',\\n\\t\\t'ask'      => '<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"9\\\"\\\/><path d=\\\"M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.7.3-1 .9-1 1.7M12 17h.01\\\"\\\/>',\\n\\t\\t'check'    => '<path d=\\\"m5 12 5 5 9-10\\\"\\\/>',\\n\\t\\t'pay'      => '<rect x=\\\"3\\\" y=\\\"6\\\" width=\\\"18\\\" height=\\\"13\\\" rx=\\\"2\\\"\\\/><path d=\\\"M3 10h18M7 15h3\\\"\\\/>',\\n\\t];\\n\\treturn '<svg viewBox=\\\"0 0 24 24\\\" width=\\\"' . (int) $size . '\\\" height=\\\"' . (int) $size . '\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"1.7\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\" aria-hidden=\\\"true\\\">' . ( $paths[ $name ] ?? $paths['store'] ) . '<\\\/svg>';\\n}\\n\\n\\\/** Product photo URL (for hero_img and tile img). *\\\/\\nfunction ddwc_demo_kit_img( $product_id, $size = 'large' ) {\\n\\treturn wp_get_attachment_image_url( get_post_thumbnail_id( $product_id ), $size );\\n}\\n\\n\\\/**\\n * Brand the store: Apple's neutral system (SF Pro via the system font stack, #1d1d1f \\\/ #6e6e73 \\\/ #f5f5f7)\\n * with one accent colour per brand. Global CSS goes in an mu-plugin so the seed may still use Additional CSS.\\n *\\n * @param array $a accent (hex), css (extra CSS appended after the kit CSS).\\n *\\\/\\nfunction ddwc_demo_kit_style( $a ) {\\n\\t$a      = array_merge( [ 'accent' => '#0071e3', 'css' => '' ], $a );\\n\\t$accent = $a['accent'];\\n\\t$rgb    = sscanf( $accent, '#%02x%02x%02x' );\\n\\t$dark   = vsprintf( '#%02x%02x%02x', array_map( function ( $c ) { return (int) round( $c * 0.84 ); }, $rgb ) );\\n\\t$tint   = vsprintf( 'rgba(%d,%d,%d,.1)', $rgb );\\n\\t$stack  = '-apple-system,BlinkMacSystemFont,\\\"SF Pro Text\\\",\\\"SF Pro Display\\\",\\\"Helvetica Neue\\\",Helvetica,Arial,sans-serif';\\n\\n\\t$colors  = [ $accent, $dark, '#1d1d1f', '#1d1d1f', '#6e6e73', '#86868b', '#d2d2d7', '#f5f5f7', '#ffffff', '#ffffff', '#248a3d', '#0071e3', '#d70015', '#bf4800', '#b25e09' ];\\n\\t$palette = [];\\n\\tforeach ( $colors as $i => $color ) {\\n\\t\\t$palette[] = [ 'color' => $color, 'slug' => 'palette' . ( $i + 1 ), 'name' => 'Palette Color ' . ( $i + 1 ) ];\\n\\t}\\n\\tupdate_option( 'kadence_global_palette', wp_json_encode( [ 'palette' => $palette, 'second-palette' => $palette, 'third-palette' => $palette, 'active' => 'palette' ] ) );\\n\\n\\tset_theme_mod( 'base_font', [ 'family' => $stack, 'google' => false, 'weight' => '400', 'variant' => 'regular', 'size' => [ 'desktop' => 17 ], 'lineHeight' => [ 'desktop' => 1.47 ], 'color' => 'palette4' ] );\\n\\tset_theme_mod( 'heading_font', [ 'family' => $stack, 'google' => false, 'weight' => '600', 'variant' => [ '600' ] ] );\\n\\tforeach ( [ 'h1_font' => [ 48, 1.08 ], 'h2_font' => [ 40, 1.1 ], 'h3_font' => [ 28, 1.14 ], 'h4_font' => [ 21, 1.2 ], 'h5_font' => [ 17, 1.3 ], 'h6_font' => [ 14, 1.4 ] ] as $mod => $size ) {\\n\\t\\tset_theme_mod( $mod, [ 'size' => [ 'desktop' => $size[0] ], 'lineHeight' => [ 'desktop' => $size[1] ], 'family' => 'inherit', 'google' => false, 'weight' => '600', 'variant' => '600', 'color' => 'palette3' ] );\\n\\t}\\n\\tset_theme_mod( 'load_fonts_local', false );\\n\\n\\tset_theme_mod( 'site_background', [ 'desktop' => [ 'color' => 'palette9' ] ] );\\n\\tset_theme_mod( 'content_background', [ 'desktop' => [ 'color' => 'palette9' ] ] );\\n\\tset_theme_mod( 'page_content_style', 'unboxed' );\\n\\tset_theme_mod( 'product_archive_content_style', 'unboxed' );\\n\\tset_theme_mod( 'product_content_style', 'unboxed' );\\n\\tset_theme_mod( 'product_archive_columns', '4' );\\n\\tset_theme_mod( 'buttons_border_radius', [ 'size' => [ 980, 980, 980, 980 ], 'unit' => 'px', 'locked' => true ] );\\n\\tset_theme_mod( 'buttons_typography', [ 'size' => [ 'desktop' => 15 ], 'family' => 'inherit', 'weight' => '400', 'variant' => 'regular', 'letterSpacing' => [ 'desktop' => -0.01 ], 'letterType' => 'em' ] );\\n\\tset_theme_mod( 'buttons_padding', [ 'size' => [ 'desktop' => [ 11, 22, 11, 22 ] ], 'unit' => [ 'desktop' => 'px' ], 'locked' => [ 'desktop' => false ] ] );\\n\\n\\t\\\/\\\/ Header: one slim frosted bar, logo left, menu and bag right.\\n\\tset_theme_mod(\\n\\t\\t'header_desktop_items',\\n\\t\\t[\\n\\t\\t\\t'top'    => [ 'top_left' => [], 'top_left_center' => [], 'top_center' => [], 'top_right_center' => [], 'top_right' => [] ],\\n\\t\\t\\t'main'   => [ 'main_left' => [ 'logo' ], 'main_left_center' => [], 'main_center' => [], 'main_right_center' => [], 'main_right' => [ 'navigation', 'cart' ] ],\\n\\t\\t\\t'bottom' => [ 'bottom_left' => [], 'bottom_left_center' => [], 'bottom_center' => [], 'bottom_right_center' => [], 'bottom_right' => [] ],\\n\\t\\t]\\n\\t);\\n\\tset_theme_mod( 'header_sticky', 'main' );\\n\\tset_theme_mod( 'header_main_height', [ 'size' => [ 'mobile' => 52, 'tablet' => 52, 'desktop' => 52 ], 'unit' => [ 'mobile' => 'px', 'tablet' => 'px', 'desktop' => 'px' ] ] );\\n\\tset_theme_mod( 'header_main_background', [ 'desktop' => [ 'color' => 'rgba(255,255,255,0.8)' ] ] );\\n\\tset_theme_mod( 'header_sticky_background', [ 'desktop' => [ 'color' => 'rgba(255,255,255,0.8)' ] ] );\\n\\tset_theme_mod( 'header_main_bottom_border', [ 'desktop' => [ 'width' => 1, 'unit' => 'px', 'style' => 'solid', 'color' => 'rgba(0,0,0,0.08)' ] ] );\\n\\tset_theme_mod( 'brand_typography', [ 'size' => [ 'desktop' => 19 ], 'family' => 'inherit', 'google' => false, 'weight' => '600', 'variant' => '600', 'letterSpacing' => [ 'desktop' => -0.02 ], 'letterType' => 'em', 'color' => 'palette3' ] );\\n\\tset_theme_mod( 'primary_navigation_typography', [ 'size' => [ 'desktop' => 13 ], 'family' => 'inherit', 'weight' => '400', 'variant' => 'regular' ] );\\n\\tset_theme_mod( 'primary_navigation_color', [ 'color' => 'palette4', 'hover' => 'palette1', 'active' => 'palette3' ] );\\n\\n\\tset_theme_mod( 'page_title_layout', 'above' );\\n\\tset_theme_mod( 'page_title_background', [ 'desktop' => [ 'color' => 'palette8' ] ] );\\n\\tset_theme_mod( 'product_archive_title_background', [ 'desktop' => [ 'color' => 'palette8' ] ] );\\n\\tset_theme_mod( 'footer_html_content', '{copyright} {year} {site-title}. A DevDiggers live demo store.' );\\n\\tset_theme_mod( 'footer_bottom_background', [ 'desktop' => [ 'color' => 'palette8' ] ] );\\n\\n\\t$css = <<<'DDWCCSS'\\n:root{--dk-accent:__A__;--dk-accent-dark:__D__;--dk-tint:__T__;--dk-ink:#1d1d1f;--dk-gray:#6e6e73;--dk-line:#d2d2d7;--dk-fog:#f5f5f7;--dk-ease:cubic-bezier(.25,.1,.25,1)}\\nbody{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;letter-spacing:-.022em;color:var(--dk-ink)}\\nh1,h2,h3,h4{letter-spacing:-.015em}\\na{color:var(--dk-accent)}\\n#masthead .site-main-header-wrap,#masthead .item-is-fixed{-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}\\n.main-navigation .primary-menu-container>ul>li.menu-item>a{padding-left:.9em;padding-right:.9em;opacity:.85}\\n.main-navigation .primary-menu-container>ul>li.menu-item>a:hover{opacity:1}\\n.button,button.button,.wp-element-button,input[type=submit],.woocommerce a.button,.woocommerce button.button{background:var(--dk-accent);color:#fff;border:0;box-shadow:none!important;transition:background .2s var(--dk-ease)}\\n.button:hover,.wp-element-button:hover,input[type=submit]:hover,.woocommerce a.button:hover,.woocommerce button.button:hover{background:var(--dk-accent-dark);color:#fff}\\ninput[type=text],input[type=email],input[type=tel],input[type=password],input[type=number],input[type=search],textarea,select{border:1px solid var(--dk-line)!important;border-radius:12px!important;padding:12px 14px!important;background:#fff!important;font-size:17px;transition:border-color .2s,box-shadow .2s}\\ninput:focus,textarea:focus,select:focus{border-color:var(--dk-accent)!important;box-shadow:0 0 0 4px var(--dk-tint)!important;outline:0}\\n.entry-hero .entry-header,.page-title{padding-top:56px;padding-bottom:40px}\\n.entry-hero h1,.page-title h1,.woocommerce-products-header__title{font-size:48px;letter-spacing:-.02em}\\n.woocommerce-store-notice{display:none!important}\\n.woocommerce-message,.woocommerce-info,.woocommerce-error{border:0!important;border-radius:14px;background:var(--dk-fog)!important;color:var(--dk-ink)}\\n\\\/* Product cards, Apple Store style. *\\\/\\nul.products li.product{background:#fff;border-radius:18px;padding:0 0 22px;overflow:hidden;box-shadow:0 2px 12px rgba(0,0,0,.08);transition:box-shadow .3s var(--dk-ease),transform .3s var(--dk-ease)}\\nul.products li.product:hover{box-shadow:0 10px 34px rgba(0,0,0,.14);transform:translateY(-2px)}\\nul.products li.product img{border-radius:0!important;aspect-ratio:1\\\/1;object-fit:cover;margin:0!important}\\nul.products li.product .woocommerce-loop-product__title,ul.products li.product .product-details,ul.products li.product .entry-content-wrap{padding-left:20px;padding-right:20px}\\nul.products li.product .woocommerce-loop-product__title{font-size:17px;font-weight:600;margin-top:16px}\\nul.products li.product .price{color:var(--dk-gray);font-size:15px;font-weight:400}\\nul.products li.product .button{font-size:14px;padding:8px 16px}\\nul.products li.product .onsale{border-radius:980px;background:var(--dk-accent);font-weight:600;font-size:12px}\\n.single-product div.product .product_title{font-size:40px;letter-spacing:-.02em}\\n.single-product div.product .price{font-size:21px;color:var(--dk-ink)}\\n.single-product div.product .woocommerce-product-gallery img{border-radius:24px}\\n\\\/* My account, as a settings sidebar. *\\\/\\n.woocommerce-MyAccount-navigation ul{background:var(--dk-fog);border-radius:18px;padding:8px!important}\\n.woocommerce-MyAccount-navigation ul li{border:0!important}\\n.woocommerce-MyAccount-navigation ul li a{display:block;padding:10px 14px!important;border-radius:10px;color:var(--dk-ink)!important;font-size:15px}\\n.woocommerce-MyAccount-navigation ul li.is-active a{background:#fff;font-weight:600;box-shadow:0 1px 4px rgba(0,0,0,.08)}\\ntable.shop_table{border-radius:18px!important;border-color:var(--dk-line)!important;overflow:hidden}\\n.site-footer{font-size:12px;color:var(--dk-gray)}\\n\\\/* Home page building blocks. *\\\/\\n.dk-wrap{max-width:1180px;margin:0 auto;padding-left:22px;padding-right:22px}\\n.dk-hero{text-align:center;padding-top:72px}\\n.dk-eyebrow{display:inline-block;color:var(--dk-accent);font-size:17px;font-weight:600;letter-spacing:-.01em;margin-bottom:10px}\\n.dk-hero h1{font-size:clamp(44px,7vw,80px);line-height:1.05;letter-spacing:-.025em;margin:0 auto 14px!important;max-width:16ch;text-wrap:balance}\\n.dk-lead{font-size:clamp(19px,2.2vw,24px);line-height:1.38;color:var(--dk-gray);max-width:36em;margin:0 auto 28px!important;text-wrap:pretty;letter-spacing:-.015em}\\n.dk-ctas{display:flex;gap:28px;justify-content:center;align-items:center;flex-wrap:wrap}\\n.dk-btn{display:inline-flex;align-items:center;padding:12px 24px;border-radius:980px;background:var(--dk-accent);color:#fff!important;font-size:17px;text-decoration:none!important;transition:background .2s var(--dk-ease)}\\n.dk-btn:hover{background:var(--dk-accent-dark)}\\n.dk-btn.is-light{background:#fff;color:var(--dk-ink)!important}.dk-btn.is-light:hover{background:#e8e8ed}\\n.dk-more{font-size:17px;color:var(--dk-accent)!important;text-decoration:none!important}\\n.dk-more:after{content:\\\"\\\\203A\\\";display:inline-block;margin-left:6px;font-size:1.2em;line-height:0;transition:transform .2s var(--dk-ease)}\\n.dk-more:hover{text-decoration:underline!important}.dk-more:hover:after{transform:translateX(3px)}\\n.dk-stage{position:relative;margin:56px auto 0;max-width:1180px;border-radius:32px;overflow:hidden;background:var(--dk-fog);aspect-ratio:16\\\/9}\\n.dk-stage>img{width:100%;height:100%;object-fit:cover;display:block}\\n.dk-stage.is-trio{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;background:#fff}\\n.dk-stage.is-trio>img{min-width:0}\\n.dk-stage .dk-widget{position:absolute;right:32px;bottom:32px}\\n.dk-widget{width:330px;max-width:calc(100% - 32px);text-align:left;padding:18px;border-radius:22px;background:rgba(255,255,255,.78);-webkit-backdrop-filter:saturate(180%) blur(24px);backdrop-filter:saturate(180%) blur(24px);box-shadow:0 22px 60px rgba(0,0,0,.18),inset 0 0 0 .5px rgba(255,255,255,.6);color:var(--dk-ink);font-size:15px;line-height:1.35}\\n.dk-w-head{display:flex;align-items:center;gap:10px;margin-bottom:12px}\\n.dk-w-app{flex:none;display:grid;place-items:center;width:34px;height:34px;border-radius:9px;background:var(--dk-accent);color:#fff}\\n.dk-w-app svg{width:19px;height:19px}\\n.dk-w-label{display:block;font-size:12px;font-weight:600;color:var(--dk-gray);letter-spacing:0;text-transform:uppercase}\\n.dk-w-title{display:block;font-size:16px;font-weight:600;letter-spacing:-.02em}\\n.dk-w-big{display:block;font-size:40px;font-weight:600;letter-spacing:-.03em;line-height:1.1;margin:4px 0}\\n.dk-w-row{display:flex;justify-content:space-between;gap:12px;padding:9px 0;border-top:.5px solid rgba(0,0,0,.12);font-size:14px}\\n.dk-w-row span:last-child{color:var(--dk-gray)}\\n.dk-w-row.is-total{font-weight:600}.dk-w-row.is-total span:last-child{color:var(--dk-ink)}\\n.dk-w-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:980px;background:var(--dk-tint);color:var(--dk-accent);font-size:13px;font-weight:600}\\n.dk-w-avatar{flex:none;width:34px;height:34px;border-radius:50%;object-fit:cover}\\n.dk-w-bubble{padding:10px 14px;border-radius:18px 18px 18px 6px;background:#e9e9eb;font-size:15px;margin-top:6px}\\n.dk-w-bubble.is-me{border-radius:18px 18px 6px 18px;background:var(--dk-accent);color:#fff;margin-left:30px}\\n.dk-w-note{display:block;font-size:12px;color:var(--dk-gray);margin-top:10px}\\n.dk-cd{display:flex;gap:8px;margin:10px 0 4px}.dk-cd span{flex:1;text-align:center;padding:10px 0 8px;border-radius:12px;background:var(--dk-ink);color:#fff;font-size:22px;font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:-.02em}\\n.dk-cd small{display:block;font-size:10px;font-weight:500;color:#a1a1a6;letter-spacing:.04em;text-transform:uppercase;margin-top:3px}\\n.dk-band{background:var(--dk-fog);margin-top:96px;padding:88px 0}\\n.dk-title{text-align:center!important;font-size:clamp(34px,4.6vw,56px);letter-spacing:-.025em;line-height:1.08;margin:0 auto 48px!important;max-width:20ch;text-wrap:balance}\\n.dk-shelf-title{font-size:clamp(28px,3.4vw,40px);letter-spacing:-.02em;line-height:1.1;margin:0 0 28px}\\n.dk-shelf-title span{color:var(--dk-gray)}\\n.dk-features{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}\\n.dk-feature{background:#fff;border-radius:28px;padding:36px 32px 40px}\\n.dk-feature svg{color:var(--dk-accent);width:36px;height:36px}\\n.dk-feature h3{font-size:24px;letter-spacing:-.02em;margin:18px 0 8px}\\n.dk-feature p{margin:0;font-size:17px;color:var(--dk-gray)}\\n.dk-shelf{padding-top:96px}\\n.dk-shelf-head{display:flex;justify-content:space-between;align-items:baseline;gap:16px;flex-wrap:wrap}\\n.dk-tile{margin:96px auto 104px;display:grid;grid-template-columns:1fr 1fr;align-items:center;border-radius:32px;overflow:hidden;background:#000;color:#f5f5f7}\\n.dk-tile-copy{padding:64px}\\n.dk-tile h2{color:#f5f5f7;font-size:clamp(32px,3.8vw,48px);letter-spacing:-.025em;line-height:1.08;margin:0 0 16px}\\n.dk-tile p{color:#a1a1a6;font-size:19px;line-height:1.42}\\n.dk-tile .dk-more{color:#2997ff!important}\\n.dk-tile img{width:100%;height:100%;min-height:440px;max-height:600px;object-fit:cover;display:block}\\n.dk-stats{display:flex;gap:36px;margin:28px 0}.dk-stats b{display:block;font-size:32px;font-weight:600;letter-spacing:-.02em;color:#f5f5f7}.dk-stats span{font-size:14px;color:#a1a1a6}\\n.dk-list{list-style:none;padding:0;margin:24px 0}.dk-list li{display:flex;gap:12px;align-items:center;padding:10px 0;border-top:.5px solid rgba(255,255,255,.16);color:#f5f5f7;font-size:17px}\\n.dk-list li b{display:grid;place-items:center;flex:none;width:26px;height:26px;border-radius:50%;background:#f5f5f7;color:#000;font-size:13px}\\n@media(max-width:900px){.dk-features,.dk-tile{grid-template-columns:1fr}.dk-stage{aspect-ratio:4\\\/5;border-radius:24px}.dk-stage .dk-widget{left:16px;right:16px;bottom:16px;width:auto}.dk-stage.is-trio{grid-template-columns:1fr 1fr}.dk-stage.is-trio>img:nth-child(3){display:none}.dk-tile-copy{padding:40px 28px}.dk-tile img{min-height:300px}.dk-band{padding:64px 0}}\\n@media(prefers-reduced-motion:reduce){*{transition:none!important}}\\nDDWCCSS;\\n\\t$css  = str_replace( [ '__A__', '__D__', '__T__' ], [ $accent, $dark, $tint ], $css ) . $a['css'];\\n\\t$code = \\\"<?php\\\\n\\\/\\\/ Live Preview only: the demo kit's global stylesheet.\\\\nadd_action( 'wp_head', function () { echo '<style id=\\\\\\\"ddwc-demo-kit\\\\\\\">' . \\\" . var_export( $css, true ) . \\\" . '<\\\/style>'; }, 99 );\\\\n\\\";\\n\\twp_mkdir_p( WPMU_PLUGIN_DIR );\\n\\tfile_put_contents( WPMU_PLUGIN_DIR . '\\\/demo-style.php', $code );\\n}\\n\\n\\\/**\\n * Build the home page and make it the front page.\\n *\\n * @param array $h eyebrow, title, lead, ctas [ [label, url], [label, url] ] (first is the filled button),\\n *                 hero_img (url, or three urls for a photo trio), hero_alt, widget (HTML on the hero stage), after_ctas (HTML, e.g. a shortcode),\\n *                 features_title, features [ [title, text, icon] ], shelf_title, shelf_sub, shelf (shortcode),\\n *                 shelf_more [label, url], tile [title, text, cta [label, url], img, alt, extra HTML], script.\\n * @return int Page ID.\\n *\\\/\\nfunction ddwc_demo_kit_home( $h ) {\\n\\t$ctas = '';\\n\\tforeach ( $h['ctas'] as $i => $cta ) {\\n\\t\\t$ctas .= '<a class=\\\"' . ( $i ? 'dk-more' : 'dk-btn' ) . '\\\" href=\\\"' . esc_url( $cta[1] ) . '\\\">' . esc_html( $cta[0] ) . '<\\\/a>';\\n\\t}\\n\\t$features = '';\\n\\tforeach ( $h['features'] as $f ) {\\n\\t\\t$features .= '<div class=\\\"dk-feature\\\">' . ddwc_demo_kit_icon( $f[2], 36 ) . '<h3>' . $f[0] . '<\\\/h3><p>' . $f[1] . '<\\\/p><\\\/div>';\\n\\t}\\n\\t\\\/\\\/ One wide photo, or three product photos side by side (works with portrait shots).\\n\\t$trio = is_array( $h['hero_img'] );\\n\\t$imgs = '';\\n\\tforeach ( (array) $h['hero_img'] as $src ) {\\n\\t\\t$imgs .= '<img src=\\\"' . esc_url( $src ) . '\\\" alt=\\\"' . esc_attr( $h['hero_alt'] ) . '\\\"\\\/>';\\n\\t}\\n\\t$t    = $h['tile'];\\n\\t$more = $h['shelf_more'] ?? [ 'View all products', wc_get_page_permalink( 'shop' ) ];\\n\\t$html = '<!-- wp:html --><section class=\\\"dk-hero dk-wrap\\\"><span class=\\\"dk-eyebrow\\\">' . $h['eyebrow'] . '<\\\/span><h1>' . $h['title'] . '<\\\/h1><p class=\\\"dk-lead\\\">' . $h['lead'] . '<\\\/p><div class=\\\"dk-ctas\\\">' . $ctas . ( $h['after_ctas'] ?? '' ) . '<\\\/div>'\\n\\t\\t. '<div class=\\\"dk-stage' . ( $trio ? ' is-trio' : '' ) . '\\\">' . $imgs . $h['widget'] . '<\\\/div><\\\/section><!-- \\\/wp:html -->'\\n\\t\\t. '<!-- wp:html --><section class=\\\"dk-band\\\"><div class=\\\"dk-wrap\\\"><h2 class=\\\"dk-title\\\">' . $h['features_title'] . '<\\\/h2><div class=\\\"dk-features\\\">' . $features . '<\\\/div><\\\/div><\\\/section><!-- \\\/wp:html -->'\\n\\t\\t. '<!-- wp:html --><section class=\\\"dk-shelf dk-wrap\\\"><div class=\\\"dk-shelf-head\\\"><h2 class=\\\"dk-shelf-title\\\">' . $h['shelf_title'] . ' <span>' . $h['shelf_sub'] . '<\\\/span><\\\/h2><a class=\\\"dk-more\\\" href=\\\"' . esc_url( $more[1] ) . '\\\">' . esc_html( $more[0] ) . '<\\\/a><\\\/div><!-- \\\/wp:html -->'\\n\\t\\t. '<!-- wp:shortcode -->' . $h['shelf'] . '<!-- \\\/wp:shortcode -->'\\n\\t\\t. '<!-- wp:html --><\\\/section><!-- \\\/wp:html -->'\\n\\t\\t. '<!-- wp:html --><section class=\\\"dk-wrap\\\"><div class=\\\"dk-tile\\\"><div class=\\\"dk-tile-copy\\\"><h2>' . $t['title'] . '<\\\/h2><p>' . $t['text'] . '<\\\/p>' . ( $t['extra'] ?? '' ) . '<p><a class=\\\"dk-btn is-light\\\" href=\\\"' . esc_url( $t['cta'][1] ) . '\\\">' . esc_html( $t['cta'][0] ) . '<\\\/a><\\\/p><\\\/div><img src=\\\"' . esc_url( $t['img'] ) . '\\\" alt=\\\"' . esc_attr( $t['alt'] ) . '\\\"\\\/><\\\/div><\\\/section>' . ( $h['script'] ?? '' ) . '<!-- \\\/wp:html -->';\\n\\n\\t$id = wp_insert_post( [ 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => 'Home', 'post_content' => $html ] );\\n\\tforeach ( [ '_kad_post_title' => 'hide', '_kad_post_layout' => 'fullwidth', '_kad_post_content_style' => 'unboxed', '_kad_post_vertical_padding' => 'hide', '_kad_post_feature' => 'hide' ] as $k => $v ) {\\n\\t\\tupdate_post_meta( $id, $k, $v );\\n\\t}\\n\\tupdate_option( 'show_on_front', 'page' );\\n\\tupdate_option( 'page_on_front', $id );\\n\\twp_delete_post( 2, true ); \\\/\\\/ Sample Page.\\n\\twp_delete_post( 1, true ); \\\/\\\/ Hello world.\\n\\tupdate_option( 'permalink_structure', '\\\/%postname%\\\/' );\\n\\tflush_rewrite_rules();\\n\\treturn $id;\\n}\\n\\n\\\/**\\n * Primary menu.\\n *\\n * @param array $items label => url.\\n *\\\/\\nfunction ddwc_demo_kit_menu( $items ) {\\n\\t$menu_id = wp_create_nav_menu( 'Main menu' );\\n\\tif ( is_wp_error( $menu_id ) ) {\\n\\t\\t$menu_id = wp_get_nav_menu_object( 'Main menu' )->term_id;\\n\\t}\\n\\tforeach ( $items as $label => $url ) {\\n\\t\\twp_update_nav_menu_item( $menu_id, 0, [ 'menu-item-title' => $label, 'menu-item-url' => $url, 'menu-item-status' => 'publish', 'menu-item-type' => 'custom' ] );\\n\\t}\\n\\t$locations            = get_theme_mod( 'nav_menu_locations', [] );\\n\\t$locations['primary'] = $menu_id;\\n\\t$locations['mobile']  = $menu_id;\\n\\tset_theme_mod( 'nav_menu_locations', $locations );\\n}\\n\\n\\\/**\\n * Write the \\\"View as\\\" switcher mu-plugin.\\n *\\n * Pass a PHP expression string that returns the views array; each view:\\n *   [ 'label' => 'Store admin', 'hint' => 'Dashboard & settings', 'icon' => 'admin', 'user' => 'admin', 'url' => admin_url(...) ]\\n * user '' logs the visitor out. icon: any ddwc_demo_kit_icon() name.\\n *\\n * @param string $views_php PHP code (no <?php) that returns the array.\\n *\\\/\\nfunction ddwc_demo_kit_switcher( $views_php ) {\\n\\t$icons = [];\\n\\tforeach ( [ 'admin', 'customer', 'store', 'product', 'cart', 'chat', 'wallet', 'star', 'register', 'link', 'cube', 'rx', 'phone', 'orders', 'calendar' ] as $n ) {\\n\\t\\t$icons[ $n ] = ddwc_demo_kit_icon( $n, 18 );\\n\\t}\\n\\t$code = <<<'DDWCKIT'\\n<?php\\n\\\/**\\n * Live Preview only: \\\"View as\\\" switcher so visitors can jump between the store owner's\\n * admin and the shopper's side without any password.\\n *\\\/\\nfunction ddwc_demo_switcher_views() {\\n\\t__VIEWS__\\n}\\n\\nadd_action(\\n\\t'init',\\n\\tfunction () {\\n\\t\\tif ( ! isset( $_GET['ddwc_demo_view'] ) ) { \\\/\\\/ phpcs:ignore WordPress.Security.NonceVerification -- demo site only.\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\t\\t$views = ddwc_demo_switcher_views();\\n\\t\\t$view  = $views[ absint( $_GET['ddwc_demo_view'] ) ] ?? null; \\\/\\\/ phpcs:ignore WordPress.Security.NonceVerification\\n\\t\\tif ( ! $view ) {\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\t\\twp_clear_auth_cookie();\\n\\t\\twp_set_current_user( 0 );\\n\\t\\t$user = $view['user'] ? get_user_by( 'login', $view['user'] ) : null;\\n\\t\\tif ( $user ) {\\n\\t\\t\\twp_set_current_user( $user->ID );\\n\\t\\t\\twp_set_auth_cookie( $user->ID, true );\\n\\t\\t}\\n\\t\\twp_safe_redirect( $view['url'] );\\n\\t\\texit;\\n\\t},\\n\\t1\\n);\\n\\n\\\/\\\/ Live Preview: keep the storefront clean, the admin bar only appears in wp-admin.\\nadd_filter( 'show_admin_bar', '__return_false' );\\n\\nfunction ddwc_demo_switcher_render() {\\n\\t$icons   = __ICONS__;\\n\\t$views   = ddwc_demo_switcher_views();\\n\\t$current = wp_get_current_user();\\n\\t$here    = untrailingslashit( set_url_scheme( 'http:\\\/\\\/' . ( $_SERVER['HTTP_HOST'] ?? '' ) . ( $_SERVER['REQUEST_URI'] ?? '' ) ) ); \\\/\\\/ phpcs:ignore\\n\\t$items   = '';\\n\\t$label   = '';\\n\\tforeach ( $views as $i => $view ) {\\n\\t\\t$active = untrailingslashit( set_url_scheme( $view['url'] ) ) === $here && ( ! $view['user'] || ( $current->exists() && $current->user_login === $view['user'] ) );\\n\\t\\tif ( $active ) {\\n\\t\\t\\t$label = $view['label'];\\n\\t\\t}\\n\\t\\t$items .= sprintf(\\n\\t\\t\\t'<a href=\\\"%s\\\" class=\\\"ddwc-ds-item%s\\\"><span class=\\\"ddwc-ds-ico\\\">%s<\\\/span><span class=\\\"ddwc-ds-text\\\"><strong>%s<\\\/strong><small>%s<\\\/small><\\\/span><\\\/a>',\\n\\t\\t\\tesc_url( add_query_arg( 'ddwc_demo_view', $i, home_url( '\\\/' ) ) ),\\n\\t\\t\\t$active ? ' is-active' : '',\\n\\t\\t\\t$icons[ $view['icon'] ?? 'store' ] ?? $icons['store'],\\n\\t\\t\\tesc_html( $view['label'] ),\\n\\t\\t\\tesc_html( $view['hint'] ?? '' )\\n\\t\\t);\\n\\t}\\n\\t?>\\n\\t<div id=\\\"ddwc-demo-switcher\\\">\\n\\t\\t<div class=\\\"ddwc-ds-panel\\\" role=\\\"menu\\\">\\n\\t\\t\\t<div class=\\\"ddwc-ds-head\\\">Explore this live demo<\\\/div>\\n\\t\\t\\t<?php echo $items; \\\/\\\/ phpcs:ignore WordPress.Security.EscapeOutput -- escaped above. ?>\\n\\t\\t<\\\/div>\\n\\t\\t<button type=\\\"button\\\" class=\\\"ddwc-ds-toggle\\\" aria-expanded=\\\"false\\\">\\n\\t\\t\\t<span class=\\\"ddwc-ds-dot\\\"><\\\/span>\\n\\t\\t\\t<span>View as<?php echo $label ? ' <b>' . esc_html( $label ) . '<\\\/b>' : ''; ?><\\\/span>\\n\\t\\t\\t<svg viewBox=\\\"0 0 24 24\\\" width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.2\\\" stroke-linecap=\\\"round\\\" aria-hidden=\\\"true\\\"><path d=\\\"m6 15 6-6 6 6\\\"\\\/><\\\/svg>\\n\\t\\t<\\\/button>\\n\\t<\\\/div>\\n\\t<style>\\n\\t\\t#ddwc-demo-switcher{position:fixed;left:20px;bottom:20px;z-index:999999;font:400 14px\\\/1.3 -apple-system,BlinkMacSystemFont,\\\"SF Pro Text\\\",\\\"Helvetica Neue\\\",Arial,sans-serif;letter-spacing:-.01em;color:#1d1d1f;-webkit-font-smoothing:antialiased}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-toggle{display:flex;align-items:center;gap:9px;padding:10px 16px;border:0;border-radius:980px;background:rgba(29,29,31,.82);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);color:#f5f5f7;font:inherit;cursor:pointer;box-shadow:0 10px 30px rgba(0,0,0,.24)}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-toggle b{font-weight:600;color:#fff}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-toggle svg{transition:transform .25s cubic-bezier(.25,.1,.25,1);opacity:.7}\\n\\t\\t#ddwc-demo-switcher.is-open .ddwc-ds-toggle svg{transform:rotate(180deg)}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-dot{width:7px;height:7px;border-radius:50%;background:#30d158;box-shadow:0 0 0 3px rgba(48,209,88,.28)}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-panel{position:absolute;left:0;bottom:calc(100% + 10px);width:300px;max-width:calc(100vw - 40px);padding:6px;border-radius:18px;background:rgba(255,255,255,.82);-webkit-backdrop-filter:saturate(180%) blur(24px);backdrop-filter:saturate(180%) blur(24px);box-shadow:0 24px 70px rgba(0,0,0,.22),inset 0 0 0 .5px rgba(0,0,0,.08);opacity:0;visibility:hidden;transform:translateY(6px) scale(.98);transform-origin:bottom left;transition:opacity .2s,transform .25s cubic-bezier(.25,.1,.25,1),visibility .2s}\\n\\t\\t#ddwc-demo-switcher.is-open .ddwc-ds-panel{opacity:1;visibility:visible;transform:none}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-head{padding:10px 12px 8px;font-size:12px;font-weight:600;color:#6e6e73}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-item{display:flex;align-items:center;gap:12px;padding:9px 10px;border-radius:12px;color:#1d1d1f;text-decoration:none}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-item:hover{background:rgba(0,0,0,.05)}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-item.is-active{background:rgba(0,113,227,.1)}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-ico{flex:none;display:grid;place-items:center;width:32px;height:32px;border-radius:9px;background:#e8e8ed;color:#1d1d1f}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-item.is-active .ddwc-ds-ico{background:#0071e3;color:#fff}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-text{display:flex;flex-direction:column;min-width:0}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-text strong{font-weight:600;font-size:14px}\\n\\t\\t#ddwc-demo-switcher .ddwc-ds-text small{font-size:12px;color:#6e6e73}\\n\\t\\t@media (max-width:782px){#ddwc-demo-switcher{left:12px;bottom:auto;top:58px}#ddwc-demo-switcher .ddwc-ds-panel{bottom:auto;top:calc(100% + 10px);transform-origin:top left}}\\n\\t<\\\/style>\\n\\t<script>\\n\\t\\t(function(){var w=document.getElementById('ddwc-demo-switcher');if(!w)return;var b=w.querySelector('.ddwc-ds-toggle');b.addEventListener('click',function(e){e.stopPropagation();var o=w.classList.toggle('is-open');b.setAttribute('aria-expanded',o)});document.addEventListener('click',function(e){if(!w.contains(e.target)){w.classList.remove('is-open');b.setAttribute('aria-expanded','false')}});try{if(!sessionStorage.getItem('ddwcDemoSeen')){w.classList.add('is-open');sessionStorage.setItem('ddwcDemoSeen','1');setTimeout(function(){w.classList.remove('is-open');b.setAttribute('aria-expanded','false')},5000)}}catch(e){}})();\\n\\t<\\\/script>\\n\\t<?php\\n}\\nadd_action( 'wp_footer', 'ddwc_demo_switcher_render' );\\nadd_action( 'admin_footer', 'ddwc_demo_switcher_render' );\\nDDWCKIT;\\n\\twp_mkdir_p( WPMU_PLUGIN_DIR );\\n\\tfile_put_contents( WPMU_PLUGIN_DIR . '\\\/demo-switcher.php', str_replace( [ '__VIEWS__', '__ICONS__' ], [ $views_php, var_export( $icons, true ) ], $code ) );\\n}\\n\\n\\nwp_set_current_user( 1 );\\nddwc_demo_kit_style( [ 'accent' => '#2F4BE8', 'css' => '.ddwcwr-ui,.ddwcwr-product-policy,.ddwcwr-footer-withdrawal{--ddwcwr-accent:#2F4BE8;--ddwcwr-tint:rgba(47,75,232,.08)}.ddwcwr-footer-withdrawal{text-align:center;padding:14px 0;font-size:14px}' ] );\\n\\n$shop    = wc_get_page_permalink( 'shop' );\\n$account = wc_get_page_permalink( 'myaccount' );\\n$returns = wc_get_endpoint_url( 'returns', '', $account );\\n$portal  = get_permalink( get_option( 'ddwcwr_portal_page_id' ) );\\nddwc_demo_kit_home( [\\n\\t'eyebrow'        => 'Free returns for 30 days',\\n\\t'title'          => 'Clothes you keep. Returns that take a minute.',\\n\\t'lead'           => 'Linen, cotton and wool made to wear every day. Not the right fit? Start a return from your account or our returns page, and follow it to the refund.',\\n\\t'ctas'           => [ [ 'Shop the collection', $shop ], [ 'Start a return \\u203a', $portal ] ],\\n\\t'hero_img'       => [ ddwc_demo_kit_img( $ids['overshirt'] ), ddwc_demo_kit_img( $ids['sweater'] ), ddwc_demo_kit_img( $ids['dress'] ) ],\\n\\t'hero_alt'       => 'Loom & Field clothing',\\n\\t'widget'         => '<div class=\\\"dk-widget\\\"><div class=\\\"dk-w-head\\\"><span class=\\\"dk-w-app\\\">' . ddwc_demo_kit_icon( 'orders' ) . '<\\\/span><span><span class=\\\"dk-w-label\\\">Order #1042<\\\/span><span class=\\\"dk-w-title\\\">Linen Overshirt<\\\/span><\\\/span><\\\/div>'\\n\\t\\t. '<div class=\\\"dk-w-row\\\"><span>Reason<\\\/span><span>Wrong size or fit<\\\/span><\\\/div><div class=\\\"dk-w-row is-total\\\"><span>Refund<\\\/span><span>$84.00<\\\/span><\\\/div>'\\n\\t\\t. '<span class=\\\"dk-w-pill\\\">Return requested<\\\/span><\\\/div>',\\n\\t'features_title' => 'Send it back in three steps.',\\n\\t'features'       => [\\n\\t\\t[ 'Return from your account', 'Pick the items, the reason and add a photo. We reply on the same page.', 'customer' ],\\n\\t\\t[ 'No account? No problem', 'Enter your order number and email on our returns page to start a return as a guest.', 'link' ],\\n\\t\\t[ 'EU withdrawal button', 'Customers in the EU and EEA can withdraw from an order within 14 days with one button.', 'check' ],\\n\\t],\\n\\t'shelf_title'    => 'New this season.',\\n\\t'shelf_sub'      => 'Free returns on everything but socks.',\\n\\t'shelf'          => '[products ids=\\\"' . implode( ',', [ $ids['overshirt'], $ids['sweater'], $ids['dress'], $ids['jacket'], $ids['cord'], $ids['cardigan'], $ids['poplin'], $ids['derby'] ] ) . '\\\" columns=\\\"4\\\" limit=\\\"8\\\" orderby=\\\"post__in\\\"]',\\n\\t'shelf_more'     => [ 'View all clothing', $shop ],\\n\\t'tile'           => [\\n\\t\\t'title' => 'Every return. One place.',\\n\\t\\t'text'  => 'See what you sent back, where it is and what you got paid, in My Account under Returns.',\\n\\t\\t'cta'   => [ 'View my returns', $returns ],\\n\\t\\t'img'   => ddwc_demo_kit_img( $ids['cardigan'] ),\\n\\t\\t'alt'   => 'Oat wool cardigan',\\n\\t],\\n] );\\nddwc_demo_kit_menu( [ 'Shop' => $shop, 'Returns' => $portal, 'My account' => $account ] );\\n\\nddwc_demo_kit_switcher( <<<'DDWCVIEWS'\\n$account = wc_get_page_permalink( 'myaccount' );\\n\\treturn [\\n\\t\\t[ 'label' => 'Return requests', 'hint' => 'Tillie reviews and refunds requests', 'icon' => 'admin', 'user' => 'admin', 'url' => admin_url( 'admin.php?page=ddwcwr-dashboard&menu=requests' ) ],\\n\\t\\t[ 'label' => 'Customer returns', 'hint' => 'Amara follows her returns', 'icon' => 'customer', 'user' => 'amara', 'url' => wc_get_endpoint_url( 'returns', '', $account ) ],\\n\\t\\t[ 'label' => 'Guest returns page', 'hint' => 'Order number and email, no login', 'icon' => 'link', 'user' => '', 'url' => get_permalink( get_option( 'ddwcwr_portal_page_id' ) ) ],\\n\\t\\t[ 'label' => 'Storefront', 'hint' => 'The shop your customers see', 'icon' => 'store', 'user' => '', 'url' => home_url( '\\\/' ) ],\\n\\t];\\nDDWCVIEWS\\n);\\n\"},{\"step\":\"login\",\"username\":\"admin\",\"password\":\"password\"}]}"}},"all_blocks":{"ddwcwr\/returns-portal":{"name":"ddwcwr\/returns-portal","title":"Returns portal"},"ddwcwr\/withdrawal-form":{"name":"ddwcwr\/withdrawal-form","title":"Withdrawal form"}},"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3794198,"resolution":"1","location":"assets","locale":"","width":1600,"height":1000},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3794198,"resolution":"10","location":"assets","locale":"","width":1600,"height":1000},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3794198,"resolution":"2","location":"assets","locale":"","width":1600,"height":1000},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3794198,"resolution":"3","location":"assets","locale":"","width":1600,"height":1000},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3794198,"resolution":"4","location":"assets","locale":"","width":1600,"height":1000},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3794198,"resolution":"5","location":"assets","locale":"","width":1600,"height":1000},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3794198,"resolution":"6","location":"assets","locale":"","width":1600,"height":1000},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3794198,"resolution":"7","location":"assets","locale":"","width":1600,"height":1000},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3794198,"resolution":"8","location":"assets","locale":"","width":1600,"height":1000},"screenshot-9.png":{"filename":"screenshot-9.png","revision":3794198,"resolution":"9","location":"assets","locale":"","width":1600,"height":1000}},"screenshots":{"1":"Customers start a return from My Account: pick the items, a reason and the condition, then add a note or photos.","2":"Guests find their order with the order number and email on the returns page, no account needed.","3":"The EU \"Withdraw from contract here\" function: a two-step withdrawal statement for orders from the EU and EEA.","4":"Customers get an on-screen confirmation and an email with the date and time their withdrawal was received.","5":"Each request has its own page with the progress, the return label, tracking and messages with your team.","6":"All returns, cancellations and EU withdrawals in one list with status tabs, filters and search.","7":"The request screen: approve or reject, upload a return label, mark items received and refund from one place.","8":"Set the return window, final sale categories and what customers can upload.","9":"Turn on the EU withdrawal function and choose the countries, the withdrawal period and where the link shows.","10":"Ten WooCommerce emails keep customers and your team updated at every step."}},"plugin_section":[],"plugin_tags":[144997,273339,170592,262873,221713],"plugin_category":[],"plugin_contributors":[220149],"plugin_business_model":[],"class_list":["post-399214","plugin","type-plugin","status-publish","hentry","plugin_tags-cancel-order","plugin_tags-refund-request","plugin_tags-rma","plugin_tags-withdrawal-button","plugin_tags-woocommerce-returns","plugin_contributors-devdiggers","plugin_committers-devdiggers"],"banners":{"banner":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/banner-772x250.png?rev=3794198","banner_2x":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/banner-1544x500.png?rev=3794198","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/icon-128x128.gif?rev=3794198","icon_2x":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/icon-256x256.gif?rev=3794198","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-1.png?rev=3794198","caption":"Customers start a return from My Account: pick the items, a reason and the condition, then add a note or photos."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-2.png?rev=3794198","caption":"Guests find their order with the order number and email on the returns page, no account needed."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-3.png?rev=3794198","caption":"The EU \"Withdraw from contract here\" function: a two-step withdrawal statement for orders from the EU and EEA."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-4.png?rev=3794198","caption":"Customers get an on-screen confirmation and an email with the date and time their withdrawal was received."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-5.png?rev=3794198","caption":"Each request has its own page with the progress, the return label, tracking and messages with your team."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-6.png?rev=3794198","caption":"All returns, cancellations and EU withdrawals in one list with status tabs, filters and search."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-7.png?rev=3794198","caption":"The request screen: approve or reject, upload a return label, mark items received and refund from one place."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-8.png?rev=3794198","caption":"Set the return window, final sale categories and what customers can upload."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-9.png?rev=3794198","caption":"Turn on the EU withdrawal function and choose the countries, the withdrawal period and where the link shows."},{"src":"https:\/\/ps.w.org\/devdiggers-returns-for-woocommerce\/assets\/screenshot-10.png?rev=3794198","caption":"Ten WooCommerce emails keep customers and your team updated at every step."}],"raw_content":"<!--section=description-->\n<p>Most stores still handle returns by email. The customer writes in, you ask for the order number, then for photos, then you work out the refund by hand and hope you remember to restock the item.<\/p>\n\n<p>This is a free <strong><a href=\"https:\/\/wpreturns.com\/\">WooCommerce returns plugin<\/a><\/strong> that gives your customers a proper returns portal and gives you one RMA screen for every return, refund and cancel order request. Customers pick the items, a reason and a quantity, add photos and send the request. You approve it, upload a return label if you have one, mark the parcel received and refund it through WooCommerce in one click. Stock goes back automatically.<\/p>\n\n<p>It also adds the <strong>EU withdrawal button<\/strong>. Since 19 June 2026, online shops selling to consumers in the EU must offer a \"Withdraw from contract here\" function with a confirmation step and an acknowledgement on a durable medium (Directive (EU) 2023\/2673). The plugin adds the button, the confirmation step and the acknowledgement email, for guests and account holders. Check your own obligations with a lawyer in the countries you sell to.<\/p>\n\n<p>Everything runs inside WooCommerce on your own server. No account to sign up for, no per-return fees, and no customer or order data sent anywhere.<\/p>\n\n<p>https:\/\/www.youtube.com\/watch?v=AFI6gmH5g7I<\/p>\n\n<h4>Quick Links<\/h4>\n\n<ul>\n<li>Free Demo: use the Live Preview button on this page<\/li>\n<li><a href=\"https:\/\/demo.devdiggers.com\/wpreturns\/\">Pro Demo<\/a><\/li>\n<li><a href=\"https:\/\/wpreturns.com\/docs\/\">Documentation<\/a><\/li>\n<li><a href=\"https:\/\/wordpress.org\/support\/plugin\/devdiggers-returns-for-woocommerce\/\">Support<\/a><\/li>\n<li><a href=\"https:\/\/wpreturns.com\/free-vs-pro\/\">Free vs Pro Comparison<\/a><\/li>\n<li><a href=\"https:\/\/wpreturns.com\/pricing\/\">Upgrade to Pro<\/a><\/li>\n<\/ul>\n\n<h4>How a return works<\/h4>\n\n<ol>\n<li>The customer opens the order in My Account, or finds it on the guest returns portal with the order number and billing email. The order shows how many days are left to return it.<\/li>\n<li>They choose the items, the quantity, a reason and the condition, write a note and add photos or videos.<\/li>\n<li>You get an email. On the request screen you see the items, photos and the conversation, and approve or reject.<\/li>\n<li>Upload a return label (any carrier) or let the customer use their own. They add the tracking number.<\/li>\n<li>When the parcel arrives, mark it received. Items go back in stock, except damaged or defective ones.<\/li>\n<li>Refund to the original payment method in one click. The customer is emailed at every step.<\/li>\n<\/ol>\n\n<h4>Key Features<\/h4>\n\n<h3>Customer returns portal in My Account and for guests<\/h3>\n\n<p>Logged in customers get a Returns page in My Account and a \"Request a return\" button on every eligible order. Guests use the returns portal with their order number and billing email, no account needed.<\/p>\n\n<ul>\n<li><strong>Guest returns portal<\/strong> with the shortcode <code>[ddwcwr_returns_portal]<\/code>, a Returns portal block, and a page created for you on activation.<\/li>\n<li><strong>Partial returns<\/strong> with a quantity per item.<\/li>\n<li>A reason and condition per item, a customer note, and <strong>photo and video uploads<\/strong> with your own file count, size and type limits.<\/li>\n<li>Return reasons you manage yourself, as many as you like, with \"Photo required\" per reason.<\/li>\n<li>\"You can request a return until 15 November (16 days left)\" on every eligible order, so customers know where they stand.<\/li>\n<li>A request page with a progress tracker, a message thread with your team (with attachments), the return label download and a tracking number field.<\/li>\n<li>You choose which order statuses can be returned, and you can rename the My Account menu item and its URL.<\/li>\n<\/ul>\n\n<h3>Cancel order requests before shipping<\/h3>\n\n<p>Customers can ask to cancel an order that has not shipped yet. You choose which order statuses allow it.<\/p>\n\n<ul>\n<li>A \"Request cancellation\" button on eligible orders in My Account and on the guest portal.<\/li>\n<li>Approving the request cancels the order and refunds it through WooCommerce.<\/li>\n<\/ul>\n\n<h3>Return policy, return window and final-sale items<\/h3>\n\n<ul>\n<li>One return window for the store, counted from delivery or from purchase.<\/li>\n<li><strong>Final-sale products and categories.<\/strong> Tick \"Final sale\" on a product or pick final-sale categories, and those items can no longer be selected on the return form. The product page says so before the customer buys.<\/li>\n<li>The return policy line on product pages and above the Place order button, in classic and block checkout, with a link to your return policy page.<\/li>\n<\/ul>\n\n<h3>EU withdrawal button (Widerrufsbutton)<\/h3>\n\n<ul>\n<li>Step 1: a \"Withdraw from contract here\" link in the footer, in My Account, on eligible orders and in the order emails.<\/li>\n<li>Step 2: the withdrawal statement (name, order, email), prefilled for logged in customers, then a \"Confirm withdrawal\" button.<\/li>\n<li>An <strong>acknowledgement email<\/strong> with the full statement and the date and time it was received, sent at once.<\/li>\n<li>The <strong>model withdrawal form<\/strong> (Annex I(B)) on the withdrawal page, addressed to your store, for customers who prefer to write.<\/li>\n<li>A withdrawal page created on activation, plus the shortcode <code>[ddwcwr_withdrawal_form]<\/code> and a Withdrawal form block.<\/li>\n<li>Order and email matching, a honeypot and a rate limit stop people using the form to email strangers. Statements that do not match an order are still kept for you.<\/li>\n<li>Art. 16 exemptions per product and per category (made to order, perishable, sealed hygiene goods and so on).<\/li>\n<li><strong>Consent for digital content<\/strong> (Art. 16(m)): when the cart has downloadable products, checkout shows a required checkbox. The customer agrees to immediate supply, the order emails confirm it and those downloads leave the withdrawal flow. Works in classic and block checkout. Off by default.<\/li>\n<li>EU and EEA countries, all countries or the countries you choose, with your own withdrawal period.<\/li>\n<li>A Withdrawals screen with every statement and a <strong>CSV export<\/strong>, your record if there is ever a dispute.<\/li>\n<\/ul>\n\n<h3>RMA screen for the shop team<\/h3>\n\n<ul>\n<li>A dashboard with requests, open requests, refunds, withdrawals and time to resolve, plus a requests chart.<\/li>\n<li>A Requests list with status tabs and counts, filters by type, reason and date, and search by request, order, name, email or tracking number.<\/li>\n<li>A request screen with a \"Next step\" card, items, photos, the conversation, internal notes and a full history.<\/li>\n<li>Approve, reject, upload a label, save tracking, mark received with restock, and <strong>refund through WooCommerce<\/strong> (to the gateway or recorded only).<\/li>\n<li>Create a request yourself for phone or email returns.<\/li>\n<li>Rename and recolor the seven built-in statuses, add your own (such as \"Inspecting\"), and choose which ones email the customer.<\/li>\n<li>A Returns box on the order screen and a Returns column in the orders list.<\/li>\n<li>A setup wizard on first activation.<\/li>\n<\/ul>\n\n<h3>Import requests from another returns plugin<\/h3>\n\n<p>Switching plugins does not mean losing your history. The Import tab finds requests left by other returns, cancellation and withdrawal plugins, even after they are deactivated, and brings them over with their items, status, dates and messages.<\/p>\n\n<p>Supported: Return Refund and Exchange for WooCommerce, Flexible Refund and Return Order, YITH Advanced Refund System, Germanized for WooCommerce, Shiptastic for WooCommerce, WC Cancel Order, Cancel Order Request for WooCommerce, Order Cancellation &amp; Returns, Withdrawal Button \u2013 Easy Return and BuddyPilot Withdrawal.<\/p>\n\n<h3>Built the WooCommerce way<\/h3>\n\n<ul>\n<li>Every email is a WooCommerce email: edit it under WooCommerce &gt; Settings &gt; Emails or switch it off from the plugin.<\/li>\n<li>Photos are stored in a private folder and only shown to the customer and your team.<\/li>\n<li>GDPR export and erase for every request. Withdrawal records are anonymized, not deleted.<\/li>\n<li>HPOS, block and classic checkout, RTL and translation ready, with a <code>wpml-config.xml<\/code> so WPML and Polylang can translate your reasons, statuses and policy line.<\/li>\n<\/ul>\n\n<h4>Free vs Pro<\/h4>\n\n<p>The free plugin covers the full return, refund, cancel order and EU withdrawal workflow with no limits on requests. <a href=\"https:\/\/wpreturns.com\/pricing\/\">Pro<\/a> is for stores where returns are a cost worth managing: it turns refunds into store credit and exchanges, decides routine requests for you and shows where returns come from.<\/p>\n\n<h3>Store credit and exchanges (Pro)<\/h3>\n\n<ul>\n<li><strong>Store credit<\/strong> as a coupon or DevDiggers Wallet balance, with a bonus to make it the customer's first choice.<\/li>\n<li><strong>Exchanges<\/strong> for another size, color or any product, with the price difference charged or refunded on a linked order.<\/li>\n<li><strong>Warranty claims<\/strong> with warranty per product, and <strong>extended warranties<\/strong> sold on the product page.<\/li>\n<\/ul>\n\n<h3>Rules and automation (Pro)<\/h3>\n\n<ul>\n<li><strong>Return rules<\/strong>: windows per product, category, role or country, final-sale rules by item price, order total or customer, auto-approve and auto-reject, restocking fees, return shipping fees, free return shipping thresholds, photo rules and keep-it refunds.<\/li>\n<li><strong>Automation<\/strong>: instant cancellations, label and ship-by reminders, auto-close of stale requests and automatic refunds after receipt.<\/li>\n<li><strong>Bulk actions<\/strong> on the Requests list.<\/li>\n<\/ul>\n\n<h3>Shipping labels and fraud protection (Pro)<\/h3>\n\n<ul>\n<li><strong>Prepaid return labels<\/strong> from your EasyPost or Shippo account, automatically on approval, and a printable return slip with a QR code.<\/li>\n<li><strong>Fraud protection<\/strong>: return rate per customer, serial returner, wear-and-return and high-value flags, a risk score, a Customers screen and a blocklist. EU withdrawals are only flagged, never refused.<\/li>\n<\/ul>\n\n<h3>Analytics, team and developers (Pro)<\/h3>\n\n<ul>\n<li><strong>Analytics<\/strong>: return rate, revenue kept, top reasons, categories and most returned products, with a full CSV export of every request.<\/li>\n<li>Team permissions and assignment, appearance settings, REST API and WooCommerce webhooks.<\/li>\n<\/ul>\n\n<p>Pro uses the same tables and settings, so every request, message, photo and withdrawal you collect in the free plugin carries over when you upgrade.<\/p>\n\n<h3>External services<\/h3>\n\n<p>The free plugin does not send customer or order data to any outside service. The bundled DevDiggers Framework, which builds the admin screens, connects to the services below, and WordPress core may load Gravatar images.<\/p>\n\n<p><strong>1. DevDiggers plugin catalog (Extensions page)<\/strong><\/p>\n\n<ul>\n<li>What it is: A public endpoint on devdiggers.com that lists DevDiggers plugins.<\/li>\n<li>What it is used for: Showing other DevDiggers plugins on the Extensions admin page.<\/li>\n<li>When data is sent: Only when an administrator opens the Extensions page. The response is cached for 24 hours, so the request runs at most once a day. No other screen makes this request.<\/li>\n<li>What data is sent: A standard outbound HTTP request only, meaning your server's IP address and a user agent string. No personal data and no store data are sent. The page also loads each listed extension's image from devdiggers.com in the administrator's browser.<\/li>\n<li>Endpoint: https:\/\/devdiggers.com\/wp-json\/ddwcs\/v1\/plugins<\/li>\n<\/ul>\n\n<p><strong>2. Newsletter subscription (optional)<\/strong><\/p>\n\n<ul>\n<li>What it is: A contact and newsletter endpoint on devdiggers.com.<\/li>\n<li>What it is used for: Adding your email address to the DevDiggers newsletter, only if you choose to subscribe.<\/li>\n<li>When data is sent: Only when an administrator submits the optional newsletter form on the DevDiggers Plugins dashboard. Nothing is sent automatically.<\/li>\n<li>What data is sent: The email address you enter and your site URL.<\/li>\n<li>Endpoint: https:\/\/devdiggers.com\/?fluentcrm=1&amp;route=contact<\/li>\n<\/ul>\n\n<p>The services above are provided by DevDiggers: Terms and Conditions https:\/\/devdiggers.com\/terms-and-conditions\/ and Privacy Policy https:\/\/devdiggers.com\/privacy-policy\/.<\/p>\n\n<p><strong>3. Gravatar (avatar images)<\/strong><\/p>\n\n<ul>\n<li>What it is: Gravatar, the avatar service operated by Automattic, used through WordPress core's <code>get_avatar()<\/code>.<\/li>\n<li>What it is used for: Showing the customer's avatar on the request screen and the administrator's avatar in the plugin dashboard header. This is standard WordPress behaviour.<\/li>\n<li>When data is sent: When those admin screens are viewed and avatars are enabled under Settings &gt; Discussion. Turning avatars off there stops the requests.<\/li>\n<li>What data is sent: A hash of the email address inside the image URL, plus the usual request data such as IP address and user agent.<\/li>\n<li>Endpoint: https:\/\/secure.gravatar.com\/avatar\/<\/li>\n<li>Terms of Service: https:\/\/automattic.com\/tos\/ \u2013 Privacy Policy: https:\/\/automattic.com\/privacy\/<\/li>\n<\/ul>\n\n<p>This plugin contains no licence checks, no update checks and no telemetry.<\/p>\n\n<h3>Source code and build tools<\/h3>\n\n<p>The admin, storefront and block editor JavaScript and CSS are compiled from the <code>src\/<\/code> folder with webpack and Babel. The complete, human readable source code, including all build configuration, is published in our public GitHub repository:<\/p>\n\n<p>https:\/\/github.com\/DevDiggers-Technologies\/returns-for-woocommerce<\/p>\n\n<p>To build the assets from source:<\/p>\n\n<ol>\n<li>Run <code>npm install<\/code> to install the build dependencies listed in <code>package.json<\/code>.<\/li>\n<li>Run <code>npm run build<\/code> to compile the production assets into <code>assets\/js<\/code> and <code>assets\/css<\/code>.<\/li>\n<\/ol>\n\n<p>The build configuration is in <code>webpack.config.js<\/code> and <code>babel.config.js<\/code>.<\/p>\n\n<p>The admin screens share the bundled DevDiggers Framework. The human readable source of its compiled files in <code>devdiggers-framework\/assets\/js<\/code> and <code>devdiggers-framework\/assets\/css<\/code> (framework, dashboard, dashboard analytics, setup wizard and review notice) is in the same GitHub repository under <code>devdiggers-framework\/src<\/code>, with its own <code>package.json<\/code>, <code>webpack.config.js<\/code> and <code>babel.config.js<\/code>. To rebuild them, run <code>npm install<\/code> and then <code>npm run build<\/code> inside the <code>devdiggers-framework<\/code> folder.<\/p>\n\n<p>Two third party libraries used by the admin screens ship unmodified under the MIT licence inside <code>devdiggers-framework\/assets\/js\/<\/code>: Chart.js (https:\/\/www.chartjs.org) and Select2 (https:\/\/select2.org).<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate WooCommerce.<\/li>\n<li>Go to Plugins &gt; Add New Plugin, search for \"returns portal withdrawal button\", then install and activate this plugin. Or upload the <code>devdiggers-returns-for-woocommerce<\/code> folder to <code>\/wp-content\/plugins\/<\/code> and activate it.<\/li>\n<li>The setup wizard opens and asks a few questions.<\/li>\n<li>The \"Returns\" and \"Withdraw from contract\" pages are created for you. Add them to your menus or footer.<\/li>\n<li>Check DevDiggers Plugins &gt; DevDiggers Returns &gt; Configuration, especially the Return Policy and EU Withdrawal tabs.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20the%20eu%20withdrawal%20button%3F\"><h3>Do I need the EU withdrawal button?<\/h3><\/dt>\n<dd><p>If you sell to consumers in the EU or EEA, yes. Since 19 June 2026 online shops must offer a withdrawal function next to the usual ways of withdrawing. It is on by default for orders from EU and EEA countries, and you can switch it off or choose the countries.<\/p><\/dd>\n<dt id=\"is%20the%20withdrawal%20function%20free%20forever%3F\"><h3>Is the withdrawal function free forever?<\/h3><\/dt>\n<dd><p>Yes. The whole EU withdrawal flow, the acknowledgement email, the model withdrawal form, the withdrawal log and its CSV export are part of the free plugin.<\/p><\/dd>\n<dt id=\"what%20is%20the%20difference%20between%20a%20return%20and%20a%20withdrawal%3F\"><h3>What is the difference between a return and a withdrawal?<\/h3><\/dt>\n<dd><p>A return follows your own return policy: your window, your reasons, your final-sale items. A withdrawal is the customer's legal right in the EU to cancel a distance contract within 14 days without a reason. The plugin keeps them apart, so a final-sale item cannot be returned but can still be withdrawn from unless it is exempt under Art. 16.<\/p><\/dd>\n<dt id=\"can%20guests%20return%20items%20without%20an%20account%3F\"><h3>Can guests return items without an account?<\/h3><\/dt>\n<dd><p>Yes. The guest returns portal finds the order by order number and billing email, and guests get a private link to follow their request.<\/p><\/dd>\n<dt id=\"can%20customers%20return%20only%20some%20of%20the%20items%3F\"><h3>Can customers return only some of the items?<\/h3><\/dt>\n<dd><p>Yes. They pick the items and the quantity of each one.<\/p><\/dd>\n<dt id=\"can%20customers%20cancel%20an%20order%20from%20my%20account%3F\"><h3>Can customers cancel an order from My Account?<\/h3><\/dt>\n<dd><p>They can send a cancel order request for orders that have not shipped. You choose the order statuses that allow it under Configuration &gt; General. When you approve the request, the order is cancelled and refunded through WooCommerce.<\/p><\/dd>\n<dt id=\"how%20do%20i%20stop%20returns%20on%20sale%20items%20or%20certain%20products%3F\"><h3>How do I stop returns on sale items or certain products?<\/h3><\/dt>\n<dd><p>Tick \"Final sale\" on the product's General tab, or choose final-sale categories under Configuration &gt; Return Policy. Those items are shown as not returnable on the return form and the product page. Pro adds final-sale rules by item price, order total or customer.<\/p><\/dd>\n<dt id=\"does%20it%20refund%20through%20my%20payment%20gateway%3F\"><h3>Does it refund through my payment gateway?<\/h3><\/dt>\n<dd><p>Refunds are WooCommerce refunds, so they go through your gateway when it supports refunds (Stripe, PayPal and most others). You can also record a refund and pay it back yourself.<\/p><\/dd>\n<dt id=\"can%20i%20charge%20a%20restocking%20fee%20or%20offer%20store%20credit%20instead%20of%20a%20refund%3F\"><h3>Can I charge a restocking fee or offer store credit instead of a refund?<\/h3><\/dt>\n<dd><p>Those are Pro features, along with exchanges, warranty claims, return rules and prepaid labels.<\/p><\/dd>\n<dt id=\"how%20is%20it%20different%20from%20other%20woocommerce%20returns%20plugins%3F\"><h3>How is it different from other WooCommerce returns plugins?<\/h3><\/dt>\n<dd><p>The guest returns portal, partial returns with quantities and photo uploads are free here, while several other returns plugins keep them for their paid version. It is also a full EU withdrawal button, so you do not need a second plugin for that.<\/p><\/dd>\n<dt id=\"can%20i%20move%20my%20requests%20over%20from%20another%20returns%20plugin%3F\"><h3>Can I move my requests over from another returns plugin?<\/h3><\/dt>\n<dd><p>Yes. Go to Configuration &gt; Import. It lists the supported plugins it finds on your site, even deactivated ones, and imports their requests with items, status, dates and messages. Running it again only brings over new requests.<\/p><\/dd>\n<dt id=\"where%20are%20customer%20photos%20stored%3F\"><h3>Where are customer photos stored?<\/h3><\/dt>\n<dd><p>In a private folder inside uploads with random file names, never in the media library. They are only served after checking that the visitor is the customer (or has the private request link) or a shop manager. On Apache the folder is also blocked with .htaccess. On nginx add <code>location ~ \/ddwcwr-private- { deny all; }<\/code>, or move the folder with the <code>ddwcwr_private_upload_dir<\/code> filter.<\/p><\/dd>\n<dt id=\"can%20i%20translate%20the%20return%20reasons%20and%20statuses%3F\"><h3>Can I translate the return reasons and statuses?<\/h3><\/dt>\n<dd><p>Yes. All plugin text is translation ready, and the bundled <code>wpml-config.xml<\/code> lets WPML and Polylang translate your own reasons, status names, policy line and My Account menu label.<\/p><\/dd>\n<dt id=\"i%20sell%20downloads.%20do%20customers%20keep%20the%20right%20of%20withdrawal%3F\"><h3>I sell downloads. Do customers keep the right of withdrawal?<\/h3><\/dt>\n<dd><p>Only until they agree to immediate supply. Turn on \"Digital content\" in the EU Withdrawal tab and checkout asks for that consent whenever the cart has downloadable products. The time of consent is saved on the order, shown on the order screen and confirmed in the order emails, and those downloads can no longer be withdrawn. In block checkout this uses WooCommerce's conditional checkout fields, so keep WooCommerce up to date.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20hpos%20and%20the%20block%20checkout%3F\"><h3>Does it work with HPOS and the block checkout?<\/h3><\/dt>\n<dd><p>Yes, with both, and with classic checkout and the legacy order storage.<\/p><\/dd>\n<dt id=\"i%20used%20the%20pro%20version%20before.%20will%20my%20data%20carry%20over%3F\"><h3>I used the Pro version before. Will my data carry over?<\/h3><\/dt>\n<dd><p>Yes. The free plugin uses the same tables and settings. Requests, messages, photos and withdrawals stay as they are, and Pro features come back when you activate Pro again.<\/p><\/dd>\n<dt id=\"where%20do%20i%20get%20support%3F\"><h3>Where do I get support?<\/h3><\/dt>\n<dd><p>Free version questions go to the support forum here on WordPress.org. The developers who build the plugin answer there. Pro license holders get direct support from DevDiggers through a ticket.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0 - 2026-10-31<\/h4>\n\n<ul>\n<li>Initial free release.<\/li>\n<li>Returns and cancellations from My Account and from a guest returns portal (page, shortcode and block), with partial returns and a quantity per item.<\/li>\n<li>Return reasons you manage, condition per item, customer note, and photo and video uploads stored in a private folder.<\/li>\n<li>Return window from delivery or purchase, final-sale products and categories, and \"days left to return\" on every eligible order.<\/li>\n<li>Request page for the customer with progress, messages with attachments, the return label download and a tracking number field.<\/li>\n<li>Request screen for the shop team: next step card, approve or reject, upload a label, mark received with restock, refund through WooCommerce, internal notes and history.<\/li>\n<li>EU withdrawal function: \"Withdraw from contract here\" link, two-step statement with \"Confirm withdrawal\", acknowledgement email, model withdrawal form, Art. 16 exemptions and a withdrawal log with CSV export.<\/li>\n<li>Checkout consent for digital content (Art. 16(m)) in classic and block checkout, with the consent confirmed in the order emails.<\/li>\n<li>Dashboard, Requests list with filters and search, editable built-in and custom statuses, Returns box on the order screen and a setup wizard.<\/li>\n<li>Import of requests from ten other returns, cancellation and withdrawal plugins.<\/li>\n<li>WooCommerce emails, GDPR export and erase, HPOS, classic and block checkout, translation ready with WPML and Polylang support for your own texts.<\/li>\n<\/ul>","raw_excerpt":"Returns portal and RMA for WooCommerce with the EU withdrawal button. Guest and partial returns, photos, refund and cancel order requests.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/399214","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=399214"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/devdiggers"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=399214"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=399214"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=399214"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=399214"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=399214"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=399214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}