Changeset 3787432
- Timestamp:
- 11/06/2026 08:11:47 AM (24 hours ago)
- Location:
- cartdini
- Files:
-
- 75 added
- 8 edited
-
tags/1.8.8 (added)
-
tags/1.8.8/LICENSE.txt (added)
-
tags/1.8.8/administration-notes.txt (added)
-
tags/1.8.8/assets (added)
-
tags/1.8.8/assets/SOURCE.md (added)
-
tags/1.8.8/assets/admin.css (added)
-
tags/1.8.8/assets/blocks.css (added)
-
tags/1.8.8/assets/blocks.js (added)
-
tags/1.8.8/assets/checkout-review.css (added)
-
tags/1.8.8/assets/checkout-review.js (added)
-
tags/1.8.8/assets/checkout.css (added)
-
tags/1.8.8/assets/checkout.js (added)
-
tags/1.8.8/assets/collection (added)
-
tags/1.8.8/assets/collection.css (added)
-
tags/1.8.8/assets/collection.js (added)
-
tags/1.8.8/assets/collection/antivirus.svg (added)
-
tags/1.8.8/assets/collection/campaignbars.svg (added)
-
tags/1.8.8/assets/collection/catalogfaq.svg (added)
-
tags/1.8.8/assets/collection/clickclue.svg (added)
-
tags/1.8.8/assets/collection/customfields.svg (added)
-
tags/1.8.8/assets/collection/frictions.svg (added)
-
tags/1.8.8/assets/collection/killerconversions.svg (added)
-
tags/1.8.8/assets/collection/logged.svg (added)
-
tags/1.8.8/assets/collection/newsletterplatform.svg (added)
-
tags/1.8.8/assets/collection/orderfloor.svg (added)
-
tags/1.8.8/assets/collection/orderworth.svg (added)
-
tags/1.8.8/assets/collection/redirectnest.svg (added)
-
tags/1.8.8/assets/collection/stockcontrols.svg (added)
-
tags/1.8.8/assets/collection/tocgenius.svg (added)
-
tags/1.8.8/assets/collection/wakemycart.svg (added)
-
tags/1.8.8/assets/collection/wishlistgenius.svg (added)
-
tags/1.8.8/assets/core-blocks.js (added)
-
tags/1.8.8/assets/core-fields.js (added)
-
tags/1.8.8/assets/dashboard.js (added)
-
tags/1.8.8/assets/editor-journey.js (added)
-
tags/1.8.8/assets/editor-session.js (added)
-
tags/1.8.8/assets/fonts (added)
-
tags/1.8.8/assets/fonts/OFL.txt (added)
-
tags/1.8.8/assets/fonts/space-grotesk-0.ttf (added)
-
tags/1.8.8/assets/fonts/space-grotesk-1.ttf (added)
-
tags/1.8.8/assets/fonts/space-grotesk-2.ttf (added)
-
tags/1.8.8/assets/fonts/space-grotesk-3.ttf (added)
-
tags/1.8.8/assets/preview-switch.css (added)
-
tags/1.8.8/assets/pro-previews (added)
-
tags/1.8.8/assets/pro-previews/business.png (added)
-
tags/1.8.8/assets/pro-previews/choices.png (added)
-
tags/1.8.8/assets/pro-previews/conditions.png (added)
-
tags/1.8.8/assets/pro-previews/date.png (added)
-
tags/1.8.8/assets/pro-previews/fees.png (added)
-
tags/1.8.8/assets/pro-previews/product.png (added)
-
tags/1.8.8/assets/pro-previews/repeaters.png (added)
-
tags/1.8.8/assets/pro-previews/reuse.png (added)
-
tags/1.8.8/assets/pro-previews/uploads.png (added)
-
tags/1.8.8/assets/review-invitation.css (added)
-
tags/1.8.8/assets/review-invitation.js (added)
-
tags/1.8.8/assets/workspace.css (added)
-
tags/1.8.8/cartdini.php (added)
-
tags/1.8.8/changelog.txt (added)
-
tags/1.8.8/includes (added)
-
tags/1.8.8/includes/class-activation-navigation.php (added)
-
tags/1.8.8/includes/class-admin.php (added)
-
tags/1.8.8/includes/class-blocks.php (added)
-
tags/1.8.8/includes/class-checkout-review.php (added)
-
tags/1.8.8/includes/class-checkout.php (added)
-
tags/1.8.8/includes/class-config.php (added)
-
tags/1.8.8/includes/class-core-fields.php (added)
-
tags/1.8.8/includes/class-discovery-preferences.php (added)
-
tags/1.8.8/includes/class-display.php (added)
-
tags/1.8.8/includes/class-fields.php (added)
-
tags/1.8.8/includes/class-lock.php (added)
-
tags/1.8.8/includes/class-pro-setup.php (added)
-
tags/1.8.8/includes/class-review-invitation.php (added)
-
tags/1.8.8/languages (added)
-
tags/1.8.8/languages/cartdini.pot (added)
-
tags/1.8.8/readme.txt (added)
-
trunk/administration-notes.txt (modified) (2 diffs)
-
trunk/cartdini.php (modified) (2 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/includes/class-blocks.php (modified) (4 diffs)
-
trunk/includes/class-checkout.php (modified) (8 diffs)
-
trunk/includes/class-discovery-preferences.php (modified) (1 diff)
-
trunk/languages/cartdini.pot (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
cartdini/trunk/administration-notes.txt
r3785872 r3787432 13 13 == Installation == 14 14 15 Current matched release: Free 1.8.7 and Pro 1.8.7. Pro 1.8.7 requires Free 1.8.4 or newer. Existing Pro 1.8.4 remains compatible while you update Free first.15 Current Free release: 1.8.8, compatible with the existing Pro 1.8.7 add-on. This corrective Free release does not require a new Pro ZIP. Pro 1.8.7 requires Free 1.8.4 or newer. 16 16 17 17 1. Install and activate WooCommerce 9.9 or newer. … … 21 21 5. Add a test product to the cart, open checkout and complete a test order. Check answers in the order and supported emails before production. 22 22 23 To upgrade an existing installation, back up the site, then upload this ZIP and choose Replace current with uploaded. Saved fields, settings and order answers are retained. If you use Pro, update Free first, then update Cartdini Pro to 1.8.7. Older incompatible add-ons pause safely until updated; their saved definitions remain retained during the update. Test your saved configurations and complete checkout flows on staging before updating the live store.23 To upgrade an existing installation, back up the site, then upload this ZIP and choose Replace current with uploaded. Saved fields, settings and historical order answers are retained. If you already use Pro 1.8.7, leave it installed and update Free to 1.8.8. Older incompatible add-ons pause safely until updated; their saved definitions remain retained during the update. Test your saved configurations and complete checkout flows on staging before updating the live store. 24 24 25 Free 1.8.0 and newer require Pro extension API 6. When upgrading an older pair, complete both plugin replacements together during a maintenance window: older Pro versions pause until updated so they cannot silently ignore new date restrictions. Pro license and update access remain available between replacements. An existing Pro 1.8.2 installation can remain in place when updating Free to 1.8.7. 25 Free 1.8.0 and newer require Pro extension API 6. When upgrading an older pair, complete both plugin replacements together during a maintenance window: older Pro versions pause until updated so they cannot silently ignore new date restrictions. Pro license and update access remain available between replacements. Free 1.8.8 retains this extension API and the Pro 1.8.7 requirements. 26 27 CHECKOUT DATA INTEGRITY (1.8.8) 28 Virtual Checkout Blocks orders using custom address inputs preserve existing saved shipping answers instead of copying billing into shipping. Physical same-address and billing-only shipping retain their normal copies. Nonapplicable shipping is excluded from the new order and its display/email snapshot. 29 30 When a shopper submits a reusable draft, pending or failed checkout order, removed Cartdini question metadata is reconciled against the current supported questions, including native fields. Historical completed orders and private attachment records are not purged by this checkout reconciliation. Hidden customer-answer cleanup checks both the authenticated shopper and the order identity. 31 32 Administrator preference erasure processes a bounded batch and checks remaining keys. Busy or failed deletions return an explicit error: retry the WordPress personal-data erasure after the other writer finishes or storage recovers. A partial deletion is not reported as complete; do not repeatedly auto-retry a persistent storage failure. 26 33 27 34 Configurations that use the expanded 1.3.0 format are saved separately. Cartdini preserves the previous compatible configuration and a recovery copy. An older plugin pair uses that older configuration; it cannot use the new controls. If an older version changes settings, the editor asks you to review both copies before choosing one. Back up the whole site before a downgrade, including orders and customer data. -
cartdini/trunk/cartdini.php
r3785872 r3787432 3 3 * Plugin Name: Cartdini – Checkout Field Editor for WooCommerce 4 4 * Description: Edit WooCommerce checkout fields in Classic and Checkout Blocks, with an admin preview. 5 * Version: 1.8. 75 * Version: 1.8.8 6 6 * Author: pluginsshop 7 7 * Author URI: https://plugins.shop/ … … 18 18 */ 19 19 defined( 'ABSPATH' ) || exit; 20 define( 'CARTDINI_VERSION', '1.8. 7' );20 define( 'CARTDINI_VERSION', '1.8.8' ); 21 21 define( 'CARTDINI_FILE', __FILE__ ); 22 22 require_once __DIR__ . '/includes/class-activation-navigation.php'; -
cartdini/trunk/changelog.txt
r3775804 r3787432 1 Cartdini Free historical changelog through 1.8.4 1 Cartdini Free full changelog through 1.8.8 2 3 = 1.8.8 = 4 * Preserve saved shipping answers on virtual Checkout Blocks orders when address questions use the custom field bridge; retain physical same-address copying. 5 * Exclude nonapplicable shipping answers from bridge validation, current-order storage and order/email snapshots. 6 * Restrict hidden-answer customer cleanup to the current shopper and avoid saving unrelated account properties. 7 * Remove retired Cartdini question metadata from the current reusable checkout order without deleting current native fields, historical orders or private attachment records. 8 * Return a retryable privacy-erasure error when preferences are busy or cannot be deleted, instead of silently completing or paging indefinitely. 9 * Keep existing Cartdini Pro 1.8.7 compatible; no Pro update is required. 10 11 = 1.8.7 = 12 * Add Plugins.shop attribution and an optional More Plugins collection with local artwork, clear availability and safe external links. 13 * Add an accessible Pro previews switch using the existing per-administrator/store preference; Off also suppresses optional suggestions. 14 * Keep Explore Pro available in Free and actual Pro workflows available regardless of the Free preview preference. 15 * Collapse mobile navigation behind Menu, preserve unfinished edits across collection navigation and keep the editor as the default destination. 16 * Keep custom order inputs before payment or submission when the native Order information block is missing; preserve explicitly positioned blocks. 17 * Clarify Checkout Blocks section placement and the limits of the structural preview. 18 * Match Pro 1.8.7 while preserving answer storage and licensing requirements. 19 20 = 1.8.6 = 21 * Preserve saved shipping answers when a Classic order does not need shipping, while retaining normal billing-to-shipping copying for physical orders. 22 * Recover focused editor inputs, identify invalid Classic settings and refresh question labels and shared-field controls. 23 * Let shoppers clear optional radio answers in Classic Checkout and Checkout Blocks. 24 * Clarify first-checkout testing, draft-only deletion and failed-save recovery; improve Tools layout. 25 * Use pluginsshop author details and match Cartdini Pro 1.8.6. 26 * Add an optional, dismissible WordPress.org review invitation after established checkout use, shared with Pro. 27 * Keep review preferences local, scoped per administrator/store, and covered by personal-data export and erasure. 28 * Preserve checkout fields and saved drafts when responding to the invitation. 29 30 = 1.8.5 = 31 * Clarify Free workflows, checkout compatibility, Pro boundaries, installation and privacy in the readme. 32 * Bundle detailed administrator notes and the full historical changelog. 33 * Open the editor after successful single manual Free activation; preserve bulk, network and background flows. 34 * Match the website logo and Pro 1.8.5. Checkout behavior and requirements are unchanged. 2 35 3 36 = 1.8.4 = -
cartdini/trunk/includes/class-blocks.php
r3785872 r3787432 174 174 foreach (Config::fields() as $field) { 175 175 foreach (Checkout::instances($field) as $instance) { 176 if ($instance['scope']==='shipping' && !Checkout::shipping_applies()) { continue; } 176 177 if (self::uses_bridge($field)) { $values[$instance['key']]=$custom[$instance['key']] ?? ''; } 177 178 else { $group=$instance['scope']==='other' ? 'additional_fields' : $instance['scope'].'_address'; $values[$instance['key']]=$json[$group]['cartdini/'.$field['key']] ?? ''; } 178 179 } 179 180 } 180 $copy=($extra['use_shipping_as_billing'] ?? false) === true && function_exists('WC') && WC()->cart&& WC()->cart->needs_shipping_address();181 $ no_shipping=function_exists('WC') && WC()->cart&& !WC()->cart->needs_shipping_address();182 if ($ no_shipping) { foreach (Config::fields() as $field) { if ($field['location']!=='address') { continue; } $instances=Checkout::instances($field); $values[$instances[1]['key']]=$values[$instances[0]['key']] ?? ''; } }181 $copy=($extra['use_shipping_as_billing'] ?? false) === true && Checkout::shipping_applies() && WC()->cart->needs_shipping_address(); 182 $billing_only=Checkout::shipping_applies() && !WC()->cart->needs_shipping_address(); 183 if ($billing_only) { foreach (Config::fields() as $field) { if ($field['location']!=='address') { continue; } $instances=Checkout::instances($field); $values[$instances[1]['key']]=$values[$instances[0]['key']] ?? ''; } } 183 184 if ($copy) { foreach (Config::fields() as $field) { if ($field['location']!=='address') { continue; } $instances=Checkout::instances($field); $values[$instances[0]['key']]=$values[$instances[1]['key']] ?? ''; } } 184 185 return $values; 185 186 } 186 187 public static function save_order($order,$request): void { 187 if ($request->get_method() !== 'POST' || !self::fields()) { return; } 188 if ($request->get_method() !== 'POST') { return; } 189 if (!self::fields()) { Checkout::reconcile_blocks_order($order); return; } 188 190 $values=self::request_values($request); $plan=[]; 189 191 // Validate every answer before changing any metadata. The authenticated … … 191 193 foreach (self::fields() as $field) { 192 194 foreach (Checkout::instances($field) as $instance) { 195 if ($instance['scope']==='shipping' && !Checkout::shipping_applies()) { continue; } 193 196 $visible=Checkout::visible($field,$instance,$values,$order); 194 197 $test=$field; $test['required']=Checkout::required($field,$instance,$values,$order); … … 206 209 if (is_wp_error($plan)) { $detail=$plan->get_error_data();$status=is_array($detail)&&is_int($detail['status']??null)&&$detail['status']>=400&&$detail['status']<=599?$detail['status']:400;throw new \Automattic\WooCommerce\StoreApi\Exceptions\RouteException('cartdini_invalid',esc_html($plan->get_error_message()),(int)$status); } 207 210 if (!is_array($plan)) { throw new \Automattic\WooCommerce\StoreApi\Exceptions\RouteException('cartdini_invalid',esc_html__('Checkout fields could not be prepared. Please review your answers and retry.','cartdini'),400); } 211 Checkout::reconcile_blocks_order($order); 208 212 foreach ($plan as $item) { 209 213 if ($item['value'] === null) { $order->delete_meta_data($item['key']); } … … 219 223 if ($field['location']==='order') { continue; } 220 224 foreach (Checkout::instances($field) as $instance) { 225 if ($instance['scope']==='shipping' && !Checkout::shipping_applies()) { continue; } 221 226 $key='_wc_'.$instance['scope'].'/cartdini/'.$field['key']; $value=$order->get_meta($key,true); 222 227 foreach ([$session,$persistent] as $customer) { -
cartdini/trunk/includes/class-checkout.php
r3776410 r3787432 101 101 } 102 102 /** Shipping can apply even when the store only ships to the billing address. */ 103 p rivate static function classic_shipping_applies(): bool {103 public static function shipping_applies(): bool { 104 104 return function_exists( 'WC' ) && WC()->cart && WC()->cart->needs_shipping(); 105 105 } 106 106 private static function skip_shipping( array $i, array $values ): bool { 107 return $i['scope'] === 'shipping' && ( ! self:: classic_shipping_applies() || ! WC()->cart->needs_shipping_address() || empty( $values['ship_to_different_address'] ) );107 return $i['scope'] === 'shipping' && ( ! self::shipping_applies() || ! WC()->cart->needs_shipping_address() || empty( $values['ship_to_different_address'] ) ); 108 108 } 109 109 /** Render malformed Free scalar input without changing the raw submission. */ … … 158 158 // An order without shipping must not replace or erase an 159 159 // unrelated saved shipping answer on a returning account. 160 if ($instance['scope']==='shipping' && !self:: classic_shipping_applies()) { continue; }160 if ($instance['scope']==='shipping' && !self::shipping_applies()) { continue; } 161 161 $key='_wc_'.$instance['scope'].'/cartdini/'.$field['key']; $value=$order->get_meta($key,true); 162 162 foreach ([$session,$account] as $customer) { … … 194 194 foreach ( Config::fields() as $f ) { 195 195 foreach ( self::instances( $f ) as $i ) { 196 if ( $i['scope'] === 'shipping' && ! self:: classic_shipping_applies() ) { continue; }196 if ( $i['scope'] === 'shipping' && ! self::shipping_applies() ) { continue; } 197 197 $read_i = $i; 198 198 if ( self::skip_shipping( $i, $values ) ) { $read_i = self::instances($f)[0]; } … … 243 243 if ( ! self::blocks_supported( $field ) ) { continue; } 244 244 foreach ( self::instances( $field ) as $instance ) { 245 if ( $instance['scope'] === 'shipping' && ! self::shipping_applies() ) { continue; } 245 246 if ( ! self::visible( $field, $instance, $values, $order ) ) { continue; } 246 247 $value = Config::clean_value( $values[$instance['key']] ?? '', $field ); … … 255 256 self::check_answer_size( $entries, true ); 256 257 } 258 public static function reconcile_blocks_order( $order ): void { 259 if ( ! $order instanceof \WC_Order || ! $order->has_status( ['checkout-draft','pending','failed'] ) || $order->is_paid() || $order->get_date_paid() ) { return; } 260 $allowed = []; 261 foreach ( Config::fields() as $field ) { 262 if ( ! self::blocks_supported( $field ) ) { continue; } 263 foreach ( self::instances( $field ) as $instance ) { 264 if ( $instance['scope'] === 'shipping' && ! self::shipping_applies() ) { continue; } 265 $allowed['_wc_'.$instance['scope'].'/cartdini/'.$field['key']] = true; 266 } 267 } 268 foreach ( $order->get_meta_data() as $metadata ) { 269 $stored = $metadata->get_data(); 270 if ( self::is_field_meta( $stored['key'] ) && ! isset( $allowed[$stored['key']] ) ) { $order->delete_meta_data( $stored['key'] ); } 271 } 272 } 257 273 public static function snapshot_blocks( $order ): void { 258 274 $service=\Automattic\WooCommerce\Blocks\Package::container()->get(\Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields::class); … … 261 277 if(!self::blocks_supported($f)){continue;} 262 278 foreach(self::instances($f) as $i){ 279 if ( $i['scope'] === 'shipping' && ! self::shipping_applies() ) { $order->delete_meta_data('_wc_'.$i['scope'].'/cartdini/'.$f['key']); continue; } 263 280 // Recheck persisted source answers before creating the display 264 281 // order/email snapshot, even if a native service kept a hidden value. … … 278 295 } 279 296 public static function clear_hidden_blocks( $object, $request ): void { 297 if ( $object instanceof \WC_Customer && ! self::checkout_customer_matches( $object ) ) { return; } 280 298 $configured=Config::fields();$by_key=array_column($configured,null,'key'); 281 299 // WC()->customer uses the session data store. Removing its metadata does … … 302 320 // Only the authenticated checkout shopper may have account data removed. 303 321 // An order's customer ID is not proof of the current shopper's identity. 304 if($id<1|| $id!==(int)get_current_user_id()){return null;}322 if($id<1||!self::checkout_customer_matches($customer,$object)){return null;} 305 323 return new \WC_Customer($id); 324 } 325 private static function checkout_customer_matches( $customer, $order = null ): bool { 326 if ( ! $customer instanceof \WC_Customer || (int)$customer->get_id() !== (int)get_current_user_id() ) { return false; } 327 return ! $order instanceof \WC_Order || (int)$order->get_customer_id() === (int)$customer->get_id(); 306 328 } 307 329 /** Shared cleanup: only the authenticated shopper is passed as $persistent. */ 308 330 public static function clear_block_value( $object, array $field, array $instance, $persistent = null ): void { 331 if ( $object instanceof \WC_Customer && ! self::checkout_customer_matches( $object ) ) { return; } 309 332 $key='_wc_'.$instance['scope'].'/cartdini/'.$field['key']; 310 $object->delete_meta_data($key); 311 if($persistent){$persistent->delete_meta_data($key);} 333 if ( $object instanceof \WC_Order ) { $object->delete_meta_data($key); } 334 if ( $instance['scope'] === 'shipping' && ! self::shipping_applies() ) { return; } 335 if ( $object instanceof \WC_Customer && self::checkout_customer_matches($object) ) { $object->delete_meta_data($key); } 336 if($persistent && self::checkout_customer_matches($persistent,$object)){$persistent->delete_meta_data($key);} 312 337 // Some WooCommerce releases persist hidden order fields before this action. 313 if($object instanceof \WC_Order && WC()->customer){WC()->customer->delete_meta_data($key);WC()->customer->save();} 338 $session=function_exists('WC') ? WC()->customer : null; 339 if($object instanceof \WC_Order && self::checkout_customer_matches($session,$object)){ 340 $session->delete_meta_data($key); 341 if(is_a($session->get_data_store()->get_current_class_name(),'WC_Customer_Data_Store_Session',true)){$session->save();} 342 else{$session->save_meta_data();} 343 } 314 344 } 315 345 public static function register_blocks(): void { -
cartdini/trunk/includes/class-discovery-preferences.php
r3775804 r3787432 371 371 } finally { Lock::release( $lock, $token ); } 372 372 } 373 $result['done'] = count( $keys ) <= 25 || ! $result['items_removed']; 373 $remaining = self::owned_keys( $id ); 374 if ( is_wp_error( $remaining ) ) { return $remaining; } 375 $result['done'] = ! $remaining; 376 if ( $remaining && ( $result['items_retained'] || ! array_diff( $keys, $remaining ) ) ) { 377 $result['items_retained'] = true; 378 return new \WP_Error( 'cartdini_preferences_erasure_incomplete', __( 'Cartdini preferences could not be erased. Retry erasure.', 'cartdini' ), $result ); 379 } 374 380 return $result; 375 381 } -
cartdini/trunk/languages/cartdini.pot
r3785872 r3787432 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Cartdini – Checkout Field Editor for WooCommerce 1.8. 7\n"5 "Project-Id-Version: Cartdini – Checkout Field Editor for WooCommerce 1.8.8\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/cartdini\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" -
cartdini/trunk/readme.txt
r3785872 r3787432 1 1 === Cartdini – Checkout Field Editor for WooCommerce === 2 2 Contributors: pluginsshop 3 Tags: woocommerce, checkout , checkout fields, checkout editor, checkout manager3 Tags: woocommerce, checkout fields, checkout field editor, checkout manager, checkout blocks 4 4 Requires at least: 6.7 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.0 7 Stable tag: 1.8. 77 Stable tag: 1.8.8 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Add custom WooCommerce checkout fields for delivery instructions, gift notes and order details. SupportsClassic Checkout and Checkout Blocks.11 Customize WooCommerce checkout fields: add gift notes, delivery instructions and billing details. Works with Classic Checkout and Checkout Blocks. 12 12 13 13 == Description == 14 14 15 Cartdini is a WooCommerce checkout field editor for delivery instructions, gift notes, purchase references and other order details. Add questions without writing code andkeep customers' answers with the order.15 **Add custom WooCommerce checkout fields without code.** Collect gift messages, delivery instructions and purchase references; keep customers' answers with the order. 16 16 17 The Free plugin includes nine custom field types in both Classic Checkout and Checkout Blocks: text, select, checkbox, textarea, email, telephone, number, radio and URL. It works without a Cartdini account, license or external service.17 Nine Free field types work in Classic Checkout and Checkout Blocks. No Cartdini account, license or subscription. 18 18 19 = What you can do withFree =19 = Custom checkout fields included in Free = 20 20 21 * Add up to 100 custom fields to order information, contact details or both billing and shipping addresses. 22 * Write labels and help text, choose optional or required answers, and configure supported text limits, number ranges and steps. 23 * Reorder or duplicate questions and preview their structure before saving. 24 * Choose answer display in admin/customer orders and supported admin/customer emails. 25 * Edit supported existing checkout fields while keeping WooCommerce's essential address validation. 26 * Recover an unfinished local editor draft, review it and save explicitly. 27 * Use WooCommerce High-Performance Order Storage (HPOS) or legacy order storage. 21 * **Nine types:** text, textarea, dropdown select, checkbox, radio buttons, email, telephone, number and URL. 22 * **Up to 100 questions:** Order information, Contact or shared billing/shipping addresses. 23 * **Field controls:** labels, help, supported placeholders, optional/required answers and supported text/number limits. 24 * **Editor:** reorder, duplicate, disable and structurally preview questions; save explicitly. 25 * **Saved answers:** select display on supported admin/customer order pages and emails. 26 * **Storage:** High-Performance Order Storage (HPOS) and legacy orders. 28 27 29 Add an optional "Delivery instructions" textarea, save it, add a test product to your cart and check its answer on a test order. A gift note is Free; showing it only when another answer matches is Pro. 28 = Practical questions for your store = 30 29 31 [Setup guides](https://cartdini.com/docs) | [Classic and Blocks compatibility](https://cartdini.com/compatibility) | [Support](https://cartdini.com/support) 30 * Add a **gift message** textarea for the packing team. 31 * Collect **delivery instructions** or an additional contact number alongside an address. 32 * Collect a **purchase order number** as text; this does not create purchase orders or change payment methods. 33 * Offer a dropdown or radio question for an order preference, without adding a charge. 32 34 33 = Editing existing checkout fields = 35 Address questions share billing/shipping definitions. Virtual orders preserve saved shipping answers instead of replacing them with billing answers. 34 36 35 Classic supports label, placeholder and position changes for supported billing, shipping and order fields. Essential address/email visibility and validation remain native. Six optional-field controls allow visibility/requirement changes; reset individual overrides. 37 = Manage existing checkout fields = 36 38 37 Checkout Blocks supports shared Company, Phone and Address line 2 visibility/requirement settings, labels and order for ten shared address fields, and the default Place Order button text. Shared address changes can also affect Classic checkout; explicit Classic overrides take precedence. Native settings save separately, outside custom-field imports, templates and history. WooCommerce retains country-specific requirements, hidden fields and validation. Blocks contact email, address placeholders and section content remain native controls; payment extensions may supply their own button text.39 Checkout manager controls differ by checkout: 38 40 39 = When you need Pro = 41 * **Classic:** supported labels, placeholders and positions; six optional-field visibility/requirement controls and individual resets. 42 * **Blocks:** shared Company, Phone and Address line 2 visibility/requirements, supported address labels/order and default Place Order text. Shared settings can affect Classic; explicit Classic overrides win. Native settings save separately. 40 43 41 [Cartdini Pro](https://cartdini.com/free-vs-pro) is a separate paid add-on. It adds conditional questions, fixed paid extras for eligible order choices, private file uploads, date availability rules, time and multiple-choice inputs, repeatable groups, reusable custom-field setups and order-answer CSV tools. Check workflow requirements before purchase. Pro is optional.44 Essential address/email validation and country requirements stay with WooCommerce. Blocks contact email, address placeholders and sections remain native; gateways may override button text. Cartdini does not remove every required field. 42 45 43 Optional Pro previews show local examples and real control screenshots. The Pro previews switch hides or restores preview navigation and optional suggestions for your administrator account on this store. Explore Pro remains available when previews are off. Examples never publish fields, upload files or add charges. Tasks require an explicit remember/pricing action; previewing does not enable measurement. 46 [Setup guides](https://cartdini.com/docs) | [Compatibility and limitations](https://cartdini.com/compatibility) | [Support](https://cartdini.com/support) 44 47 45 The editor opens first. More Plugins is a separate, optional collection of tools from Plugins.shop, with bundled logos and descriptions. Opening the collection makes no external request and installs nothing. Product links open Plugins.shop in a new tab; check current availability there. On small screens, the Menu button expands navigation without pushing the editor down on every visit. 48 = Optional Cartdini Pro add-on = 49 50 Separate paid [Cartdini Pro](https://cartdini.com/free-vs-pro) adds conditional fields, fixed paid extras for eligible choices, private uploads, date availability rules, time/multiple-choice inputs, repeatable groups, reusable setups and order-answer CSV tools. Uploads/groups are order-only. 51 52 Initial activation unlocks Pro editing/tools. Disconnecting locks tools but saved checkout behavior continues; deactivation pauses Pro-only behavior. Pro is optional, not auto-installed. Previews never publish fields, upload files or charge shoppers. 53 54 = Related WooCommerce plugins from Plugins.shop = 55 56 Optional tools from our team for your WooCommerce store: 57 58 * [Frictions – WooCommerce checkout session replay](https://wordpress.org/plugins/frictions/) — investigate eligible checkout visits and observed errors with protected structural replay. 59 * [OrderFloor – WooCommerce minimum order and quantity limits](https://wordpress.org/plugins/orderfloor/) — set minimum order amounts, quantity limits and pack multiples. 60 * [OrderWorth – WooCommerce cost of goods and profit reports](https://wordpress.org/plugins/orderworth/) — review product costs, expenses and estimated profit for WooCommerce orders. 61 62 Neither is required or auto-installed. Check their requirements; links do not imply automatic integration or guaranteed compatibility. 46 63 47 64 == Installation == 48 65 49 Requires WordPress 6.7+, PHP 8.0+ and WooCommerce 9.9+. JavaScript is required for the editor. Current matched release: Free 1.8.7 and Pro 1.8.7.66 Requires WordPress 6.7+, PHP 8.0+, WooCommerce 9.9+ and JavaScript for the editor. 50 67 51 1. Install and activate WooCommerce. 52 2. In Plugins > Add New, search for Cartdini by pluginsshop and choose Install Now. Alternatively, use Upload Plugin with the Free ZIP. 53 3. Use WordPress's Activate Plugin control. A successful single manual activation opens the Cartdini editor. 54 4. Add your questions, review them and choose Save. For bulk/network activation, open WooCommerce > Cartdini yourself. 55 5. Add a test product to your cart, then open checkout. Complete test checkouts, including missing or invalid answers, and check order/email display before using the configuration on a live store. 68 1. Activate WooCommerce, then install Cartdini through Plugins > Add New or upload the Free ZIP. 69 2. Activate Cartdini. Ordinary single activation opens the editor; otherwise open WooCommerce > Cartdini. 70 3. Add a question, review its type/location and choose Save questions & fields. 71 4. Test checkout, missing/invalid answers and saved order/email answers before going live. 56 72 57 Back up your site before updating. Upload the new ZIP and choose Replace current with uploaded; do not uninstall first. With Pro, update Free first and Pro second, keeping both active. Pro 1.8.7 requires Free 1.8.4 or newer; the recommended matched pair is 1.8.7. Settings and saved order answers are retained. Update pairs older than 1.8.0 together: incompatible Pro extensions pause safely. Older formats/recovery: administration-notes.txt. 73 Fresh installs enable no sample questions. Save applies changes; reactivation resumes saved settings. 74 75 Back up; replace without uninstalling. Keep Free active and update it before Pro. Free 1.8.8 supports Pro 1.8.7 (minimum Free 1.8.4). Settings/history are retained. Update pre-1.8.0 pairs together; incompatible Pro features pause. Recovery details: administration-notes.txt. 58 76 59 77 == Frequently Asked Questions == 60 78 61 = Does Free work without an account or license? =62 Yes . Free field editing and checkout features need no Cartdini account, license key or subscription. Free makes no requests to the Cartdini license service.79 = Can I add a gift note or delivery instructions for free? = 80 Yes: add a textarea, label it and choose its location. Conditional display requires Pro. Gift notes are separate from WooCommerce's native "Add a note to your order" option; label them distinctly. 63 81 64 = Does activating Cartdini change my checkout immediately? =65 New installations enable no sample fields. Save to apply a configuration. Reactivation resumes saved settings; previews and recovered drafts do not publish them.82 = Does it work with the block checkout? = 83 Yes: all nine Free types support both. Existing-field controls differ as described above. Test your theme/gateways; not every third-party checkout builder is supported. 66 84 67 = Does it work with WooCommerce Checkout Blocks and HPOS? =68 Yes. All nine Free custom field types support Classic and Checkout Blocks, and order data uses WooCommerce's CRUD APIs for HPOS and legacy orders. Existing-field controls differ between checkouts as described above. Test your theme and payment extensions on the actual checkout. The compatibility guide lists recorded environments and limits.85 = Why does my custom field appear after payment? = 86 Order questions follow the Order information block in your Checkout page. Move that block before Payment in the page editor if preferred. Question-reorder arrows do not move sections. The structural preview is not your exact storefront layout. 69 87 70 = Where can I see customers' answers? =71 Answers stay with orders and, for supported contact/address fields, customer accounts. Choose their display on supported order pages/emails; hiding answers does not delete them. Order-answer CSV export and optional Orders-list answer columns belong toPro.88 = Where are checkout answers saved? = 89 With orders and, for supported contact/address fields, customer accounts. Order-only notes are not account-prefilled. Display settings control supported order/email output; hiding answers does not delete them. CSV export and optional Orders-list answer columns require Pro. 72 90 73 = Can I make a question conditional, charge for a choice or accept a file? =74 Those are Pro features. Free collects ordinary notes. Pro adds conditions, fixed positive fees for eligible order choices and private JPG/PNG/PDF files. Uploads and repeatable groups use the order location only. Pro's initial license activation unlocks editing and tools; disconnecting locks those tools while saved checkout behavior continues. Deactivating Pro pauses Pro-only behavior. Review the separate add-on's licensing and compatibility details.91 = What if I leave before saving? = 92 Drafts last up to 24 hours in the same browser tab for your administrator/store. Closing it or clearing storage may remove them. Recovery requires review and Save. Follow retry/reload guidance after conflicts; custom questions and native Blocks settings save separately. 75 93 76 = What happens to my unfinished work? = 77 A draft stays in this browser tab for up to 24 hours, scoped to this administrator/store. Closing the tab or clearing storage may remove it. Recovery checks newer settings and loads a draft for review; Save is still required. Custom fields and native Blocks settings have separate save actions. Follow retry/reload guidance rather than deleting recovery records. 78 79 = Does deleting the plugin remove settings or order answers? = 80 No. Deactivation and deletion retain configuration, recovery data and saved answers. Removing a field does not erase historical answers. While Free and WooCommerce are active, WordPress personal-data tools export saved account/order answers; erasure removes account answers and follows WooCommerce's order-retention settings. If an order has private Pro uploads, keep or reactivate a compatible Pro for file erasure; this needs no license. Failed or unreadable storage is reported for retry, and order identity/answers are retained until private-file erasure can be checked safely. Removing both plugins leaves retained data outside their privacy tools. 94 = What happens if I remove a field or delete Cartdini? = 95 Removing a field keeps historical answers. Deactivation/deletion retains settings, recovery data and saved answers. With Free and WooCommerce active, WordPress privacy tools export account/order answers; erasure removes account answers and follows WooCommerce order-retention settings. Keep compatible Pro active to erase private uploads; no license is needed for erasure. Failed/unreadable storage remains retryable, preserving order identity/answers until private-file erasure is checked safely. Removing both plugins leaves retained data outside their privacy tools. 81 96 82 97 == Privacy and local preferences == 83 98 84 Free stores answers in your WordPress/WooCommerce database. It sends no answers or administrator preferences to Cartdini. Request only necessary information and explain its purpose, recipients and retention in your store's privacy policy. Suggested wording is available in WordPressSettings > Privacy.99 Answers stay in your WordPress/WooCommerce database. Free sends no answers or administrator preferences to Cartdini. Request necessary information only and explain purpose, recipients and retention in your privacy policy. Suggested wording: Settings > Privacy. 85 100 86 Browser drafts store field settings, not shopper answers, preview answers, files or license credentials. Full-screen and individual contextual suggestion dismissals use browser storage; WordPress navigation is visible by default. Optional remembered Pro tasks use site-scoped administrator metadata and expire after seven days. The Pro previews switch also uses administrator/store-scoped WordPress metadata, persists across browsers and updates, and controls optional suggestions as well as preview navigation. It never disables actual Pro workflows. 101 * **Browser storage:** drafts hold field settings, not shopper/preview answers, files or credentials. Full-screen/contextual dismissals use browser storage; WordPress navigation is visible by default. 102 * **Pro previews:** On/Off persists per administrator/store across browsers/updates. It controls optional previews/suggestions, not real Pro workflows; Explore Pro stays available. Remembered tasks require an explicit remember/pricing action, use local administrator metadata and expire after seven days. 103 * **Local action counts:** off by default. When enabled, preview opens, pricing clicks and matching workflow saves are counted for 90 days, not purchases/conversion rates. No shopper answers/license keys; disabling clears counts. Expired tasks/counts use WordPress cron and support privacy export/erasure. Previewing is not consent to measurement. 104 * **Review invitation:** only in Cartdini settings after 30 days and qualifying checkout use on three dates; disabled on development/local/staging sites. Eligibility stores a first-use time and at most three dates, no order IDs/customer details/answers. Local per-administrator/store review/dismissal preferences persist across updates and support export/erasure. Remind in 30 days or stop permanently; no payment verification, review-submission tracking or external analytics. 87 105 88 Optional local action counts are off by default. If enabled, they count preview opens, pricing-link clicks and matching workflow saves for 90 days; they do not measure purchases or conversion rates. Counts contain no shopper answers or license keys, stay on the store and are cleared when disabled. Expired tasks and counts are scheduled for removal through WordPress cron while active and are included in personal-data export/erasure. Opening an example is not consent to measurement. Free makes no external service requests; following documentation, support or pricing links opens the selected website. Pro license connections are separately disclosed and require an explicit administrator action. 89 90 A quiet review invitation appears only in Cartdini settings after at least 30 days from the first recorded qualifying checkout and use on three distinct days. Eligibility keeps only a local first-use time and up to three checkout creation dates, without order identifiers, customer details or answer copies. It is not payment verification or external analytics. The invitation is disabled in WordPress development, local and staging environments. Review-link and dismissal preferences are scoped to the administrator and website, persist across updates, and are included in personal-data export and erasure. Reminders can be delayed for 30 days or stopped permanently. Opening the WordPress.org review link does not tell Cartdini whether a review was submitted. 106 The optional More Plugins screen bundles artwork/descriptions; opening it sends no request and installs nothing. Product links open Plugins.shop. Free makes no external service requests; following documentation/support/pricing links opens that website. Pro license connections are separately disclosed and require explicit administrator action. 91 107 92 108 == Source and licenses == 93 109 94 All executable PHP, JavaScript and CSS is included as readable source; no compilation or external download is needed. See assets/SOURCE.md for dependencies and translation instructions. Locally bundled fonts make no external request and include their SIL Open Font License in assets/fonts/OFL.txt. Cartdini is licensed under GPLv2 or later; seeLICENSE.txt.110 Readable PHP/JavaScript/CSS need no build. Dependencies/translations: assets/SOURCE.md. Local fonts make no requests; SIL license: assets/fonts/OFL.txt. Plugin license: GPLv2 or later, LICENSE.txt. 95 111 96 112 == Screenshots == … … 103 119 == Changelog == 104 120 105 = 1.8.7 = 106 * Add Plugins.shop attribution and an optional More Plugins collection with local artwork, clear availability and safe external links. 107 * Add an accessible Pro previews switch using the existing per-administrator/store preference; Off also suppresses optional suggestions. 108 * Keep Explore Pro available in Free and actual Pro workflows available regardless of the Free preview preference. 109 * Collapse mobile navigation behind Menu, preserve unfinished edits across collection navigation and keep the editor as the default destination. 110 * Keep custom order inputs before payment or submission when the native Order information block is missing; preserve explicitly positioned blocks. 111 * Clarify Checkout Blocks section placement and the limits of the structural preview. 112 * Match Pro 1.8.7 while preserving answer storage and licensing requirements. 121 = 1.8.8 = 122 * Preserve saved shipping answers on virtual Checkout Blocks orders; retain normal physical-order copying. 123 * Exclude nonapplicable shipping answers from order details and emails. 124 * Harden customer identity checks and remove obsolete answers from reused checkout drafts, preserving history. 125 * Make busy or failed preference erasure retryable. 126 * Remain compatible with Pro 1.8.7; no Pro update required. 113 127 114 = 1.8.6 = 115 * Preserve saved shipping answers when a Classic order does not need shipping, while retaining normal billing-to-shipping copying for physical orders. 116 * Recover focused editor inputs, identify invalid Classic settings and refresh question labels and shared-field controls. 117 * Let shoppers clear optional radio answers in Classic Checkout and Checkout Blocks. 118 * Clarify first-checkout testing, draft-only deletion and failed-save recovery; improve Tools layout. 119 * Use pluginsshop author details and match Cartdini Pro 1.8.6. 120 * Add an optional, dismissible WordPress.org review invitation after established checkout use, shared with Pro. 121 * Keep review preferences local, scoped per administrator/store, and covered by personal-data export and erasure. 122 * Preserve checkout fields and saved drafts when responding to the invitation. 123 124 = 1.8.5 = 125 * Clarify Free workflows, checkout compatibility, Pro boundaries, installation and privacy in the readme. 126 * Bundle detailed administrator notes and the full historical changelog. 127 * Open the editor after successful single manual Free activation; preserve bulk, network and background flows. 128 * Match the website logo and Pro 1.8.5. Checkout behavior and requirements are unchanged. 129 130 = 1.8.4 = 131 * Preserve Pro date availability restrictions when saving and resuming a local editor draft. Unfinished values remain available for review; normal validation and an explicit Save are still required. 132 * Use Cartdini Pro 1.8.4 for the matched release. 133 134 Earlier releases: changelog.txt. 128 Full release notes and earlier versions: changelog.txt.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)