From a63512421b66cb8bdfd28b70f56db73d17c6cf4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rabbi=20Islam=20Rony=20=E2=9A=A1=EF=B8=8F?= <35329385+RabbiIslamRony@users.noreply.github.com> Date: Sun, 9 Aug 2026 10:45:33 +0600 Subject: [PATCH] fix: preserve directory builder access after mode changes Make the multi-directory toggle use the standard settings workflow so changes remain local until the footer Save changes action is used, without a confirmation modal or forced reload. Register the inactive Directory Builder slug as a hidden compatibility page and redirect it to the active mode-specific route. This keeps stale AJAX-era menu links and saved bookmarks working while retaining a single visible submenu item and the existing manage_options capability. Document the manual-save contract and compatibility routing behavior in the settings-panel references. --- .../references/current-settings-panel-map.md | 5 +- .../references/settings-option-catalog.md | 2 +- includes/classes/class-settings-panel.php | 8 --- .../class-multi-directory-manager.php | 53 ++++++++++++++++--- 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/docs/agents/directorist-settings-panel/references/current-settings-panel-map.md b/docs/agents/directorist-settings-panel/references/current-settings-panel-map.md index b03f3013b0..77f0199d69 100644 --- a/docs/agents/directorist-settings-panel/references/current-settings-panel-map.md +++ b/docs/agents/directorist-settings-panel/references/current-settings-panel-map.md @@ -85,7 +85,7 @@ Settings values are read throughout Directorist. Treat these areas as connected ## Redesign Implementation Notes -Last updated: 2026-06-08 +Last updated: 2026-08-09 - Completed redesigned areas are locked by default: `Directory` (`General`, `Listings page`, `Single listing`, `Submissions`, `Categories & locations`, `Map`, `Reviews`), `Search` (`Search form`, `Search results`), `Users & accounts` (`Registration`, `Login`, `Dashboard`, `Authors`), `Monetization` (`Currency`, `Featured listings`, `Payment gateways`), `Notifications` (`Channels`, `Events & Templates`), `Appearance` (`Brand & styling`, `Badges`), `Site & pages` (`Pages`, `SEO`, `Schema`, `Maintenance`), `Extensions`, and `Import / Export`. Before changing any locked area, first identify the affected existing option keys, confirm the change with the user, and run focused QA against the reference/current design. Do not silently move, remove, or duplicate fields in locked areas. - The static/reference redesign keeps WordPress admin chrome visible. Only the Directorist settings surface should be redesigned inside the available `#wpcontent` area. @@ -112,7 +112,8 @@ Last updated: 2026-06-08 - The footer `Save changes` button should use the same `hasUnsavedChanges` comparator as the unsaved hint: disabled when there are no real changes, enabled only after a setting value differs from `cached_fields`, and disabled again while the save request is processing. - The footer save button's loading label is injected via `v-html` with a Font Awesome `` tag. Keep `.settings-save-btn` as inline-flex with a small gap, and normalize child `i` to a 14px inline-flex box so the spinner is centered vertically/horizontally with `Saving...`. - After a normal successful settings save, the footer save button briefly shows ` Saved` for about 1600ms using the local `.settings-save-btn--saved` state. Show this only after WordPress returns `status.success` and after changed fields are committed to `cached_fields`; do not show it for validation errors, failed AJAX responses, no-op saves, or the leave-guard `Save & leave` redirect path. -- The settings leave guard is page-exit only. `Settings_Manager.vue` listens for document clicks outside the Vue settings shell and opens a modal only when `hasUnsavedChanges` is true and the target is a normal same-window navigation link. Internal settings menu/submenu/search clicks stay unguarded because they are inside `this.$el`. Browser refresh/close/back uses the native `beforeunload` prompt because browsers do not allow a custom modal there. The leave guard modal should use the same `cptm-modal-container`, `cptm-modal-header`, `cptm-modal-action-link`, `cptm-modal-confirmation-title`, and `cptm-btn-rounded` scaffold as `Confirmation_Modal.vue`, which is the modal used by the `enable_multi_directory` toggle confirmation. Keep only minimal unsaved-specific overrides such as width, copy spacing, and button sizing; do not add a separate body background or custom close-icon treatment. +- `enable_multi_directory` follows the standard unsaved-settings flow: changing the switch does not show a confirmation modal, save automatically, or reload the page. Because the AJAX save leaves the current WordPress admin menu unchanged, Directory Builder keeps its mode-specific visible route (`atbdp-layout-builder` when disabled and `atbdp-directory-types` when enabled) while the inactive slug is registered as a hidden compatibility page that redirects to the active route before rendering. This keeps stale menu links and bookmarks working without showing a duplicate submenu item. +- The settings leave guard is page-exit only. `Settings_Manager.vue` listens for document clicks outside the Vue settings shell and opens a modal only when `hasUnsavedChanges` is true and the target is a normal same-window navigation link. Internal settings menu/submenu/search clicks stay unguarded because they are inside `this.$el`. Browser refresh/close/back uses the native `beforeunload` prompt because browsers do not allow a custom modal there. The leave guard modal should use the shared confirmation scaffold from `Confirmation_Modal.vue`, including `cptm-modal-container`, `cptm-modal-header`, `cptm-modal-action-link`, `cptm-modal-confirmation-title`, and `cptm-btn-rounded`. Keep only minimal unsaved-specific overrides such as width, copy spacing, and button sizing; do not add a separate body background or custom close-icon treatment. - Leave-guard copy should stay short. Use `Save changes before leaving?` with a brief helper such as `Unsaved changes will be lost.` rather than long explanatory text. - Shared confirmation modals should not render empty feedback placeholders. If no feedback/error message exists, omit the `.cptm-form-group-feedback` node rather than leaving a blank div above the title. - The leave guard's `Save & leave` action must reuse the same settings AJAX payload and update `cached_fields` only after `status.success`, then set a local bypass flag before redirecting so `beforeunload` does not prompt again. Save failures and validation errors must keep the user on the settings page and show the error in the modal. diff --git a/docs/agents/directorist-settings-panel/references/settings-option-catalog.md b/docs/agents/directorist-settings-panel/references/settings-option-catalog.md index 482964ae2b..f82ca74ccc 100644 --- a/docs/agents/directorist-settings-panel/references/settings-option-catalog.md +++ b/docs/agents/directorist-settings-panel/references/settings-option-catalog.md @@ -29,7 +29,7 @@ Redesigned UI note (2026-06-08): Core listing display settings are no longer rou ### General -- `enable_multi_directory`: enables multi-directory mode and exposes directory type workflows. +- `enable_multi_directory`: enables multi-directory mode and exposes directory type workflows. The toggle changes directly without a confirmation modal and persists only through the standard `Save changes` action; it does not automatically save or reload the settings page. - `guest_listings`: allows listing submission by non-logged-in visitors. - `guest_email_label`, `guest_email_placeholder`: customize guest email field copy on listing submission. - `new_user_registration`: controls whether registration is enabled from Directorist flows. diff --git a/includes/classes/class-settings-panel.php b/includes/classes/class-settings-panel.php index 9081ecf7f7..4889f3f993 100644 --- a/includes/classes/class-settings-panel.php +++ b/includes/classes/class-settings-panel.php @@ -149,14 +149,6 @@ public function register_setting_fields( $fields = [] ) { 'type' => 'toggle', 'label' => 'Enable Multi Directory', 'value' => false, - 'confirm-before-change' => true, - 'confirmation-modal' => [ - 'show-model-header' => false - ], - 'data-on-change' => [ - 'action' => 'updateData', - 'args' => [ 'reload_after_save' => true ] - ], 'componets' => [ 'link' => [ 'label' => __( 'Start Building Directory', 'directorist' ), diff --git a/includes/modules/multi-directory-setup/class-multi-directory-manager.php b/includes/modules/multi-directory-setup/class-multi-directory-manager.php index 3631ad34b1..a4be98833e 100644 --- a/includes/modules/multi-directory-setup/class-multi-directory-manager.php +++ b/includes/modules/multi-directory-setup/class-multi-directory-manager.php @@ -747,13 +747,9 @@ public static function load_builder_data() { // add_menu_pages public function add_menu_pages() { - $page_title = __( 'Directory Builder', 'directorist' ); - $page_slug = 'atbdp-layout-builder'; - - if ( directorist_is_multi_directory_enabled() ) { - $page_title = __( 'Directory Builder', 'directorist' ); - $page_slug = 'atbdp-directory-types'; - } + $page_title = __( 'Directory Builder', 'directorist' ); + $page_slug = $this->get_active_directory_builder_page_slug(); + $compatibility_page_slug = ( 'atbdp-directory-types' === $page_slug ) ? 'atbdp-layout-builder' : 'atbdp-directory-types'; add_submenu_page( 'edit.php?post_type=at_biz_dir', @@ -764,6 +760,49 @@ public function add_menu_pages() { [$this, 'menu_page_callback__directory_types'], 5 ); + + $compatibility_page_hook = add_submenu_page( + '', + $page_title, + $page_title, + 'manage_options', + $compatibility_page_slug, + [$this, 'redirect_to_active_directory_builder_page'] + ); + + if ( $compatibility_page_hook ) { + add_action( "load-{$compatibility_page_hook}", [$this, 'redirect_to_active_directory_builder_page'] ); + } + } + + /** + * Get the directory builder page slug for the current multi-directory mode. + * + * @return string + */ + private function get_active_directory_builder_page_slug() { + return directorist_is_multi_directory_enabled() ? 'atbdp-directory-types' : 'atbdp-layout-builder'; + } + + /** + * Redirect the inactive directory builder route to the active route. + * + * This keeps stale admin-menu links and saved bookmarks working after the + * multi-directory setting is changed through the AJAX settings form. + * + * @return void + */ + public function redirect_to_active_directory_builder_page() { + $redirect_url = add_query_arg( + [ + 'post_type' => 'at_biz_dir', + 'page' => $this->get_active_directory_builder_page_slug(), + ], + admin_url( 'edit.php' ) + ); + + wp_safe_redirect( $redirect_url ); + exit; } // get_default_directory_id