fix: for custom time format store opening closing not working in vendor store settings#3090
Conversation
โฆor store settings
๐ WalkthroughWalkthroughServer-side time conversions were simplified to pass only the time string; client templates separate visible time inputs from hidden submission inputs; client JS adds a Moment-compatible i18n time-format helper and uses it for timepicker parsing/formatting, validation, and populating hidden fields before submit. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser as Client JS
participant Server as PHP
participant DB
User->>Browser: Enter opening/closing times (visible inputs)
Browser->>Browser: Map locale -> moment format\nParse & format times, populate hidden hidden inputs
User->>Browser: Submit form
Browser->>Server: POST with hidden time fields
Server->>Server: Convert/validate times (dokan_convert_date_format)
Server->>DB: Save timings
DB-->>Server: Persisted
Server-->>Browser: Response (saved)
Browser-->>User: Show confirmation
Estimated code review effort๐ฏ 3 (Moderate) | โฑ๏ธ ~25 minutes Suggested labels
Suggested reviewers
Poem
๐ฅ Pre-merge checks | โ 2 | โ 1โ Failed checks (1 warning)
โ Passed checks (2 passed)
โ๏ธ Tip: You can configure your own custom pre-merge checks in the settings. โจ 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
๐ค Fix all issues with AI agents
In `@templates/settings/store-form.php`:
- Around line 340-344: The client-side time formatting currently uses
moment(...).format('hh:mm a') for openValueSelected and closeValueSelected which
produces leading zeros; update both calls to use format('h:mm a') to match the
server-side PHP expectation (ensure the two lines setting openValueSelected and
closeValueSelected are changed), so the values written via
$openInputHidden.val(...) and $closeInputHidden.val(...) will have no leading
zero.
In `@templates/settings/store-time.php`:
- Around line 26-32: The value attributes for the opening time inputs are
outputting the raw $opening_time variable and must be escaped to prevent XSS;
update both the visible input (id "opening-time[<?php echo esc_attr( $day_key );
?>]" / class "opening-time") and the hidden input (name "opening_time[<?php echo
esc_attr( $day_key ); ?>]" / class "opening-time-hidden") to wrap $opening_time
with esc_attr() so the attribute values are safely escaped before rendering.
๐งน Nitpick comments (1)
templates/settings/store-form.php (1)
378-385: Same format inconsistency and missing invalid date handling.
- Same
'hh:mm a'vs'h:mm a'issue as the change handler.- If
moment()parsing fails (e.g., empty or malformed input after manual edit),format()returns"Invalid date"which would be submitted to the server.Proposed fix
const formattedOpenValue = moment( openValue, timeFormatMoment ).format( 'HH:mm' ), formattedCloseValue = moment( closeValue, timeFormatMoment ).format( 'HH:mm' ); - let openValueSelected = moment(openValue, timeFormatMoment ).format('hh:mm a'); - let closeValueSelected = moment(closeValue, timeFormatMoment ).format('hh:mm a'); + const parsedOpen = moment( openValue, timeFormatMoment ); + const parsedClose = moment( closeValue, timeFormatMoment ); + + if ( ! parsedOpen.isValid() || ! parsedClose.isValid() ) { + self.find( 'input.dokan-form-control' ).css({ 'border-color': '#F87171', 'color': '#F87171' }); + self.find( '.opening-time' ).focus(); + e.preventDefault(); + return false; + } + + let openValueSelected = parsedOpen.format( 'h:mm a' ); + let closeValueSelected = parsedClose.format( 'h:mm a' ); $openInputHidden.val(openValueSelected); $closeInputHidden.val(closeValueSelected);
templates/settings/store-form.php
Outdated
| let openValueSelected = moment( openValue, timeFormatMoment ).format('hh:mm a' ); | ||
| let closeValueSelected = moment( closeValue, timeFormatMoment ).format('hh:mm a' ); | ||
|
|
||
| $openInputHidden.val( openValueSelected ); | ||
| $closeInputHidden.val( closeValueSelected ); |
There was a problem hiding this comment.
Use 'h:mm a' format to match server-side expectations.
The 'hh:mm a' format outputs times with leading zeros (e.g., "09:30 am"), but the PHP backend uses 'g:i a' which expects no leading zeros (e.g., "9:30 am"). Use moment's single 'h' to avoid potential parsing issues.
Proposed fix
- let openValueSelected = moment( openValue, timeFormatMoment ).format('hh:mm a' );
- let closeValueSelected = moment( closeValue, timeFormatMoment ).format('hh:mm a' );
+ let openValueSelected = moment( openValue, timeFormatMoment ).format('h:mm a' );
+ let closeValueSelected = moment( closeValue, timeFormatMoment ).format('h:mm a' );๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let openValueSelected = moment( openValue, timeFormatMoment ).format('hh:mm a' ); | |
| let closeValueSelected = moment( closeValue, timeFormatMoment ).format('hh:mm a' ); | |
| $openInputHidden.val( openValueSelected ); | |
| $closeInputHidden.val( closeValueSelected ); | |
| let openValueSelected = moment( openValue, timeFormatMoment ).format('h:mm a' ); | |
| let closeValueSelected = moment( closeValue, timeFormatMoment ).format('h:mm a' ); | |
| $openInputHidden.val( openValueSelected ); | |
| $closeInputHidden.val( closeValueSelected ); |
๐ค Prompt for AI Agents
In `@templates/settings/store-form.php` around lines 340 - 344, The client-side
time formatting currently uses moment(...).format('hh:mm a') for
openValueSelected and closeValueSelected which produces leading zeros; update
both calls to use format('h:mm a') to match the server-side PHP expectation
(ensure the two lines setting openValueSelected and closeValueSelected are
changed), so the values written via $openInputHidden.val(...) and
$closeInputHidden.val(...) will have no leading zero.
โฆ-closing-time-not-working-for-custom-time-format
This reverts commit bcb2376.
There was a problem hiding this comment.
Actionable comments posted: 2
๐ค Fix all issues with AI agents
In `@templates/settings/store-form.php`:
- Around line 339-361: The change handler on
$('.dokan-store-times').on('change', '.dokan-form-group', ...) currently
compares formattedOpenValue > formattedCloseValue which permits equal open/close
times visually but the submit handler uses formattedOpenValue >=
formattedCloseValue and blocks equals; update the change handler's comparison to
formattedOpenValue >= formattedCloseValue (the same comparison used on submit)
so the error styling triggers immediately โ locate the handler by the selector
'.dokan-store-times' / '.dokan-form-group' and the variables formattedOpenValue
and formattedCloseValue and replace the '>' check with '>=' for consistency.
In `@templates/settings/store-time.php`:
- Around line 37-41: The template references an undefined variable $full_day and
uses the magic sentinel string '11:59 pm'; fix by pulling $full_day from the
incoming $args with a safe default (e.g. $full_day = isset($args['full_day']) ?
(bool)$args['full_day'] : false) in templates/settings/store-time.php so the
ternary on $closing_time won't error, and replace the literal '11:59 pm'
comparison with a named constant (e.g. define('STORE_FULL_DAY_SENTINEL', '11:59
pm') or use an existing class constant like Store_Settings::FULL_DAY_SENTINEL)
and use that constant in the closing_time hidden input value expression to avoid
brittle string comparisons; ensure any other uses of the sentinel across the
template or related store-form.php consume the same constant.
๐งน Nitpick comments (1)
templates/settings/store-form.php (1)
321-329:mapTimepickerLocaleToMomentperforms sequential single-occurrence replacements โ beware of overlapping tokens.The chained
.replace()calls replace locale AM/PM strings one at a time. If a locale'sPMstring happens to be a substring of theAMstring (or vice versa), or if the time value itself contains characters that match a locale token unexpectedly, the replacements can interfere with each other.For typical locales this is fine, but consider guarding against it by only replacing the matched locale token (e.g., using a regex with word boundaries or replacing only the last token in the string).
| $('.dokan-store-times').on('change', '.dokan-form-group', function() { | ||
| const self = $(this), | ||
| openValue = self.find('.opening-time').val(), | ||
| closeValue = self.find('.closing-time').val(), | ||
| openInputHidden = self.find('.opening-time-hidden'), | ||
| closeInputHidden = self.find('.closing-time-hidden'), | ||
| formattedOpenValue = moment(mapTimepickerLocaleToMoment(openValue), timeFormatMoment).format('HH:mm'), | ||
| formattedCloseValue = moment(mapTimepickerLocaleToMoment(closeValue), timeFormatMoment).format('HH:mm'); | ||
|
|
||
| let openValueSelected = moment(mapTimepickerLocaleToMoment(openValue), timeFormatMoment).locale('en').format('hh:mm a'); | ||
| let closeValueSelected = moment(mapTimepickerLocaleToMoment(closeValue), timeFormatMoment).locale('en').format('hh:mm a'); | ||
|
|
||
| openInputHidden.val(openValueSelected); | ||
| closeInputHidden.val(closeValueSelected); | ||
| if (formattedOpenValue > formattedCloseValue) { | ||
| self.find('input.dokan-form-control').css({ | ||
| 'border-color': '#F87171', | ||
| 'color': '#F87171' | ||
| }); | ||
| } else { | ||
| self.find( 'input.dokan-form-control' ).css({ 'border-color': '#bbb', 'color': '#4e4e4e' }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Inconsistent validation: change handler uses > but submit handler uses >= for time comparison.
On line 353 (change handler), the comparison is formattedOpenValue > formattedCloseValue, which allows equal open/close times without flagging an error. On line 399 (submit handler), it's formattedOpenValue >= formattedCloseValue, which rejects equal times. This means a user can set equal open/close times, see no visual error feedback, but then be blocked on submit โ a confusing UX.
Use >= in both places so the error styling appears immediately.
Proposed fix (change handler, line 353)
- if (formattedOpenValue > formattedCloseValue) {
+ if (formattedOpenValue >= formattedCloseValue) {Also applies to: 363-411
๐ค Prompt for AI Agents
In `@templates/settings/store-form.php` around lines 339 - 361, The change handler
on $('.dokan-store-times').on('change', '.dokan-form-group', ...) currently
compares formattedOpenValue > formattedCloseValue which permits equal open/close
times visually but the submit handler uses formattedOpenValue >=
formattedCloseValue and blocks equals; update the change handler's comparison to
formattedOpenValue >= formattedCloseValue (the same comparison used on submit)
so the error styling triggers immediately โ locate the handler by the selector
'.dokan-store-times' / '.dokan-form-group' and the variables formattedOpenValue
and formattedCloseValue and replace the '>' check with '>=' for consistency.
templates/settings/store-time.php
Outdated
| value="<?php echo esc_attr( ! $full_day ? dokan_convert_date_format( $closing_time, 'g:i A', 'H:i' ) : '' ); ?>" /> | ||
| <input type="hidden" | ||
| name="closing_time[<?php echo esc_attr( $day_key ); ?>]" | ||
| class="closing-time-hidden" | ||
| value="<?php echo esc_attr( $closing_time === '11:59 pm' ? '11:30 pm' : $closing_time ); ?>" /> |
There was a problem hiding this comment.
๐งฉ Analysis chain
๐ Script executed:
#!/bin/bash
# First, locate the file and get its full context
find . -name "store-time.php" -type fRepository: getdokan/dokan
Length of output: 93
๐ Script executed:
#!/bin/bash
# Search for $full_day definition/usage
rg -n '\$full_day' --type php -B3 -A3Repository: getdokan/dokan
Length of output: 999
๐ Script executed:
#!/bin/bash
# Search for '11:59 pm' sentinel usage across the codebase
rg -n '11:59 pm' --type phpRepository: getdokan/dokan
Length of output: 214
๐ Script executed:
#!/bin/bash
# Also search for variations like uppercase/no space
rg -n '11:59' --type php | head -20Repository: getdokan/dokan
Length of output: 214
๐ Script executed:
#!/bin/bash
# Get line count and read the entire template file
wc -l ./templates/settings/store-time.php
echo "---"
cat -n ./templates/settings/store-time.phpRepository: getdokan/dokan
Length of output: 3530
๐ Script executed:
#!/bin/bash
# Find where this template is included/required from
rg -n 'store-time.php' --type phpRepository: getdokan/dokan
Length of output: 40
๐ Script executed:
#!/bin/bash
# Search for where $full_day is SET (not just used)
rg -n '\$full_day\s*=' --type php -B2 -A2Repository: getdokan/dokan
Length of output: 40
๐ Script executed:
#!/bin/bash
# Find where store-time.php is included/required
rg -n 'store-time' --type php -B2 -A2Repository: getdokan/dokan
Length of output: 7814
๐ Script executed:
#!/bin/bash
# Search in the templates directory for includes and parent files
rg -n '\$full_day' --type php -B5 -A5 2>/dev/null | head -50Repository: getdokan/dokan
Length of output: 1396
๐ Script executed:
#!/bin/bash
# Look for template loading in controller/view files
fd -name '*.php' -path '*/templates/*' | grep -i store | head -20Repository: getdokan/dokan
Length of output: 288
๐ Script executed:
#!/bin/bash
# Read store-form.php to see how $args is built
wc -l ./templates/settings/store-form.php
echo "---"
sed -n '1,100p' ./templates/settings/store-form.php | cat -nRepository: getdokan/dokan
Length of output: 6053
๐ Script executed:
#!/bin/bash
# Search for where the template is actually included/loaded in store-form.php
rg -n 'get_template_part|include|require' ./templates/settings/store-form.phpRepository: getdokan/dokan
Length of output: 360
๐ Script executed:
#!/bin/bash
# Search for $full_day assignment across the entire codebase
rg -n '\$full_day' --type phpRepository: getdokan/dokan
Length of output: 234
๐ Script executed:
#!/bin/bash
# Find the dokan_get_template_part function definition
rg -n 'function dokan_get_template_part' --type php -A10Repository: getdokan/dokan
Length of output: 609
๐ Script executed:
#!/bin/bash
# Also search for where $full_day might be set via filter or other means
rg -n 'full_day' --type phpRepository: getdokan/dokan
Length of output: 234
๐ Script executed:
#!/bin/bash
# Check if there's extract() call in store-time.php or its parent
rg -n 'extract\(' --type php | grep -E '(store-time|store-form)'Repository: getdokan/dokan
Length of output: 40
Fix the undefined $full_day variable and extract the '11:59 pm' sentinel to a named constant.
The $full_day variable referenced on line 37 is never passed in the $args array (defined in store-form.php lines 43-47) and doesn't exist anywhere else in the codebase. This will cause an undefined variable error when the template renders. The '11:59 pm' sentinel comparison on line 41 is brittleโit should be defined as a class constant or configuration value to avoid silent failures if the stored time format ever changes.
๐ค Prompt for AI Agents
In `@templates/settings/store-time.php` around lines 37 - 41, The template
references an undefined variable $full_day and uses the magic sentinel string
'11:59 pm'; fix by pulling $full_day from the incoming $args with a safe default
(e.g. $full_day = isset($args['full_day']) ? (bool)$args['full_day'] : false) in
templates/settings/store-time.php so the ternary on $closing_time won't error,
and replace the literal '11:59 pm' comparison with a named constant (e.g.
define('STORE_FULL_DAY_SENTINEL', '11:59 pm') or use an existing class constant
like Store_Settings::FULL_DAY_SENTINEL) and use that constant in the
closing_time hidden input value expression to avoid brittle string comparisons;
ensure any other uses of the sentinel across the template or related
store-form.php consume the same constant.
All Submissions:
Changes proposed in this Pull Request:
Related Pull Request(s)
Closes
How to test the changes in this Pull Request:
Changelog entry
Title
Detailed Description of the pull request. What was previous behaviour
and what will be changed in this PR.
Before Changes
Describe the issue before changes with screenshots(s).
After Changes
Describe the issue after changes with screenshot(s).
Feature Video (optional)
Link of detailed video if this PR is for a feature.
PR Self Review Checklist:
FOR PR REVIEWER ONLY:
Summary by CodeRabbit