PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 4.5.0
WooCommerce Square v4.5.0
5.5.0 5.4.3 5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / Framework / Square_Helper.php
woocommerce-square / includes / Framework Last commit date
Addresses 3 years ago Api 3 years ago Compatibility 2 years ago PaymentGateway 2 years ago Utilities 3 years ago Admin_Message_Handler.php 3 years ago Admin_Notice_Handler.php 3 years ago Lifecycle.php 3 years ago Plugin.php 3 years ago Plugin_Compatibility.php 3 years ago Plugin_Dependencies.php 3 years ago Square_Helper.php 3 years ago
Square_Helper.php
416 lines
1 <?php
2
3 namespace WooCommerce\Square\Framework;
4
5 use WooCommerce\Square\Framework\Plugin_Compatibility;
6
7 defined( 'ABSPATH' ) || exit;
8
9 /**
10 * Square Helper Class
11 *
12 * The purpose of this class is to centralize common utility functions.
13 *
14 * @since 3.0.0
15 */
16 class Square_Helper {
17
18
19 /** encoding used for mb_*() string functions */
20 const MB_ENCODING = 'UTF-8';
21
22
23 /** String manipulation functions (all multi-byte safe) ***************/
24
25 /**
26 * Returns true if the haystack string starts with needle
27 *
28 * Note: case-sensitive
29 *
30 * @since 3.0.0
31 * @param string $haystack
32 * @param string $needle
33 * @return bool
34 */
35 public static function str_starts_with( $haystack, $needle ) {
36
37 if ( self::multibyte_loaded() ) {
38
39 if ( '' === $needle ) {
40 return true;
41 }
42
43 return 0 === mb_strpos( $haystack, $needle, 0, self::MB_ENCODING );
44
45 } else {
46
47 $needle = self::str_to_ascii( $needle );
48
49 if ( '' === $needle ) {
50 return true;
51 }
52
53 return 0 === strpos( self::str_to_ascii( $haystack ), self::str_to_ascii( $needle ) );
54 }
55 }
56
57 /**
58 * Returns true if the needle exists in haystack
59 *
60 * Note: case-sensitive
61 *
62 * @since 3.0.0
63 * @param string $haystack
64 * @param string $needle
65 * @return bool
66 */
67 public static function str_exists( $haystack, $needle ) {
68
69 if ( self::multibyte_loaded() ) {
70
71 if ( '' === $needle ) {
72 return false;
73 }
74
75 return false !== mb_strpos( $haystack, $needle, 0, self::MB_ENCODING );
76
77 } else {
78
79 $needle = self::str_to_ascii( $needle );
80
81 if ( '' === $needle ) {
82 return false;
83 }
84
85 return false !== strpos( self::str_to_ascii( $haystack ), self::str_to_ascii( $needle ) );
86 }
87 }
88
89 /**
90 * Returns a string with all non-ASCII characters removed. This is useful
91 * for any string functions that expect only ASCII chars and can't
92 * safely handle UTF-8. Note this only allows ASCII chars in the range
93 * 33-126 (newlines/carriage returns are stripped)
94 *
95 * @since 3.0.0
96 * @param string $string string to make ASCII
97 * @return string
98 */
99 public static function str_to_ascii( $string ) {
100
101 // strip ASCII chars 32 and under
102 $string = filter_var( $string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW );
103
104 // strip ASCII chars 127 and higher
105 return filter_var( $string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH );
106 }
107
108 /**
109 * Truncates a given $string after a given $length if string is longer than
110 * $length. The last characters will be replaced with the $omission string
111 * for a total length not exceeding $length
112 *
113 * @since 3.0.0
114 * @param string $string text to truncate
115 * @param int $length total desired length of string, including omission
116 * @param string $omission omission text, defaults to '...'
117 * @return string
118 */
119 public static function str_truncate( $string, $length, $omission = '...' ) {
120
121 if ( self::multibyte_loaded() ) {
122
123 // bail if string doesn't need to be truncated
124 if ( mb_strlen( $string, self::MB_ENCODING ) <= $length ) {
125 return $string;
126 }
127
128 $length -= mb_strlen( $omission, self::MB_ENCODING );
129
130 return mb_substr( $string, 0, $length, self::MB_ENCODING ) . $omission;
131
132 } else {
133
134 $string = self::str_to_ascii( $string );
135
136 // bail if string doesn't need to be truncated
137 if ( strlen( $string ) <= $length ) {
138 return $string;
139 }
140
141 $length -= strlen( $omission );
142
143 return substr( $string, 0, $length ) . $omission;
144 }
145 }
146
147 /**
148 * Helper method to check if the multibyte extension is loaded, which
149 * indicates it's safe to use the mb_*() string methods
150 *
151 * @since 3.0.0
152 * @return bool
153 */
154 protected static function multibyte_loaded() {
155
156 return extension_loaded( 'mbstring' );
157 }
158
159
160 /** Array functions ***************************************************/
161
162
163 /**
164 * Insert the given element after the given key in the array
165 *
166 * Sample usage:
167 *
168 * given
169 *
170 * array( 'item_1' => 'foo', 'item_2' => 'bar' )
171 *
172 * array_insert_after( $array, 'item_1', array( 'item_1.5' => 'w00t' ) )
173 *
174 * becomes
175 *
176 * array( 'item_1' => 'foo', 'item_1.5' => 'w00t', 'item_2' => 'bar' )
177 *
178 * @since 3.0.0
179 * @param array $array array to insert the given element into
180 * @param string $insert_key key to insert given element after
181 * @param array $element element to insert into array
182 * @return array
183 */
184 public static function array_insert_after( array $array, $insert_key, array $element ) {
185
186 $new_array = array();
187
188 foreach ( $array as $key => $value ) {
189
190 $new_array[ $key ] = $value;
191
192 if ( $insert_key === $key ) {
193
194 foreach ( $element as $k => $v ) {
195 $new_array[ $k ] = $v;
196 }
197 }
198 }
199
200 return $new_array;
201 }
202
203 /**
204 * Lists an array as text.
205 *
206 * Takes an array and returns a list like "one, two, three, and four"
207 * with a (mandatory) oxford comma.
208 *
209 * @since 3.0.0
210 *
211 * @param array $items items to list
212 * @param string|null $conjunction coordinating conjunction, like "or" or "and"
213 * @param string $separator list separator, like a comma
214 * @return string
215 */
216 public static function list_array_items( array $items, $conjunction = null, $separator = '' ) {
217
218 if ( ! is_string( $conjunction ) ) {
219 $conjunction = _x( 'and', 'coordinating conjunction for a list of items: a, b, and c', 'woocommerce-square' );
220 }
221
222 // append the conjunction to the last item
223 if ( count( $items ) > 1 ) {
224
225 $last_item = array_pop( $items );
226
227 array_push( $items, trim( "{$conjunction} {$last_item}" ) );
228
229 // only use a comma if needed and no separator was passed
230 if ( count( $items ) < 3 ) {
231 $separator = ' ';
232 } elseif ( ! is_string( $separator ) || '' === $separator ) {
233 $separator = ', ';
234 }
235 }
236
237 return implode( $separator, $items );
238 }
239
240
241 /** Number helper functions *******************************************/
242
243
244 /**
245 * Format a number with 2 decimal points, using a period for the decimal
246 * separator and no thousands separator.
247 *
248 * Commonly used for payment gateways which require amounts in this format.
249 *
250 * @since 3.0.0
251 * @param float $number
252 * @return string
253 */
254 public static function number_format( $number ) {
255
256 return number_format( (float) $number, 2, '.', '' );
257 }
258
259 /**
260 * Determines if an order contains only virtual products.
261 *
262 * @since 3.0.0
263 * @param \WC_Order $order the order object
264 * @return bool
265 */
266 public static function is_order_virtual( \WC_Order $order ) {
267
268 $is_virtual = true;
269
270 foreach ( $order->get_items() as $item ) {
271 $product = $item->get_product();
272
273 // once we've found one non-virtual product we know we're done, break out of the loop
274 if ( $product && ! $product->is_virtual() ) {
275 $is_virtual = false;
276 break;
277 }
278 }
279
280 return $is_virtual;
281 }
282
283
284 /**
285 * Safely get sanitized data from $_POST
286 *
287 * @since 3.0.0
288 * @param string $key Array key to get from $_POST array.
289 * @param string $sanitize_callback Name of the sanitization callback function.
290 *
291 * @return string value from $_POST or blank string if $_POST[ $key ] is not set
292 */
293 public static function get_post( $key = '', $sanitize_callback = 'sanitize_text_field' ) {
294 if ( ! is_callable( $sanitize_callback ) ) {
295 $sanitize_callback = 'sanitize_text_field';
296 }
297
298 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
299 return isset( $_POST[ $key ] ) ? call_user_func( $sanitize_callback, wp_unslash( $_POST[ $key ] ) ) : '';
300 }
301
302
303 /**
304 * Safely get and trim data from $_REQUEST
305 *
306 * @since 3.0.0
307 * @param string $key Array key to get from $_REQUEST array.
308 * @param string $sanitize_callback Name of the sanitization callback function.
309 *
310 * @return string value from $_REQUEST or blank string if $_REQUEST[ $key ] is not set
311 */
312 public static function get_request( $key, $sanitize_callback = 'sanitize_text_field' ) {
313
314 if ( ! is_callable( $sanitize_callback ) ) {
315 $sanitize_callback = 'sanitize_text_field';
316 }
317
318 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
319 return isset( $_REQUEST[ $key ] ) ? call_user_func( $sanitize_callback, wp_unslash( $_REQUEST[ $key ] ) ) : '';
320 }
321
322 /**
323 * Add and store a notice.
324 *
325 * WC notice functions are not available in the admin
326 *
327 * @since 3.0.0
328 * @param string $message The text to display in the notice.
329 * @param string $notice_type The singular name of the notice type - either error, success or notice. [optional]
330 */
331 public static function wc_add_notice( $message, $notice_type = 'success' ) {
332
333 if ( function_exists( 'wc_add_notice' ) ) {
334 wc_add_notice( $message, $notice_type );
335 }
336 }
337
338 /**
339 * Gets the full URL to the log file for a given $handle
340 *
341 * @since 3.0.0
342 * @param string $handle log handle
343 * @return string URL to the WC log file identified by $handle
344 */
345 public static function get_wc_log_file_url( $handle ) {
346 return admin_url( sprintf( 'admin.php?page=wc-status&tab=logs&log_file=%s-%s-log', $handle, sanitize_file_name( wp_hash( $handle ) ) ) );
347 }
348
349
350 /**
351 * Gets the current WordPress site name.
352 *
353 * This is helpful for retrieving the actual site name instead of the
354 * network name on multisite installations.
355 *
356 * @since 3.0.0
357 * @return string
358 */
359 public static function get_site_name() {
360 return ( is_multisite() ) ? get_blog_details()->blogname : get_bloginfo( 'name' );
361 }
362
363 /**
364 * Displays a notice if the provided hook has not yet run.
365 *
366 * @since 3.0.0
367 *
368 * @param string $hook action hook to check
369 * @param string $method method/function name
370 * @param string $version version the notice was added
371 */
372 public static function maybe_doing_it_early( $hook, $method, $version ) {
373
374 if ( ! did_action( $hook ) ) {
375 Plugin_Compatibility::wc_doing_it_wrong( $method, "This should only be called after '{$hook}'", $version );
376 }
377 }
378
379 /**
380 * Triggers a PHP error.
381 *
382 * This wrapper method ensures AJAX isn't broken in the process.
383 *
384 * @since 3.0.0
385 * @param string $message the error message
386 * @param int $type Optional. The error type. Defaults to E_USER_NOTICE
387 */
388 public static function trigger_error( $message, $type = E_USER_NOTICE ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
389 wc_deprecated_function( __METHOD__, '3.9.0' );
390
391 if ( wp_doing_ajax() ) {
392
393 switch ( $type ) {
394
395 case E_USER_NOTICE:
396 $prefix = 'Notice: ';
397 break;
398
399 case E_USER_WARNING:
400 $prefix = 'Warning: ';
401 break;
402
403 default:
404 $prefix = '';
405 }
406
407 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
408 error_log( $prefix . $message );
409
410 } else {
411 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
412 trigger_error( $message, $type );
413 }
414 }
415 }
416