array( array( 'start_time' => $rule['start_time'], 'end_time' => $rule['end_time'] ) ) ) )[0]; if ( 'break' === $rule['rule_type'] ) { $breaks[] = $period; } else { $working[] = $period; } } usort( $working, static fn( $a, $b )=>$a['start'] <=> $b['start'] ); $merged = array(); foreach ( $working as $window ) { $key = array_key_last( $merged ); if ( null === $key || $merged[ $key ]['end'] <= $window['start'] ) { $merged[] = $window; } else { $merged[ $key ]['end'] = max( $merged[ $key ]['end'], $window['end'] ); } } $working = $merged; foreach ( $breaks as $break ) { foreach ( $working as $window ) { if ( $window['end'] > 86400 && $break['start'] < $window['start'] && $break['end'] + 86400 <= $window['end'] ) { $break['start'] += 86400; $break['end'] += 86400; break; } } $working = ScheduleIntervals::subtract( $working, $break ); } $periods = array(); foreach ( $working as $window ) { // An overlapping legacy union can reach a full day: use unequal endpoints. while ( $window['end'] - $window['start'] >= 86400 ) { $end = $window['start'] + 43200; $periods[] = self::offset_period( $window['start'], $end ); $window['start'] = $end; } $periods[] = self::offset_period( $window['start'], $window['end'] ); } $out[ $day ] = array( 'periods' => $periods ); } return $out; } private static function offset_period( int $start, int $end ): array { return array( 'start_time' => sprintf( '%02d:%02d:00', intdiv( $start % 86400, 3600 ), intdiv( $start % 3600, 60 ) ), 'end_time' => sprintf( '%02d:%02d:00', intdiv( $end % 86400, 3600 ), intdiv( $end % 3600, 60 ) ), 'day_offset' => intdiv( $start, 86400 ) ); } public static function posted( array $schedule ): array { foreach ( array_keys( $schedule ) as $key ) { if ( ! preg_match( '/^[0-6]$/D', (string) $key ) ) { throw new \InvalidArgumentException( 'Invalid weekday.' ); } } $out = array(); foreach ( range( 0, 6 ) as $day ) { $row = $schedule[ $day ] ?? array(); if ( ! is_array( $row ) ) { throw new \InvalidArgumentException( 'Invalid schedule.' ); } $out[ $day ] = self::posted_day( $row ); } return $out; } public static function posted_day( array $row ): array { if ( array_key_exists( 'periods', $row ) || isset( $row['periods_present'] ) ) { if ( isset( $row['enabled_present'] ) && empty( $row['enabled'] ) ) { return array( 'periods' => array() ); } return ScheduleIntervals::normalize_entry( array( 'periods' => $row['periods'] ?? array() ) ); } $enabled = $row['enabled'] ?? $row['working_enabled'] ?? null; if ( empty( $enabled ) ) { return array( 'periods' => array() ); } $entry = array( 'working' => array( 'start_time' => $row['start'] ?? $row['working_start'] ?? '', 'end_time' => $row['end'] ?? $row['working_end'] ?? '' ) ); if ( ! empty( $row['break_enabled'] ) ) { $entry['break'] = array( 'start_time' => $row['break_start'] ?? '', 'end_time' => $row['break_end'] ?? '' ); } return ScheduleIntervals::normalize_entry( $entry ); } public static function render( string $name, array $schedule, ?array $labels = null ): void { if ( null === $labels ) { $labels = array(); foreach ( \Abientot\Support\Locale::weekday_order() as $day ) { $labels[ $day ] = \Abientot\Support\Locale::date( 'l', strtotime( '2024-01-07 +' . $day . ' days UTC' ), new \DateTimeZone( 'UTC' ) ); } } echo '
'; echo '

' . esc_html__( 'Add working periods. Gaps are breaks. An end earlier than its start is on the next day.', 'abientot' ) . '

'; foreach ( $labels as $day => $label ) { $entry = ScheduleIntervals::normalize_entry( $schedule[ $day ] ?? array() ); echo '
' . esc_html( $label ) . ''; self::day( $name . '[' . $day . ']', $entry, $label, true ); echo '
'; } echo '
'; } public static function day( string $name, array $entry, string $label, bool $copy = false ): void { $entry = ScheduleIntervals::normalize_entry( $entry ); echo '
'; foreach ( $entry['periods'] as $index => $period ) { self::row( $name, (string) $index, $period, $label ); } echo '
'; if ( $copy ) { echo ''; } echo '
'; } private static function row( string $name, string $index, array $period, string $label ): void { echo '
'; foreach ( array( 'start_time' => __( 'Start', 'abientot' ), 'end_time' => __( 'End', 'abientot' ) ) as $key => $title ) { echo ''; } echo '' . esc_html__( 'This period starts on the next day.', 'abientot' ) . '' . esc_html__( 'Next day', 'abientot' ) . '
'; } }