Persist sortable checkout address field order in admin UI - #9822
Open
jakejackson1 wants to merge 1 commit into
Open
Persist sortable checkout address field order in admin UI#9822jakejackson1 wants to merge 1 commit into
jakejackson1 wants to merge 1 commit into
Conversation
## Summary
The "Checkout Address Fields" multicheck on `Downloads → Settings → Payments → Checkout` is supposed to remember the order you drag the fields into. It doesn't — the saved order is correctly written to `edd_settings[checkout_address_fields_order]` and honored by the front-end checkout, but the admin settings screen ignores it and re-renders the list in a hardcoded order. Re-saving the settings page without re-dragging then wipes the stored order entirely. Two compounding bugs are responsible; this PR fixes both.
## Bug 1 — `edd_multicheck_callback()` always reads an empty order
`includes/admin/settings/register-settings.php:709`
```php
'order' => edd_get_option( 'edd_settings[' . edd_sanitize_key( $args['id'] ) . '_order', array() ),
```
The literal key passed to `edd_get_option()` is `edd_settings[checkout_address_fields_order` — the closing `]` is on the wrong side of the function call, and the `edd_settings[…]` wrapper shouldn't be there in the first place because `edd_get_option()` already reads from the `edd_settings` array (see lines 838 and 903 in the same file for the correct pattern, e.g. `edd_get_option( 'payment_icons_order', '' )`).
As a result this lookup always returns the `array()` default, so the hidden `<input class="edd-order" value="">` rendered by `EDD\HTML\Multicheck` is **always blank on page load**. The jQuery UI `sortable` `stop` handler updates the hidden input on drag, so a drag-then-save round-trip works once — but the next page load wipes the value, and any non-drag save (e.g. toggling an unrelated checkbox) POSTs an empty string and erases the saved order.
**Fix:** strip the wrapper and the stray bracket so the key is just `<id>_order`.
## Bug 2 — `Gateways::get_address_options()` clobbers the saved order
`src/Admin/Settings/Tabs/Gateways.php:591-601`
```php
$options = \EDD\Forms\Checkout\Registry::get_fields();
$order = edd_get_option( 'checkout_address_fields_order', array() );
if ( ! empty( $order ) ) {
$order = explode( ',', $order );
$options = array_merge( array_flip( $order ), $options );
}
if ( ! \EDD\Checkout\Validator::has_block() ) {
$original_shortcode_order = array( 'address', 'address_2', 'city', 'zip', 'country', 'state' );
$options = array_merge( array_flip( $original_shortcode_order ), $options );
}
```
The first block correctly reorders `$options` to the user's saved sort. The second block then unconditionally prepends the hardcoded shortcode order. Because `array_merge` assigns key positions by *first occurrence*, this reseats every key at the hardcoded position and discards the user's order. On any site whose checkout page uses the `[download_checkout]` shortcode rather than the `edd/checkout` block, the multicheck list is forced back to `address → address_2 → city → zip → country → state` regardless of what's stored. This appears to have been intended as a first-render fallback for the shortcode flow but is missing the empty-order guard.
**Fix:** apply the hardcoded fallback only when no saved order exists (`elseif`).
## Reproduction (before this PR)
1. Install EDD on a site whose checkout page uses the `[download_checkout]` shortcode.
2. Go to `Downloads → Settings → Payments → Checkout`.
3. Drag "Country" above "Address Line 1", save.
4. Reload the page → the list reverts to the default order.
5. Inspect `wp_options.edd_settings.checkout_address_fields_order` → it contains the correct dragged order. The front-end checkout also renders fields in the correct dragged order (Registry consumes the option directly at `src/Forms/Checkout/Registry.php:93`). Only the admin UI is wrong.
6. Toggle any unrelated checkbox and save → `checkout_address_fields_order` is now wiped to an empty string.
## After
- The hidden order input is hydrated with the stored value on every render, so non-drag saves no longer wipe the order.
- The admin multicheck list renders in the user's saved order on both shortcode and block checkouts.
- The hardcoded shortcode order is preserved as a first-run fallback when nothing has been saved yet.
## Test plan
- [ ] Shortcode checkout site, no saved order → list renders as `address, address_2, city, zip, country, state` (unchanged default).
- [ ] Shortcode checkout site, drag to a custom order, save, reload → custom order persists in the admin UI and on the front-end.
- [ ] Same site, save the settings page without dragging → `checkout_address_fields_order` retains its prior value.
- [ ] Block checkout site → behavior unchanged from current main (saved order honored, no shortcode fallback applied).
- [ ] Other sortable multichecks routed through `edd_multicheck_callback` (e.g. anything else passing `'sortable' => true`) → hidden input is now populated from the matching `<id>_order` option on render.
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes a couple bugs with how the address fields are displayed/sorted in the admin area when using the old checkout shortcode. Full details are below (summarized by AI).
The "Checkout Address Fields" multicheck on
Downloads → Settings → Payments → Checkoutis supposed to remember the order you drag the fields into. It doesn't — the saved order is correctly written toedd_settings[checkout_address_fields_order]and honored by the front-end checkout, but the admin settings screen ignores it and re-renders the list in a hardcoded order. Re-saving the settings page without re-dragging then wipes the stored order entirely. Two compounding bugs are responsible; this PR fixes both.Bug 1 —
edd_multicheck_callback()always reads an empty orderincludes/admin/settings/register-settings.php:709The literal key passed to
edd_get_option()isedd_settings[checkout_address_fields_order— the closing]is on the wrong side of the function call, and theedd_settings[…]wrapper shouldn't be there in the first place becauseedd_get_option()already reads from theedd_settingsarray (see lines 838 and 903 in the same file for the correct pattern, e.g.edd_get_option( 'payment_icons_order', '' )).As a result this lookup always returns the
array()default, so the hidden<input class="edd-order" value="">rendered byEDD\HTML\Multicheckis always blank on page load. The jQuery UIsortablestophandler updates the hidden input on drag, so a drag-then-save round-trip works once — but the next page load wipes the value, and any non-drag save (e.g. toggling an unrelated checkbox) POSTs an empty string and erases the saved order.Fix: strip the wrapper and the stray bracket so the key is just
<id>_order.Bug 2 —
Gateways::get_address_options()clobbers the saved ordersrc/Admin/Settings/Tabs/Gateways.php:591-601The first block correctly reorders
$optionsto the user's saved sort. The second block then unconditionally prepends the hardcoded shortcode order. Becausearray_mergeassigns key positions by first occurrence, this reseats every key at the hardcoded position and discards the user's order. On any site whose checkout page uses the[download_checkout]shortcode rather than theedd/checkoutblock, the multicheck list is forced back toaddress → address_2 → city → zip → country → stateregardless of what's stored. This appears to have been intended as a first-render fallback for the shortcode flow but is missing the empty-order guard.Fix: apply the hardcoded fallback only when no saved order exists (
elseif).Reproduction (before this PR)
[download_checkout]shortcode.Downloads → Settings → Payments → Checkout.wp_options.edd_settings.checkout_address_fields_order→ it contains the correct dragged order. The front-end checkout also renders fields in the correct dragged order (Registry consumes the option directly atsrc/Forms/Checkout/Registry.php:93). Only the admin UI is wrong.checkout_address_fields_orderis now wiped to an empty string.After