PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.9.15
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.9.15
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
woocommerce-pos / includes / Services / Opening_Hours_Formatter.php

Opening_Hours_Formatter.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.9.15, at includes/Services/Opening_Hours_Formatter.php

190 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Opening hours formatter service.
4 *
5 * Converts the structured opening hours array into human-readable strings
6 * in three formats: compact (grouped), vertical (one day per line), and
7 * inline (single comma-separated line).
8 *
9 * @package WCPOS\WooCommercePOS\Services
10 */
11
12 namespace WCPOS\WooCommercePOS\Services;
13
14 /**
15 * Opening_Hours_Formatter class.
16 */
17 class Opening_Hours_Formatter {
18
19 /**
20 * Day keys in order (Monday=0 through Sunday=6).
21 */
22 private const DAY_KEYS = array( 0, 1, 2, 3, 4, 5, 6 );
23
24 /**
25 * Format as vertical list — one day per line, newline-separated.
26 *
27 * @param array $hours Structured hours array (keys 0–6).
28 * @return string Newline-separated string.
29 */
30 public static function format_vertical( array $hours ): string {
31 $lines = array();
32 foreach ( self::DAY_KEYS as $day ) {
33 $day_name = self::get_day_name( $day );
34 $slots = isset( $hours[ (string) $day ] ) ? $hours[ (string) $day ] : array();
35 $formatted = self::format_slots( $slots );
36 $lines[] = $day_name . ' ' . $formatted;
37 }
38
39 return implode( "\n", $lines );
40 }
41
42 /**
43 * Format as compact grouped — consecutive days with identical hours are ranged.
44 *
45 * @param array $hours Structured hours array (keys 0–6).
46 * @return string Newline-separated string.
47 */
48 public static function format_compact( array $hours ): string {
49 $groups = self::group_consecutive_days( $hours );
50 $lines = array();
51
52 foreach ( $groups as $group ) {
53 $day_label = self::format_day_range( $group['start'], $group['end'] );
54 $lines[] = $day_label . ' ' . $group['formatted'];
55 }
56
57 return implode( "\n", $lines );
58 }
59
60 /**
61 * Format as inline — single comma-separated line using compact grouping.
62 *
63 * @param array $hours Structured hours array (keys 0–6).
64 * @return string Single line string.
65 */
66 public static function format_inline( array $hours ): string {
67 $groups = self::group_consecutive_days( $hours );
68 $parts = array();
69
70 foreach ( $groups as $group ) {
71 $day_label = self::format_day_range( $group['start'], $group['end'] );
72 $parts[] = $day_label . ' ' . $group['formatted'];
73 }
74
75 return implode( ', ', $parts );
76 }
77
78 /**
79 * Group consecutive days that share identical time slots.
80 *
81 * @param array $hours Structured hours array.
82 * @return array Array of groups, each with 'start', 'end', 'formatted'.
83 */
84 private static function group_consecutive_days( array $hours ): array {
85 $groups = array();
86 $current = null;
87
88 foreach ( self::DAY_KEYS as $day ) {
89 $slots = isset( $hours[ (string) $day ] ) ? $hours[ (string) $day ] : array();
90 $formatted = self::format_slots( $slots );
91
92 if ( null === $current || $current['formatted'] !== $formatted ) {
93 if ( null !== $current ) {
94 $groups[] = $current;
95 }
96 $current = array(
97 'start' => $day,
98 'end' => $day,
99 'formatted' => $formatted,
100 );
101 } else {
102 $current['end'] = $day;
103 }
104 }
105
106 if ( null !== $current ) {
107 $groups[] = $current;
108 }
109
110 return $groups;
111 }
112
113 /**
114 * Format a day range label.
115 *
116 * @param int $start Start day index (0–6).
117 * @param int $end End day index (0–6).
118 * @return string
119 */
120 private static function format_day_range( int $start, int $end ): string {
121 if ( $start === $end ) {
122 return self::get_day_name( $start );
123 }
124
125 return self::get_day_name( $start ) . "\u{2013}" . self::get_day_name( $end );
126 }
127
128 /**
129 * Format time slots for a single day.
130 *
131 * @param array $slots Flat array of time pairs.
132 * @return string
133 */
134 private static function format_slots( array $slots ): string {
135 if ( empty( $slots ) ) {
136 return /* translators: Short WCPOS UI label; keep concise. */ __( 'Closed', 'woocommerce-pos' );
137 }
138
139 // Drop trailing unpaired element to ensure open/close pairs.
140 if ( count( $slots ) % 2 !== 0 ) {
141 array_pop( $slots );
142 }
143
144 if ( empty( $slots ) ) {
145 return /* translators: Short WCPOS UI label; keep concise. */ __( 'Closed', 'woocommerce-pos' );
146 }
147
148 $ranges = array();
149 $slot_count = count( $slots );
150 for ( $i = 0; $i < $slot_count - 1; $i += 2 ) {
151 $open = self::format_time( $slots[ $i ] );
152 $close = self::format_time( $slots[ $i + 1 ] );
153 $ranges[] = $open . " \u{2013} " . $close;
154 }
155
156 return implode( ', ', $ranges );
157 }
158
159 /**
160 * Format a time string according to WP time_format option.
161 *
162 * @param string $time Time in H:i format (e.g. "09:00").
163 * @return string Formatted time (e.g. "9:00 AM" or "09:00").
164 */
165 private static function format_time( string $time ): string {
166 $timestamp = strtotime( '2000-01-01 ' . $time );
167
168 if ( false === $timestamp ) {
169 return $time;
170 }
171
172 $time_format = get_option( 'time_format', 'g:i A' );
173
174 return date_i18n( $time_format, $timestamp );
175 }
176
177 /**
178 * Get the localized short day name.
179 *
180 * @param int $day Day index (0=Monday, 6=Sunday).
181 * @return string Short day name (e.g. "Mon", "Tue").
182 */
183 private static function get_day_name( int $day ): string {
184 // 2024-01-01 is a Monday. Offset by $day to get the right weekday.
185 $timestamp = strtotime( '2024-01-01 +' . $day . ' days' );
186
187 return date_i18n( 'D', $timestamp );
188 }
189 }
190