$staff Staff row.
*/
private function render_staff_time_off_panel( array $staff, int $location_id ): void {
$month = $this->calendar_month_from_request( 'staff_time_off_month' );
$start = $month['start'];
$end = $month['end'];
$exceptions = $this->exceptions->closed_days_for_staff_between( (int) $staff['id'], $start, $end, null );
$all_closed = $this->exceptions->closed_days_for_staff( (int) $staff['id'], null );
$conflicts = $this->conflicts_from_request( 'staff' );
$bookings = $this->booking_conflicts_for_window( 'staff', (int) $staff['id'], $location_id, $start, $end );
?>
render_closure_conflicts_panel( $conflicts, 'staff' ); ?>
render_time_off_month_nav( 'staff', $month ); ?>
render_time_off_periods( $all_closed, 'staff', $month['anchor'] ); ?>
$location Location row.
*/
private function render_location_closures_panel( array $location ): void {
$staff = $this->default_staff();
$month = $this->calendar_month_from_request( 'location_time_off_month' );
$start = $month['start'];
$end = $month['end'];
$exceptions = $this->exceptions->closed_days_for_staff_between( (int) $staff['id'], $start, $end, (int) $location['id'] );
$all_closed = $this->exceptions->closed_days_for_staff( (int) $staff['id'], (int) $location['id'] );
$bookings = $this->booking_conflicts_for_window( 'location', (int) $staff['id'], (int) $location['id'], $start, $end );
?>
render_time_off_month_nav( 'location', $month ); ?>
render_time_off_periods( $all_closed, 'location', $month['anchor'] ); ?>
availability->overrides_for_staff( $staff_id, 80 );
$week = $this->schedule_week_from_request();
$week_days = $this->week_dates( $week );
$visible = $this->show_specific_schedule();
?>
>
render_schedule_week_picker( $week ); ?>
render_schedule_overrides_table( $overrides ); ?>
exceptions->for_staff( $staff_id );
?>
render_closed_days_calendar( $exceptions ); ?>
| | | | |
|
|
exception_time_label( $exception ) ); ?> |
|
|
> $exceptions Exceptions.
*/
private function render_closed_days_calendar( array $exceptions, string $scope = 'staff', array $booking_counts = array(), string $start_date = '', string $end_date = '', string $anchor_date = '' ): void {
$closed = $this->closed_date_map( $exceptions );
$label = 'location' === $scope ? __( 'Location closure days', 'abientot' ) : __( 'Staff time off days', 'abientot' );
if ( '' === $start_date || '' === $end_date ) {
$start_date = wp_date( 'Y-m-d' );
$end_date = wp_date( 'Y-m-d', strtotime( $start_date . ' +41 days' ) );
}
$anchor_month = preg_match( '/^\d{4}-\d{2}-\d{2}$/', $anchor_date ) ? substr( $anchor_date, 0, 7 ) : substr( $start_date, 0, 7 );
echo '';
foreach ( array_merge( array_slice( \Abientot\Support\Locale::date_names()['shortWeekdays'],\Abientot\Support\Locale::week_start() ),array_slice( \Abientot\Support\Locale::date_names()['shortWeekdays'],0,\Abientot\Support\Locale::week_start() ) ) as $weekday_label ) {
echo '' . esc_html( $weekday_label ) . '';
}
foreach ( $this->exception_dates( $start_date, $end_date ) as $date ) {
$booking_data = $booking_counts[ $date ] ?? array();
$count = is_array( $booking_data ) ? (int) ( $booking_data['count'] ?? 0 ) : (int) $booking_data;
$booking_ids = is_array( $booking_data ) ? array_map( 'absint', (array) ( $booking_data['ids'] ?? array() ) ) : array();
$classes = array();
if ( ! empty( $closed[ $date ] ) ) {
$classes[] = 'is-closed';
$classes[] = 'is-saved';
}
if ( substr( $date, 0, 7 ) !== $anchor_month ) {
$classes[] = 'is-outside-month';
}
printf(
'',
esc_attr( implode( ' ', $classes ) ),
esc_html( \Abientot\Support\Locale::date( 'j', strtotime( $date ), DateTimeHelper::business_timezone() ) ),
esc_html( \Abientot\Support\Locale::date( 'M', strtotime( $date ), DateTimeHelper::business_timezone() ) ),
esc_attr( $date ),
esc_attr( ! empty( $closed[ $date ] ) ? 'true' : 'false' ),
$count > 0 ? '' . esc_html( sprintf( /* translators: %d: number of bookings. */ _n( '%d booking', '%d bookings', $count, 'abientot' ), $count ) ) . '' : '',
esc_attr( implode( ',', array_filter( $booking_ids ) ) ),
esc_attr( ! empty( $closed[ $date ] ) ? '1' : '0' )
);
}
echo '
';
}
/**
* @param array> $exceptions Exceptions.
* @return array
*/
private function closed_date_map( array $exceptions ): array {
$closed = array();
foreach ( $exceptions as $exception ) {
if ( 'closed' === (string) $exception['exception_type'] && empty( $exception['start_time'] ) ) {
$closed[ (string) $exception['exception_date'] ] = true;
}
}
ksort( $closed );
return $closed;
}
/**
* @param array> $rows Booking rows.
*/
private function render_closure_conflicts_panel( array $rows, string $scope ): void {
if ( ! $rows ) {
return;
}
?>
| | | |
| local_booking_time_label( $row ) ); ?> |
|
|
|
> $overrides Override rows.
*/
private function render_schedule_overrides_table( array $overrides ): void {
if ( ! $overrides ) {
echo '' . esc_html__( 'No specific week schedules yet.', 'abientot' ) . '
';
return;
}
?>
| | | | |
|
weekdays()[ (int) $row['weekday'] ] ?? '' ); ?> |
|
time_value( (string) $row['start_time'] ) . ' - ' . $this->time_value( (string) $row['end_time'] ) ); ?> |
|
staff->default_staff();
if ( is_array( $staff ) ) {
return $staff;
}
$now = gmdate( 'Y-m-d H:i:s' );
$id = $this->staff->insert(
array(
'display_name' => __( 'Default Staff', 'abientot' ),
'timezone' => (string) Settings::values()['business_timezone'],
'is_default' => 1,
'status' => 'active',
'created_at' => $now,
'updated_at' => $now,
)
);
return $this->staff->find( $id ) ?: array(
'id' => $id,
'display_name' => __( 'Default Staff', 'abientot' ),
'status' => 'active'
);
}
private function default_location(): array {
$location = $this->locations->default_location();
if ( is_array( $location ) ) {
return $location;
}
$now = gmdate( 'Y-m-d H:i:s' );
$id = $this->locations->insert(
array(
'name' => __( 'Default Location', 'abientot' ),
'timezone' => (string) Settings::values()['business_timezone'],
'is_default' => 1,
'status' => 'active',
'created_at' => $now,
'updated_at' => $now,
)
);
return $this->locations->find( $id ) ?: array(
'id' => $id,
'name' => __( 'Default Location', 'abientot' ),
'status' => 'active'
);
}
private function link_all_services_to_default_staff(): void {
$staff = $this->default_staff();
foreach ( $this->services->list_for_admin() as $service ) {
$this->services->link_to_staff( (int) $service['id'], (int) $staff['id'] );
}
}
private function weekly_rule_map( int $staff_id ): array {
return ScheduleEditor::from_rules( $this->availability->weekly_rules_for_staff( $staff_id ) );
}
/**
* Returns the default location's recurring business hours. Existing sites inherit
* the staff schedule until location hours are saved explicitly.
*
* @return array>>
*/
private function location_weekly_rule_map(): array {
$saved = get_option( 'abientot_location_weekly_schedule', null );
if ( is_array( $saved ) ) {
return $saved;
}
$staff = $this->default_staff();
return $this->weekly_rule_map( (int) $staff['id'] );
}
/**
* @param array>> $staff_rules Staff schedule.
* @param array>> $location_rules Location schedule.
* @return array>>
*/
private function constrain_staff_rule_map( array $staff_rules, array $location_rules ): array {
return $staff_rules;
}
/**
* @return array>>
*/
private function location_schedule_from_post(): array {
return $this->posted_period_map( 'location_schedule' );
}
private function posted_period_map( string $name ): array {
try {
if ( ! $this->input()->has_list( $name ) ) {
throw new \InvalidArgumentException();
}
return ScheduleEditor::posted( $this->input()->text_list( $name ) );
} catch ( \InvalidArgumentException $error ) {
wp_die( esc_html__( 'Check working periods: use valid times, different start and end times, and no overlapping periods.', 'abientot' ), '', array( 'response' => 400 ) );
}
}
/**
* @return array>
*/
private function schedule_rules_from_post(): array {
return $this->period_rules_from_post( 'schedule', (int) $this->default_location()['id'] );
}
private function period_rules_from_post( string $name, int $location_id, ?string $from = null, ?string $to = null ): array {
$map = $this->posted_period_map( $name );
$rules = array();
foreach ( $map as $weekday => $entry ) {
if ( null !== $from && ! $entry['periods'] ) {
$rules[] = array(
'location_id' => $location_id,
'weekday' => $weekday,
'start_time' => '00:00:00',
'end_time' => '00:00:00',
'rule_type' => 'override_closed',
'effective_from' => $from,
'effective_to' => $to
);
}
foreach ( $entry['periods'] as $period ) {
$offset = (int) ( $period['day_offset'] ?? 0 );
$rules[] = array(
'location_id' => $location_id,
'weekday' => ( $weekday + $offset ) % 7,
'start_time' => $period['start_time'],
'end_time' => $period['end_time'],
'rule_type' => 'working',
'effective_from' => $from && $offset ? ( new \DateTimeImmutable( $from ) )->modify( '+1 day' )->format( 'Y-m-d' ) : $from,
'effective_to' => $to && $offset ? ( new \DateTimeImmutable( $to ) )->modify( '+1 day' )->format( 'Y-m-d' ) : $to
);
}
}
return $rules;
}
/**
* @param array>> $rules Schedule map.
*/
private function render_weekly_schedule_table( string $field_name, array $rules, bool $include_breaks = true ): void {
ScheduleEditor::render( $field_name, $rules, $this->weekdays() );
}
/**
* @return array>
*/
private function schedule_rules_from_post_for_range( string $start_date, string $end_date, int $location_id ): array {
return $this->period_rules_from_post( 'override_schedule', $location_id, $start_date, $end_date );
}
/**
* @param string[] $dates Local dates.
* @return array>
*/
private function closure_conflicts( string $scope, int $staff_id, int $location_id, array $dates ): array {
$conflicts = array();
foreach ( $dates as $date ) {
$window = $this->local_date_utc_window( $date );
if ( ! $window ) {
continue;
}
$rows = 'location' === $scope
? $this->appointments->blocking_for_location_between_admin( $location_id, $window['start_utc'], $window['end_utc'] )
: $this->appointments->blocking_for_staff_between_admin( $staff_id, $window['start_utc'], $window['end_utc'] );
foreach ( $rows as $row ) {
$conflicts[ (int) $row['id'] ] = $row;
}
}
return array_values( $conflicts );
}
/**
* @return array
*/
private function booking_conflicts_for_window( string $scope, int $staff_id, int $location_id, string $start_date, string $end_date ): array {
$dates = $this->exception_dates( $start_date, $end_date );
$rows = $this->closure_conflicts( $scope, $staff_id, $location_id, $dates );
$bookings = array();
foreach ( $rows as $row ) {
try {
$timezone = new DateTimeZone( (string) $row['timezone'] );
} catch ( Exception $exception ) {
$timezone = DateTimeHelper::business_timezone();
}
$start = new DateTimeImmutable( (string) $row['start_utc'], DateTimeHelper::utc_timezone() );
$date = $start->setTimezone( $timezone )->format( 'Y-m-d' );
if ( empty( $bookings[ $date ] ) ) {
$bookings[ $date ] = array(
'count' => 0,
'ids' => array(),
);
}
$bookings[ $date ]['count']++;
$bookings[ $date ]['ids'][] = (int) $row['id'];
}
return $bookings;
}
/**
* @return array{start_utc:string,end_utc:string}|null
*/
private function local_date_utc_window( string $date ): ?array {
if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ) {
return null;
}
try {
$start = new DateTimeImmutable( $date . ' 00:00:00', DateTimeHelper::business_timezone() );
$end = $start->modify( '+1 day' );
} catch ( Exception $exception ) {
return null;
}
return array(
'start_utc' => $start->setTimezone( DateTimeHelper::utc_timezone() )->format( 'Y-m-d H:i:s' ),
'end_utc' => $end->setTimezone( DateTimeHelper::utc_timezone() )->format( 'Y-m-d H:i:s' ),
);
}
/**
* @return array>
*/
private function conflicts_from_request( string $scope ): array {
$rows = array();
foreach ( RedirectNotice::ids( 'conflict_ids' ) as $id ) {
$row = $this->appointments->find_for_admin( $id );
if ( $row ) {
$rows[] = $row;
}
}
return $rows;
}
/**
* @param array> $conflicts Conflict booking rows.
*/
private function redirect_with_conflicts( string $page, string $notice, array $conflicts, array $extra_args = array() ): void {
$ids = array();
foreach ( $conflicts as $row ) {
$ids[] = (int) $row['id'];
}
wp_safe_redirect(
RedirectNotice::url(
admin_url( 'admin.php?page=abientot-' . $page ),
array_merge(
$extra_args,
array(
'abientot_notice' => $notice,
'conflict_ids' => implode( ',', array_slice( array_unique( $ids ), 0, 20 ) ),
)
)
)
);
exit;
}
/**
* @param array $row Booking row.
*/
private function local_booking_time_label( array $row ): string {
try {
$timezone = new DateTimeZone( (string) $row['timezone'] );
} catch ( Exception $exception ) {
$timezone = DateTimeHelper::business_timezone();
}
$start = new DateTimeImmutable( (string) $row['start_utc'], DateTimeHelper::utc_timezone() );
$end = new DateTimeImmutable( (string) $row['end_utc'], DateTimeHelper::utc_timezone() );
return DateTimeHelper::format_utc_datetime( (string) $row['start_utc'], $timezone->getName() ) . ' - ' . DateTimeHelper::format_utc_datetime( (string) $row['end_utc'], $timezone->getName(), DateTimeHelper::time_display_format() );
}
private function render_services_table( array $services ): void {
$status_labels = array(
'active' => __( 'Active', 'abientot' ),
'archived' => __( 'Archived', 'abientot' ),
'inactive' => __( 'Inactive', 'abientot' )
);
$visibility_labels = array(
'public' => __( 'Public', 'abientot' ),
'private' => __( 'Private', 'abientot' )
);
if ( ! $services ) {
echo '' . esc_html__( 'Create your first service to make it available for future booking forms.', 'abientot' ) . '
';
return;
}
?>
| | | | | |
|
|
|
format_money( (int) $row['price_cents'], (string) $row['currency'] ) ); ?> |
|
|
services->find( $service_id );
if ( ! $service ) {
return;
}
$count = $this->appointments->count_by_service( $service_id );
$appointments = $this->appointments->service_delete_impact( $service_id );
$replacements = array_values(
array_filter(
$services,
static function ( array $row ) use ( $service_id ): bool {
return (int) $row['id'] !== $service_id;
}
)
);
if ( $count <= 0 ) {
return;
}
?>
count( $appointments ) ) : ?>
|
|
text_post( 'phone' );
if ( '' === $phone || $phone === $previous ) {
return $phone;
}
try {
$country = $this->input()->text( 'phone_country' );
return \Abientot\Support\Phone::normalize( $phone, $country );
} catch ( \DomainException $error ) {
wp_die( esc_html__( 'Enter a valid phone number. Select its country or include the +country code.', 'abientot' ), '', array( 'response' => 400 ) );
}
}
private function input_row( string $name, string $label, string $value, string $type = 'text', bool $required = false, string $min = '', string $max = '', string $step = '', string $description = '' ): void {
if ( 'tel' === $type ) {
echo ' | ';
\Abientot\Support\PhoneField::render(
$name,
$value,
'phone_country',
array(
'id' => $name,
'required' => $required
),
$label
);
echo ' |
';
return;
}
?>
|
>
|
| |
| |
| |
$staff Default staff profile.
*/
private function service_staff_row( array $staff, ?array $service = null ): void {
if ( apply_filters( 'abientot_render_service_staff', false, $staff, $service ) ) {
return;
}
?>
|
|
|
media_field( $name, $attachment_id ); ?>
|
0 ? wp_get_attachment_image( $attachment_id, 'thumbnail', false, array( 'class' => 'abientot-media-preview-image' ) ) : '';
$input_name = '' === $input_name ? $name : $input_name;
?>
| |
__( 'Changes saved.', 'abientot' ),
'retained-team-bookings' => __( 'This service has retained team bookings. Use a compatible Pro edition to replace it.', 'abientot' ),
'deleted' => __( 'Item deleted.', 'abientot' ),
'category-saved' => __( 'Category saved.', 'abientot' ),
'category-order-saved' => __( 'Category order saved.', 'abientot' ),
'category-deleted' => __( 'Category deleted.', 'abientot' ),
'exception-saved' => __( 'Exception saved.', 'abientot' ),
'exception-deleted' => __( 'Exception deleted.', 'abientot' ),
'time-off-saved' => __( 'Calendar saved.', 'abientot' ),
'time-off-period-deleted' => __( 'Period deleted.', 'abientot' ),
'closure-conflict' => __( 'Closure was not saved because there are bookings on one or more selected days.', 'abientot' ),
'schedule-override-saved' => __( 'Schedule override saved.', 'abientot' ),
'schedule-override-deleted' => __( 'Schedule override deleted.', 'abientot' ),
'empty-override' => __( 'Choose at least one working day for the override.', 'abientot' ),
'service-in-use' => __( 'This service has bookings. Reassign the affected bookings before deleting it.', 'abientot' ),
'service-reassigned-deleted' => __( 'Bookings reassigned and service deleted.', 'abientot' ),
'invalid-replacement-service' => __( 'Choose a valid replacement service.', 'abientot' ),
'missing-name' => __( 'Name is required.', 'abientot' ),
'missing-category' => __( 'Category name is required.', 'abientot' ),
'invalid-date' => __( 'Enter a valid exception date.', 'abientot' ),
);
if ( isset( $map[ $notice ] ) ) {
$class = in_array( $notice, array( 'closure-conflict', 'invalid-date', 'empty-override', 'missing-name', 'missing-category', 'service-in-use', 'invalid-replacement-service' ), true ) ? 'notice-error' : 'notice-success';
echo '' . esc_html( $map[ $notice ] ) . '
';
}
}
/**
* Capability check and configuration lock, for handlers that verified their nonce first.
*/
private function authorize( string $capability ): void {
if ( ! current_user_can( $capability ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'abientot' ), '', array( 'response' => 403 ) );
}
BookingLock::require_configuration_lock();
}
/**
* Fields of the current form; only handlers set them, after verifying the nonce.
*/
private function input(): Input {
if ( null === $this->input ) {
wp_die( esc_html__( 'Invalid request.', 'abientot' ), '', array( 'response' => 400 ) );
}
return $this->input;
}
/** Array values that are not strings become empty strings. */
private function list_text( $value ): string {
return is_string( $value ) ? $value : '';
}
private function redirect( string $page, string $notice ): void {
wp_safe_redirect( RedirectNotice::url( admin_url( 'admin.php?page=abientot-' . $page ), array( 'abientot_notice' => $notice ) ) );
exit;
}
private function redirect_to_calendar_month( string $page, string $scope, string $month, string $notice ): void {
$key = 'location' === $scope ? 'location_time_off_month' : 'staff_time_off_month';
wp_safe_redirect(
RedirectNotice::url(
admin_url( 'admin.php?page=abientot-' . $page ),
array(
'abientot_notice' => $notice,
$key => $month,
)
)
);
exit;
}
private function redirect_to_schedule_week( string $week, string $notice ): void {
wp_safe_redirect(
RedirectNotice::url(
admin_url( 'admin.php?page=abientot-staff' ),
array(
'abientot_notice' => $notice,
'schedule_week' => $week,
'show_specific_schedule' => '1',
)
)
);
exit;
}
private function text_post( string $key ): string {
return $this->input()->text( $key );
}
private function textarea_post( string $key ): string {
return $this->input()->textarea( $key );
}
private function date_post( string $key ): string {
$date = $this->input()->text( $key );
return preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ? $date : '';
}
/**
* @return string[]
*/
private function dates_post( string $key, string $start_date, string $end_date ): array {
$value = $this->input()->text( $key );
$dates = array();
foreach ( explode( ',', $value ) as $date ) {
$date = trim( $date );
if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) && $date >= $start_date && $date <= $end_date ) {
$dates[ $date ] = true;
}
}
return array_keys( $dates );
}
private function int_post( string $key ): int {
return $this->input()->int( $key );
}
private function signed_int_post( string $key ): int {
return (int) $this->input()->text( $key );
}
private function nullable_absint_post( string $key ): ?int {
$value = $this->int_post( $key );
return $value > 0 ? $value : null;
}
private function attachment_id_post( string $key ): ?int {
$id = $this->nullable_absint_post( $key );
if ( null === $id ) {
return null;
}
return 'attachment' === get_post_type( $id ) ? $id : null;
}
private function price_cents_post( string $key ): int {
$value = $this->input()->text( $key, '0' );
try {
$cents = \Abientot\Support\MoneyInput::parse( $value,'USD' );
$id = $this->input()->int( 'service_id' );
$existing = $id ? $this->services->find( $id ) : null;
$currency = (string) Settings::values()['currency'];
if ( ! $existing || (int) $existing['price_cents'] !== $cents || $existing['currency'] !== $currency ) {
\Abientot\Support\Currency::validate( $cents,$currency );
}
return $cents;
} catch ( \InvalidArgumentException $error ) {
wp_die( esc_html__( 'Enter an exact price supported by the selected currency. Use whole amounts for zero-decimal currencies; other prices support increments of 0.01.','abientot' ),'',array('response' => 400) );
}
}
private function currency_post( string $key ): string {
$currency = strtoupper( $this->text_post( $key ) );
return preg_match( '/^[A-Z]{3}$/', $currency ) ? $currency : 'USD';
}
/**
* @return array
*/
private function timezone_options(): array {
$options = array();
foreach ( timezone_identifiers_list() as $timezone ) {
if ( false === strpos( $timezone, '/' ) ) {
continue;
}
$options[ $timezone ] = $this->timezone_label( $timezone );
}
asort( $options, SORT_NATURAL | SORT_FLAG_CASE );
return $options;
}
private function timezone_label( string $timezone ): string {
try {
$zone = new DateTimeZone( $timezone );
$now = new DateTimeImmutable( 'now', $zone );
$location = timezone_location_get( $zone );
$country = '';
if ( is_array( $location ) && ! empty( $location['country_code'] ) && class_exists( '\Locale' ) ) {
$country = (string) \Locale::getDisplayRegion( '-' . $location['country_code'], get_user_locale() );
}
if ( '' === $country ) {
$country = str_replace( '_', ' ', strtok( $timezone, '/' ) ?: $timezone );
}
$city = str_replace( '_', ' ', substr( strrchr( $timezone, '/' ) ?: $timezone, 1 ) );
$offset = $zone->getOffset( $now );
$sign = $offset >= 0 ? '+' : '-';
$offset = abs( $offset );
return sprintf( '%s (%s) - GMT%s%02d:%02d', $country, $city, $sign, floor( $offset / HOUR_IN_SECONDS ), floor( ( $offset % HOUR_IN_SECONDS ) / MINUTE_IN_SECONDS ) );
} catch ( Exception $exception ) {
return $timezone;
}
}
private function timezone_post( string $key ): string {
$timezone = $this->text_post( $key );
return in_array( $timezone, timezone_identifiers_list(), true ) ? $timezone : wp_timezone_string();
}
private function choice_post( string $key, array $choices, string $default ): string {
$value = $this->input()->key( $key, $default );
return in_array( $value, $choices, true ) ? $value : $default;
}
private function time_post( string $key ): ?string {
$value = $this->input()->has( $key ) ? $this->sanitize_time_value( $this->input()->text( $key ) ) : '';
return '' === $value ? null : $value . ':00';
}
private function sanitize_time_value( $value ): string {
$value = is_string( $value ) ? sanitize_text_field( $value ) : '';
return preg_match( '/^\d{2}:\d{2}$/', $value ) ? $value : '';
}
private function time_value( string $value ): string {
return substr( $value, 0, 5 );
}
private function unique_slug( string $name, $repository, int $current_id = 0 ): string {
$base = sanitize_title( $name ) ?: 'item';
$slug = $base;
$i = 2;
while ( true ) {
$existing = $repository->find_by_slug( $slug );
if ( ! $existing || ( $current_id > 0 && (int) $existing['id'] === $current_id ) ) {
return $slug;
}
$slug = $base . '-' . $i;
$i++;
}
}
private function format_price( int $cents ): string {
return number_format( $cents / 100, 2, '.', '' );
}
private function format_money( int $cents, string $currency ): string {
return \Abientot\Support\Currency::format( $cents,$currency );
}
private function exception_time_label( array $exception ): string {
if ( 'closed' === (string) $exception['exception_type'] ) {
return __( 'All day', 'abientot' );
}
return $this->time_value( (string) $exception['start_time'] ) . ' - ' . $this->time_value( (string) $exception['end_time'] );
}
/**
* @return array
*/
private function weekdays(): array {
$labels = array(
0 => __( 'Sunday', 'abientot' ),
1 => __( 'Monday', 'abientot' ),
2 => __( 'Tuesday', 'abientot' ),
3 => __( 'Wednesday', 'abientot' ),
4 => __( 'Thursday', 'abientot' ),
5 => __( 'Friday', 'abientot' ),
6 => __( 'Saturday', 'abientot' ),
);
$ordered = array();
$start = \Abientot\Support\Locale::week_start();
for ( $offset = 0; $offset < 7; $offset++ ) {
$weekday = ( $start + $offset ) % 7;
$ordered[ $weekday ] = $labels[ $weekday ];
}
return $ordered;
}
}