feat(vendor-settings): flat-array Store settings backend (schema, mapper, writer, REST) - #3310
Conversation
…per, writer, REST) Backend for the vendor Store Settings React migration (PR 1 of 3, spec: getdokan/plugin-internal-tasks#2115). Serves the plugin-ui flat-array schema with values from dokan_profile_settings and persists through the exact legacy pipeline - storage keys and value shapes stay byte-identical. - StoreSettingsSchema: sections/fields with legacy server-side gating; Pro extends via the new dokan_get_vendor_settings_schema filter. - ValueMapper: flat ids -> legacy keys (composite store_map/address, nested catalog_mode preserving RFQ's key + the legacy forced-off rule). - StoreSettingsWriter: shallow merge, dokan_store_name mirror, both legacy seams; never re-applies the legacy dokan_store_time POST filter. - VendorStoreSettingsController: GET/PUT /dokan/v1/vendor-settings/store, 400 {errors:{field_id}} contract, g:i a schedule validation, Pro sanitize/validate extension filters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
… variants Wiring + components for the vendor Store Settings React page (PR 2 of 3, spec: getdokan/plugin-internal-tasks#2115), delivered through the existing VendorNavMenuChecker takeover - no new flag or template interception. - SPA route /settings/store (dokan_view_store_settings_menu) mounting the plugin-ui <Settings> engine with hookPrefix dokan_vendor against GET/PUT /dokan/v1/vendor-settings/store; 400 field errors re-thrown in the {errors} shape plugin-ui merges into per-field state. - react_route on the Settings > Store nav item + template dependencies (store-form, store-time, address-form, maps-with-search) so any theme override automatically falls back to the legacy page. - 4 custom variants: vendor_image (wp.media via @dokan/components MediaUploader, attachment-ID fidelity), vendor_address (WC country/state cascade from dokan/v1/data/countries), vendor_map (Google canvas + places autocomplete, provider-agnostic composite value), and vendor_store_schedule (shared WeeklyTimeSlots bound to the legacy dokan_store_time struct per dokan-pro#5915; Lite single-range, Pro flips multiple via the schema filter). - wp_enqueue_media() on the new-dashboard asset path for the media fields. Verified live on dokan-core.test: route renders schema cards, banner preview + values populate, schedule/ToC dependency toggles hide fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completion pass for the vendor Store Settings React page (PR 3 of 3, spec: getdokan/plugin-internal-tasks#2115). - vendor_map: full Mapbox support (mapbox-gl on demand, draggable marker, Enter-to-geocode via the Mapbox places API) alongside Google; Google auth failures (gm_authFailure) and loader errors now degrade to plain coordinate inputs instead of a dead canvas. - vendor_image: Change action under the preview (Figma parity) in addition to remove; still persists attachment IDs only. - Schema: subpage titled Store so the content header no longer duplicates the page title. Verified end-to-end on dokan-core.test: PUT with empty store name returns 400 {errors:{store_name}}; a real save flips dokan_store_time_enabled, keeps all 47 profile keys byte-identical (vendor_biography/payment untouched), syncs the dokan_store_name mirror, and the LEGACY settings form immediately renders the change (schedule checkbox on, day rows visible). Snapshot restored after testing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ST saves Verifier finding (plan-aligner #7): RFQ's Seam-A handler is nonce-guarded and silent on REST saves, so a React save turning the cart button back on left request_a_quote_enabled='on' where the identical legacy save writes 'off'. The mapper now applies the same forced-off rule when the key exists, keeping REST and AJAX saves byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ore-settings-react-wiring
…or-store-settings-page
Reworks the page presentation to the Figma Store frames using only plugin-ui's native schema capabilities (no engine forks): - Every section is its own card with title + helper description (Branding, Store Information, Store Locations, Store Map, Store Schedule, Catalog Mode, Terms & Conditions) ordered via priority so Pro slots its cards (Store Biography lands before T&C). - Fields use layout: full-width (stacked label above a full-width control); subpage hide_heading kills the duplicated inner title; the route header reads Store. - Store schedule renders the delivery-time treatment: WeeklyTimeSlots inside a bordered box with divided weekday rows (dokan-pro#5915). - vendor_image matches the Figma media pattern: spec line, preview with pencil-Change and trash beside it, circular logo via the new shape attribute. - Footer gains Cancel (refetch + engine remount discards edits) alongside Save Changes. - Map card: on Google auth failure the search input is handed back to the vendor (Google disables it and injects an error string after gm_authFailure), and a bare ',' stored location displays empty. Field ids, storage keys, and value shapes are untouched - this is presentation only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… Cancel style
Figma re-verification findings (design agent, 21 -> 8 mismatches after the
rework; these close the two real defects and one style delta):
- vendor_image remove button: the SVG lost the fight with the theme's
button rules (same battle WeeklyTimeSlots' icon buttons solve) - inline
lucide size + important-flagged classes make the trash glyph render.
- vendor_store_schedule: override the shared component's delivery-domain
validation copy ('%s delivery time can not be empty') with store-schedule
wording via the messages prop.
- Cancel is a ghost (borderless) button per the Figma footer.
Verified live: banner row renders [pencil Change] [trash] per the design;
map search input restores after Google auth failure with the proper
placeholder, and a bare ',' stored location displays empty.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation and page chrome - Header: "Store Settings" title with Cancel/Update Settings portaled beside it; the engine save area stays as the Figma footer, stripped of its bar chrome - Cards sit flush with the page title (dokan-tailwind ships !important utilities, so the gutter/save-bar overrides carry the flag too) - Store Title gains the red (Required) marker via a vendor_text variant - Banner/Logo reworked to the admin vendor-edit pattern: title+spec with inline Change/delete controls, full-width banner frame, default banner/logo placeholders - New vendor_multiselect renderer (SmartMultiSelect) that Pro drives for Store Category; non_meta fields skip the profile slice and persist on the new dokan_after_saving_vendor_settings seam - Store Information: email toggle (with helper copy) ahead of Phone - Page-shaped loading skeleton replacing the engine's sidebar-panel skeleton - Terms & Conditions card expanded by default Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… editor - Day rows render full-bleed in the card (horizontal rules only) instead of a second bordered/padded box - Days with no stored times show one dimmed empty pair, so disabled rows read like the delivery-time page instead of bare labels - Toggling a day off keeps its times in the form (dimmed, delivery behaviour); the server still zeroes closed days at save so storage stays legacy-identical - Errors surface on touch like the delivery page (no validate-on-mount) - Helper descriptions for the schedule toggle and open/close notices Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A Full Day slot previously hid its + button, leaving a gap beside the trash so the row didn't line up with dated rows. Render it visible-but-disabled (a full day already spans 24h, matching the disabled trash), so every row aligns in both the store schedule and the delivery-time editor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… cross-field validation seam - New vendor_store_locations variant: DataViews locations table with add/edit/delete modals; row 0 is the pinned Default location and extra rows are gated by the sibling multiple-locations switch (Pro injects the section and owns persistence). - New vendor_rich_text variant so store_tnc can render the red (Required) marker; the schema marks it required and adds T&C field descriptions. - update_item() now applies dokan_rest_vendor_settings_validate before the 400 return so Pro modules can enforce cross-field rules (e.g. min <= max). - style.scss: seat the DataViews grid flush inside the settings card, lift the location popovers above the WP modal overlay, and pin the light input theme inside the modal (it renders outside plugin-ui's theme provider). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…add-slot end-of-day gate - Add `vendor_number` variant with an optional live cross-field guard so the cart Min-Max "max ≥ min" error surfaces the instant either value changes, not only after Save (mirrors the server rule client-side). - Store Map: render the search box with the shared Input component and geocode the map on the fly as the vendor types (Google + Mapbox), keeping Places autocomplete and pin drag on the same composite value. - WeeklyTimeSlots: retire the add-slot "+" once a slot closes at the last selectable preset (11:30 pm), matching the legacy "Add hours" behaviour. - Register the new field variants (number, plus the pending company-bank, vacation-history, date-range, radio and textarea renderers). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Emit `type => tab` elements (General/Location/Schedule/Business/Policies) with inline `tab_id` on each Lite section; group_into_tabs() runs after the schema filter so extensions place cards by declaring `tab_id` on their section (or injecting their own tab element) — undeclared cards fall back to General and empty tabs are dropped. - TabKeeper keeps the active tab across the save/cancel refresh-remounts, and a failed save activates the first tab carrying a validation error. - Header Save/Cancel pair removed — the footer pair is the save UI. - Tab strip styling: flush-left, 32px gaps, 15px/600 labels, near-black resting color, 1px active underline flush with the strip hairline (active color already follows the customizer via the base --primary map). - Store Map card: "Find Address" title and spacing above the canvas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The `dokan-before-header` Slot wrapper always renders, and when nothing fills the slot (every page by default) the empty div still occupies a slot in the header's `flex flex-col gap-4` column — a phantom 16px of space above the page title on every vendor-dashboard SPA page. `empty:hidden` removes it from the flow until a plugin actually fills the slot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tabs with little content (e.g. Policies' single Terms & Conditions card) let the Cancel/Save row hug the card with a sea of empty page below. The content region now keeps a 400px minimum, and the engine's inner wrapper is stretched into a full-height column so the cards container's existing flex-1 pushes the save row to the bottom of the region — the footer holds a steady, breathable position across all tabs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The address variant hand-rolled bare <input> elements, so the dashboard theme's generic input chrome (grey fill, heavier border) painted over Street/Street 2/City/ZIP while sibling fields (Store Name, etc.) rendered through plugin-ui's <Input>. The text subfields — and the country/state free-text fallbacks — now use the same <Input> component, and the native country/state selects pin a white background so the whole grid reads as one family of controls. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Make VendorStoreSettingsController variant-agnostic, mirroring AdminSettingsController: a field declares its own `sanitize_callback` (tried before the variant switch) and `validation_func` (run after the declarative rules), so the controller no longer special-cases phone, store_tnc or the store schedule. - update_item now sanitizes every field first, then validates, so a field's validation_func can compare siblings (returns true|false| string|string[]). - Move the schedule sanitize/validate into a new StoreScheduleValidator and wire it as the field's callbacks; phone + store_tnc collapse move onto their fields; the enable_tnc→content rule becomes store_tnc's validation_func. - Keep the whole-payload `dokan_rest_vendor_settings_validate` filter for section-level rules that belong to no single field (seller vacation). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A merge concatenated both sides of the class-map conflict, registering every controller twice (48 entries). Collapse it to the 34-entry union: each controller once, keeping both the settings controllers this branch adds (AdminSettingsController, VendorStoreSettingsController) and the base's newer ones (ProductControllerV3, AdminDashboardStatsController, WithdrawExportController, ExportController, AdminExtensionsController). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Pro counterpart: getdokan/dokan-pro#5919 — extends this vendor Store settings implementation (module sections, tab placements, min-max validation) and should ship together with it. |
Align Manager.php with the parent flat-array settings branch and add just the one line this PR owns — the VendorStoreSettingsController route. The class-map de-duplication and the AdminSettingsController registration are the parent PR's (refactor/simplify-settings-to-flat-array) concern, not this one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backend: - dedupe the vendor-resolution 404, extract normalize_field_key() and validate_rule() to flatten the sanitize/validate nesting - StoreScheduleValidator: split validate_open_day() out of the day loop - ValueMapper: drop the empty catalog switch cases for a single skip-guard + legacy_entry() mapper - schema: visible_when() helper replaces three inlined show/hide pairs - keep __() (not esc_html__) for schema strings: plugin-ui renders labels as React text with no entity decode, so esc_html__ would double-escape Frontend: - reuse plugin-ui built-ins: store_name -> text, store_tnc -> rich_text, vacation message -> textarea; delete the pure-wrapper variants - register-fields is now a data-driven variant->component map - new shared.tsx: useCountries() (cached + decodeEntities, fixes AddressFields not decoding), fieldKeyOf(), RequiredMark, shared row-action button classes - ImageField trash + Vacation textarea use plugin-ui Button/Textarea - rename dead vendor_date_range variant file to RangeInput.tsx Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…to frontend - validate_rule: full-ternary message fallbacks; keep the strict blank check (empty() would reject '0'/0 and diverge from the client's not_empty, matching AdminSettingsController) - split group_into_tabs into base_tabs()/known_tab_ids()/is_tab_member() - add reusable vendor_note field variant (info icon + muted text) so schemas declare note text instead of building raw HTML/SVG in PHP Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-ui v2 markup plugin-ui v2 dropped the [data-slot='popover-portal'] wrapper around the SmartSelect portal, so the old selector matched nothing and the country/state dropdown in the Edit Location Details modal opened invisibly behind the WP modal overlay (z-50 vs 100000). Anchor the lift one level shallower at .pui-root so it survives either markup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…at-array' into feat/vendor-store-settings-backend
…der again plugin-ui v2 evaluates `values[dep.key]` literally against a values map keyed by dot paths, where the old engine resolved a sibling id relative to the field. Schema conventions like `key: 'dokan_store_time_enabled'` therefore matched nothing and every same-section dependent field was silently hidden — the schedule day rows, open/close notices, vacation fields and the terms editor all disappeared behind their toggles with no error. qualifyDependencyKeys() rewrites each dep.key through the engine's own formatSettingsData() map before the schema reaches <Settings>. The same map re-keys REST validation errors, which the engine reads as errors[dependency_key] — bare-id keys meant inline errors never rendered either. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All Submissions:
Changes proposed in this Pull Request:
PR 1 of 3 for the vendor Store Settings → React migration (spec: getdokan/plugin-internal-tasks#2115, parent: getdokan/plugin-internal-tasks#1981). This is the pure PHP backend — no UI change, no behavior change for the legacy page.
Serves the plugin-ui flat-array schema with values from
dokan_profile_settingsand persists through the exact legacy save pipeline, so storage keys and value shapes stay byte-identical and every Pro consumer on the two seams keeps working.Vendor/Settings/Schema/StoreSettingsSchema.php— flatSettingsElement[](page → subpage → collapsible section cards → fields) with values populated inline. Conditional blocks use the same server-side gates astemplates/settings/store-form.php: map only withdokan_has_map_api_key(), ToC only whenseller_enable_terms_and_conditionsis on, schedule only when appearancestore_open_closeis on, email visibility hidden perdokan_is_vendor_info_hidden('email'), address handed over when Pro delivery-time is active, catalog-mode per its admin gates. Pro appends via the newdokan_get_vendor_settings_schemafilter (mirrorsdokan_get_admin_settings_schema).Vendor/Settings/ValueMapper.php— flat field ids → legacy keys. Composites handled bespoke:store_map→location+find_address;addressmerges over previous subkeys (preserves store-pickup'slocation_name); catalog-mode ids → nestedcatalog_modearray preserving RFQ'srequest_a_quote_enabled+ the legacy forced-off rule. Any Pro-injected field persists via its stringlegacy_key(defaults to the field id).Vendor/Settings/StoreSettingsWriter.php— the one write path: shallowarray_merge,dokan_store_namemirror meta,dokan_store_profile_settings_argsfilter, canonical meta write,dokan_store_profile_saved( $id, $merged, $prev ). Deliberately never re-applies the legacydokan_store_timePOST-parsing filter (Pro's parser returnsnullwithout the legacy nonce and would wipe the schedule on REST saves).REST/VendorStoreSettingsController.php—GET/PUT /dokan/v1/vendor-settings/storeonDokanBaseVendorController(vendor-staff aware viaget_vendor_id_for_user()), permissiondokandar+dokan_view_store_settings_menu. Validation failures return400 { errors: { field_id: [messages] } }(plugin-ui merges these into per-field errors). Validations use the plugin-ui client contract ([{ rules: 'not_empty', message }]) so one declaration drives both sides; the schedule validator enforces matchingg:i apairs with opening < closing (single Lite slot and Pro multi-slot both accepted). Pro extension filters:dokan_rest_vendor_settings_sanitize_field/dokan_rest_vendor_settings_validate_field.Related Pull Request(s)
Closes
How to test the changes in this Pull Request:
GET /wp-json/dokan/v1/vendor-settings/store— returns the flat schema with current values; sections respect the admin gates (disable the map API key →store_map_sectiondisappears, etc.).PUT /wp-json/dokan/v1/vendor-settings/storewith{ "values": { "store_name": "" } }→400witherrors.store_name.dokan_profile_settingskeys/shapes are byte-identical to a legacy form save ('yes'/'no','on'/'off', attachment-ID ints, per-day{status, opening_time[], closing_time[]}withg:i astrings); untouched keys (payment,vendor_biography, …) survive;dokan_store_namemirror meta syncs; both legacy seams fire (verify a Seam-B consumer like store-support still persists).Changelog entry
Vendor Store Settings flat-array backend
Adds the schema/REST backend for the React vendor Store Settings page. No user-facing change yet: the legacy page keeps rendering and saving as before; storage stays in
dokan_profile_settingswith unchanged keys and value shapes.🤖 Generated with Claude Code