PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.3.0-beta.2
WooCommerce v10.3.0-beta.2
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Utilities / ArrayUtil.php
woocommerce / src / Utilities Last commit date
ArrayUtil.php 1 year ago DiscountsUtil.php 2 years ago FeaturesUtil.php 10 months ago I18nUtil.php 3 years ago LoggingUtil.php 1 year ago NumberUtil.php 10 months ago OrderUtil.php 8 months ago PluginUtil.php 7 months ago RestApiUtil.php 2 years ago ShippingUtil.php 1 year ago StringUtil.php 1 year ago TimeUtil.php 2 years ago
ArrayUtil.php
371 lines
1 <?php
2 /**
3 * A class of utilities for dealing with arrays.
4 */
5
6 declare( strict_types = 1 );
7 namespace Automattic\WooCommerce\Utilities;
8
9 /**
10 * A class of utilities for dealing with arrays.
11 */
12 class ArrayUtil {
13
14 /**
15 * Automatic selector type for the 'select' method.
16 */
17 public const SELECT_BY_AUTO = 0;
18
19 /**
20 * Object method selector type for the 'select' method.
21 */
22 public const SELECT_BY_OBJECT_METHOD = 1;
23
24 /**
25 * Object property selector type for the 'select' method.
26 */
27 public const SELECT_BY_OBJECT_PROPERTY = 2;
28
29 /**
30 * Array key selector type for the 'select' method.
31 */
32 public const SELECT_BY_ARRAY_KEY = 3;
33
34 /**
35 * Get a value from an nested array by specifying the entire key hierarchy with '::' as separator.
36 *
37 * E.g. for [ 'foo' => [ 'bar' => [ 'fizz' => 'buzz' ] ] ] the value for key 'foo::bar::fizz' would be 'buzz'.
38 *
39 * @param array $items The array to get the value from.
40 * @param string $key The complete key hierarchy, using '::' as separator.
41 * @param mixed $default_value The value to return if the key doesn't exist in the array.
42 *
43 * @return mixed The retrieved value, or the supplied default value.
44 * @throws \Exception $array is not an array.
45 */
46 public static function get_nested_value( array $items, string $key, $default_value = null ) {
47 $key_stack = explode( '::', $key );
48 $subkey = array_shift( $key_stack );
49
50 if ( isset( $items[ $subkey ] ) ) {
51 $value = $items[ $subkey ];
52
53 if ( count( $key_stack ) ) {
54 foreach ( $key_stack as $subkey ) {
55 if ( is_array( $value ) && isset( $value[ $subkey ] ) ) {
56 $value = $value[ $subkey ];
57 } else {
58 $value = $default_value;
59 break;
60 }
61 }
62 }
63 } else {
64 $value = $default_value;
65 }
66
67 return $value;
68 }
69
70 /**
71 * Checks if a given key exists in an array and its value can be evaluated as 'true'.
72 *
73 * @param array $items The array to check.
74 * @param string $key The key for the value to check.
75 * @return bool True if the key exists in the array and the value can be evaluated as 'true'.
76 */
77 public static function is_truthy( array $items, string $key ) {
78 return isset( $items[ $key ] ) && $items[ $key ];
79 }
80
81 /**
82 * Gets the value for a given key from an array, or a default value if the key doesn't exist in the array.
83 *
84 * This is equivalent to "$array[$key] ?? $default" except in one case:
85 * when they key exists, has a null value, and a non-null default is supplied:
86 *
87 * $array = ['key' => null]
88 * $array['key'] ?? 'default' => 'default'
89 * ArrayUtil::get_value_or_default($array, 'key', 'default') => null
90 *
91 * @param array $items The array to get the value from.
92 * @param string $key The key to use to retrieve the value.
93 * @param null $default_value The default value to return if the key doesn't exist in the array.
94 * @return mixed|null The value for the key, or the default value passed.
95 */
96 public static function get_value_or_default( array $items, string $key, $default_value = null ) {
97 return array_key_exists( $key, $items ) ? $items[ $key ] : $default_value;
98 }
99
100 /**
101 * Converts an array of numbers to a human-readable range, such as "1,2,3,5" to "1-3, 5". It also supports
102 * floating point numbers, however with some perhaps unexpected / undefined behaviour if used within a range.
103 * Source: https://stackoverflow.com/a/34254663/4574
104 *
105 * @param array $items An array (in any order, see $sort) of individual numbers.
106 * @param string $item_separator The string that separates sequential range groups. Defaults to ', '.
107 * @param string $range_separator The string that separates ranges. Defaults to '-'. A plausible example otherwise would be ' to '.
108 * @param bool|true $sort Sort the array prior to iterating? You'll likely always want to sort, but if not, you can set this to false.
109 *
110 * @return string
111 */
112 public static function to_ranges_string( array $items, string $item_separator = ', ', string $range_separator = '-', bool $sort = true ): string {
113 if ( $sort ) {
114 sort( $items );
115 }
116
117 $point = null;
118 $range = false;
119 $str = '';
120
121 foreach ( $items as $i ) {
122 if ( null === $point ) {
123 $str .= $i;
124 } elseif ( ( $point + 1 ) === $i ) {
125 $range = true;
126 } else {
127 if ( $range ) {
128 $str .= $range_separator . $point;
129 $range = false;
130 }
131 $str .= $item_separator . $i;
132 }
133 $point = $i;
134 }
135
136 if ( $range ) {
137 $str .= $range_separator . $point;
138 }
139
140 return $str;
141 }
142
143 /**
144 * Helper function to generate a callback which can be executed on an array to select a value from each item.
145 *
146 * @param string $selector_name Field/property/method name to select.
147 * @param int $selector_type Selector type.
148 *
149 * @return \Closure Callback to select the value.
150 */
151 private static function get_selector_callback( string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): \Closure {
152 if ( self::SELECT_BY_OBJECT_METHOD === $selector_type ) {
153 $callback = function ( $item ) use ( $selector_name ) {
154 return $item->$selector_name();
155 };
156 } elseif ( self::SELECT_BY_OBJECT_PROPERTY === $selector_type ) {
157 $callback = function ( $item ) use ( $selector_name ) {
158 return $item->$selector_name;
159 };
160 } elseif ( self::SELECT_BY_ARRAY_KEY === $selector_type ) {
161 $callback = function ( $item ) use ( $selector_name ) {
162 return $item[ $selector_name ];
163 };
164 } else {
165 $callback = function ( $item ) use ( $selector_name ) {
166 if ( is_array( $item ) ) {
167 return $item[ $selector_name ];
168 } elseif ( method_exists( $item, $selector_name ) ) {
169 return $item->$selector_name();
170 } else {
171 return $item->$selector_name;
172 }
173 };
174 }
175 return $callback;
176 }
177
178 /**
179 * Select one single value from all the items in an array of either arrays or objects based on a selector.
180 * For arrays, the selector is a key name; for objects, the selector can be either a method name or a property name.
181 *
182 * @param array $items Items to apply the selection to.
183 * @param string $selector_name Key, method or property name to use as a selector.
184 * @param int $selector_type Selector type, one of the SELECT_BY_* constants.
185 * @return array The selected values.
186 */
187 public static function select( array $items, string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): array {
188 $callback = self::get_selector_callback( $selector_name, $selector_type );
189 return array_map( $callback, $items );
190 }
191
192 /**
193 * Returns a new assoc array with format [ $key1 => $item1, $key2 => $item2, ... ] where $key is the value of the selector and items are original items passed.
194 *
195 * @param array $items Items to use for conversion.
196 * @param string $selector_name Key, method or property name to use as a selector.
197 * @param int $selector_type Selector type, one of the SELECT_BY_* constants.
198 *
199 * @return array The converted assoc array.
200 */
201 public static function select_as_assoc( array $items, string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): array {
202 $selector_callback = self::get_selector_callback( $selector_name, $selector_type );
203 $result = array();
204 foreach ( $items as $item ) {
205 $key = $selector_callback( $item );
206 self::ensure_key_is_array( $result, $key );
207 $result[ $key ][] = $item;
208 }
209 return $result;
210 }
211
212 /**
213 * Returns whether two assoc array are same. The comparison is done recursively by keys, and the functions returns on first difference found.
214 *
215 * @param array $array1 First array to compare.
216 * @param array $array2 Second array to compare.
217 * @param bool $strict Whether to use strict comparison.
218 *
219 * @return bool Whether the arrays are different.
220 */
221 public static function deep_compare_array_diff( array $array1, array $array2, bool $strict = true ) {
222 return self::deep_compute_or_compare_array_diff( $array1, $array2, true, $strict );
223 }
224
225 /**
226 * Computes difference between two assoc arrays recursively. Similar to PHP's native assoc_array_diff, but also supports nested arrays.
227 *
228 * @param array $array1 First array.
229 * @param array $array2 Second array.
230 * @param bool $strict Whether to also match type of values.
231 *
232 * @return array The difference between the two arrays.
233 */
234 public static function deep_assoc_array_diff( array $array1, array $array2, bool $strict = true ): array {
235 return self::deep_compute_or_compare_array_diff( $array1, $array2, false, $strict );
236 }
237
238 /**
239 * Helper method to compare to compute difference between two arrays. Comparison is done recursively.
240 *
241 * @param array $array1 First array.
242 * @param array $array2 Second array.
243 * @param bool $compare Whether to compare the arrays. If true, then function will return false on first difference, in order to be slightly more efficient.
244 * @param bool $strict Whether to do string comparison.
245 *
246 * @return array|bool The difference between the two arrays, or if array are same, depending upon $compare param.
247 */
248 private static function deep_compute_or_compare_array_diff( array $array1, array $array2, bool $compare, bool $strict = true ) {
249 $diff = array();
250 foreach ( $array1 as $key => $value ) {
251 if ( is_array( $value ) ) {
252 if ( ! array_key_exists( $key, $array2 ) || ! is_array( $array2[ $key ] ) ) {
253 if ( $compare ) {
254 return true;
255 }
256 $diff[ $key ] = $value;
257 continue;
258 }
259 $new_diff = self::deep_assoc_array_diff( $value, $array2[ $key ], $strict );
260 if ( ! empty( $new_diff ) ) {
261 if ( $compare ) {
262 return true;
263 }
264 $diff[ $key ] = $new_diff;
265 }
266 } elseif ( $strict ) {
267 if ( ! array_key_exists( $key, $array2 ) || $value !== $array2[ $key ] ) {
268 if ( $compare ) {
269 return true;
270 }
271 $diff[ $key ] = $value;
272 }
273 // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual -- Intentional when $strict is false.
274 } elseif ( ! array_key_exists( $key, $array2 ) || $value != $array2[ $key ] ) {
275 if ( $compare ) {
276 return true;
277 }
278 $diff[ $key ] = $value;
279 }
280 }
281
282 return $compare ? false : $diff;
283 }
284
285 /**
286 * Push a value to an array, but only if the value isn't in the array already.
287 *
288 * @param array $items The array.
289 * @param mixed $value The value to maybe push.
290 * @return bool True if the value has been added to the array, false if the value was already in the array.
291 */
292 public static function push_once( array &$items, $value ): bool {
293 if ( in_array( $value, $items, true ) ) {
294 return false;
295 }
296
297 $items[] = $value;
298 return true;
299 }
300
301 /**
302 * Ensure that an associative array has a given key, and if not, set the key to an empty array.
303 *
304 * @param array $items The array to check.
305 * @param string $key The key to check.
306 * @param bool $throw_if_existing_is_not_array If true, an exception will be thrown if the key already exists in the array but the value is not an array.
307 * @return bool True if the key has been added to the array, false if not (the key already existed).
308 * @throws \Exception The key already exists in the array but the value is not an array.
309 */
310 public static function ensure_key_is_array( array &$items, string $key, bool $throw_if_existing_is_not_array = false ): bool {
311 if ( ! isset( $items[ $key ] ) ) {
312 $items[ $key ] = array();
313 return true;
314 }
315
316 if ( $throw_if_existing_is_not_array && ! is_array( $items[ $key ] ) ) {
317 $type = is_object( $items[ $key ] ) ? get_class( $items[ $key ] ) : gettype( $items[ $key ] );
318 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
319 throw new \Exception( "Array key exists but it's not an array, it's a {$type}" );
320 }
321
322 return false;
323 }
324
325 /**
326 * Given an array of associative arrays, all having a shared key name ("column"), generates a new array in which
327 * keys are the distinct column values found, and values are arrays with all the matches found
328 * (or only the last matching array found, if $single_values is true).
329 * See ArrayUtilTest for examples.
330 *
331 * @param array $items The array to process.
332 * @param string $column The name of the key to group by.
333 * @param bool $single_values True to only return the last suitable array found for each column value.
334 * @return array The grouped array.
335 */
336 public static function group_by_column( array $items, string $column, bool $single_values = false ): array {
337 if ( $single_values ) {
338 return array_combine( array_column( $items, $column ), array_values( $items ) );
339 }
340
341 $distinct_column_values = array_unique( array_column( $items, $column ), SORT_REGULAR );
342 $result = array_fill_keys( $distinct_column_values, array() );
343
344 foreach ( $items as $value ) {
345 $result[ $value[ $column ] ][] = $value;
346 }
347
348 return $result;
349 }
350
351 /**
352 * Check if all items in an array pass a callback.
353 *
354 * @param array $items The array to check.
355 * @param callable $callback The callback to check each item.
356 *
357 * @return bool true if all items pass the callback, false otherwise.
358 */
359 public static function array_all( array $items, callable $callback ): bool {
360 if ( function_exists( 'array_all' ) ) {
361 return array_all( $items, $callback );
362 }
363 foreach ( $items as $item ) {
364 if ( ! $callback( $item ) ) {
365 return false;
366 }
367 }
368 return true;
369 }
370 }
371