PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.0
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.0
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 / wcpos-functions.php

wcpos-functions.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.0, at includes/wcpos-functions.php

618 lines 18.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Global helper functions for WCPOS.
4 *
5 * @author Paul Kilmurray <paul@kilbot.com>
6 *
7 * @see http://wcpos.com
8 * @package WCPOS\WooCommercePOS
9 */
10
11 use WCPOS\WooCommercePOS\Admin\Permalink;
12 use WCPOS\WooCommercePOS\Logger;
13 use WCPOS\WooCommercePOS\Services\Settings;
14 use WCPOS\WooCommercePOS\Template_Router;
15 use const WCPOS\WooCommercePOS\PLUGIN_PATH;
16 use const WCPOS\WooCommercePOS\SHORT_NAME;
17 use const WCPOS\WooCommercePOS\VERSION;
18
19 /*
20 * ============================================================================
21 * WCPOS Functions
22 * ============================================================================
23 *
24 * Primary functions using the wcpos_ prefix.
25 */
26
27 /*
28 * getallheaders() is an alias of apache_response_headers()
29 * This function provides compatibility for nginx servers
30 */
31 if ( ! \function_exists( 'getallheaders' ) ) {
32 /**
33 * Polyfill for getallheaders() on nginx servers.
34 *
35 * @return array The request headers.
36 */
37 function getallheaders(): array { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- polyfill for missing PHP function.
38 $headers = array();
39 foreach ( $_SERVER as $name => $value ) {
40 // RFC2616 (HTTP/1.1) defines header fields as case-insensitive entities.
41 if ( 'http_' == strtolower( substr( $name, 0, 5 ) ) ) {
42 $headers[ str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $name, 5 ) ) ) ) ) ] = $value;
43 }
44 }
45
46 return $headers;
47 }
48 }
49
50 /*
51 * Resolve the URL scheme for POS permalinks.
52 *
53 * @return string|null 'https' when force_ssl is enabled, null for the home scheme.
54 */
55 if ( ! \function_exists( 'wcpos_url_scheme' ) ) {
56 /**
57 * Resolve the URL scheme for POS permalinks.
58 *
59 * See Settings::url_scheme() for the policy.
60 *
61 * @return string|null 'https' when force_ssl is enabled, null for the home scheme.
62 */
63 function wcpos_url_scheme(): ?string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
64 return Settings::instance()->url_scheme();
65 }
66 }
67
68 /*
69 * Construct the POS permalink.
70 *
71 * @param string $page Page slug.
72 * @return string POS URL.
73 */
74 if ( ! \function_exists( 'wcpos_url' ) ) {
75 /**
76 * Construct the POS permalink.
77 *
78 * The trailing slash follows the site's permalink structure, via
79 * user_trailingslashit().
80 *
81 * @param string $page Page slug.
82 *
83 * @return string POS URL.
84 */
85 function wcpos_url( $page = '' ): string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
86 $slug = Permalink::get_slug();
87
88 return home_url( user_trailingslashit( $slug . '/' . $page ), wcpos_url_scheme() );
89 }
90 }
91
92 /*
93 * Construct a POS checkout permalink.
94 *
95 * @param string $path Path relative to the wcpos-checkout endpoint.
96 * @return string POS checkout URL.
97 */
98 if ( ! \function_exists( 'wcpos_checkout_url' ) ) {
99 /**
100 * Construct a POS checkout permalink.
101 *
102 * Respects the force_ssl setting, like wcpos_url(), so checkout and receipt
103 * links work when the site home URL is http but the POS is served over https,
104 * eg: behind an SSL-terminating proxy.
105 *
106 * Like home_url(), this performs no encoding — pass trusted path segments
107 * only and escape the result on output.
108 *
109 * The trailing slash follows the site's permalink structure, via
110 * user_trailingslashit(). Slash-less URLs can trip origin rewrite rules
111 * that force a trailing slash — some redirect to a hardcoded http://
112 * target, which the browser then blocks as mixed content. The slash is
113 * appended to the end of the string, so $path must not contain a query
114 * string or fragment; append query args to the returned URL instead.
115 *
116 * @param string $path Path relative to the wcpos-checkout endpoint, eg: 'order-pay/123'.
117 *
118 * @return string POS checkout URL.
119 */
120 function wcpos_checkout_url( $path = '' ): string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
121 $full_path = Template_Router::CHECKOUT_PATH . '/' . ltrim( $path, '/' );
122
123 return home_url( user_trailingslashit( $full_path ), wcpos_url_scheme() );
124 }
125 }
126
127 /*
128 * Test for POS requests to the server.
129 *
130 * @param string $type Request type: 'query_var', 'header', or 'all'.
131 * @return bool Whether this is a POS request.
132 */
133 if ( ! \function_exists( 'wcpos_request' ) ) {
134 /**
135 * Test for POS requests to the server.
136 *
137 * Core's rest_api_loaded() reads this query var, which remains the original
138 * outer route during internal re-dispatches; this behavior is load-bearing.
139 *
140 * @param string $type Request type: 'query_var', 'header', 'rest_route', or 'all'.
141 *
142 * @return bool Whether this is a POS request.
143 */
144 function wcpos_request( $type = 'all' ): bool { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
145 // check query_vars, eg: ?wcpos=1 or /pos rewrite rule.
146 if ( 'all' == $type || 'query_var' == $type ) {
147 global $wp;
148 if ( 1 == isset( $wp->query_vars[ SHORT_NAME ] ) && $wp->query_vars[ SHORT_NAME ] ) {
149 return true;
150 }
151 }
152
153 // check headers, eg: from ajax request.
154 if ( 'all' == $type || 'header' == $type ) {
155 $headers = array_change_key_case( getallheaders() ); // convert headers to lowercase.
156 if ( 1 == isset( $headers[ 'x-' . SHORT_NAME ] ) && $headers[ 'x-' . SHORT_NAME ] ) {
157 return true;
158 }
159 }
160
161 if ( ( 'all' == $type || 'rest_route' == $type ) && isset( $GLOBALS['wp']->query_vars['rest_route'] ) ) {
162 $route = '/' . ltrim( (string) $GLOBALS['wp']->query_vars['rest_route'], '/' );
163 return 1 === preg_match( '#^/' . preg_quote( SHORT_NAME, '#' ) . '/v\d+(?:/|$)#', $route );
164 }
165
166 return false;
167 }
168 }
169
170 /*
171 * Check for POS admin requests.
172 *
173 * @return mixed Admin request header value or false.
174 */
175 if ( ! \function_exists( 'wcpos_admin_request' ) ) {
176 /**
177 * Check for POS admin requests.
178 *
179 * @return mixed Admin request header value or false.
180 */
181 function wcpos_admin_request() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
182 if ( \function_exists( 'getallheaders' ) ) {
183 $headers = getallheaders();
184 if ( $headers && isset( $headers['X-WC-POS-ADMIN'] ) ) {
185 return $headers['X-WC-POS-ADMIN'];
186 }
187 }
188 if ( isset( $_SERVER['HTTP_X_woocommerce_pos_ADMIN'] ) ) {
189 return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_woocommerce_pos_ADMIN'] ) );
190 }
191
192 return false;
193 }
194 }
195
196 /*
197 * Helper function to get WCPOS settings.
198 *
199 * @param string $id Settings ID.
200 * @param string $key Optional settings key.
201 * @return mixed Settings value.
202 */
203 if ( ! \function_exists( 'wcpos_get_settings' ) ) {
204 /**
205 * Helper function to get WCPOS settings.
206 *
207 * @param string $id Settings ID.
208 * @param string $key Optional settings key.
209 *
210 * @return mixed Settings value.
211 */
212 function wcpos_get_settings( $id, $key = null ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
213 $settings_service = Settings::instance();
214
215 return $settings_service->get_settings( $id, $key );
216 }
217 }
218
219 /*
220 * Get the site UUID (Plugin State), generating and persisting it on first use.
221 *
222 * @return string Site UUID.
223 */
224 if ( ! \function_exists( 'wcpos_get_site_uuid' ) ) {
225 /**
226 * Get the site UUID, generating and persisting it on first use.
227 *
228 * Single owner for the woocommerce_pos_uuid option — the
229 * generate-if-missing logic previously lived in three places (REST index,
230 * POS frontend, analytics) and could race.
231 *
232 * @return string Site UUID.
233 */
234 function wcpos_get_site_uuid(): string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
235 $uuid = get_option( 'woocommerce_pos_uuid', '' );
236 if ( \is_string( $uuid ) && '' !== $uuid ) {
237 return $uuid;
238 }
239
240 $uuid = \Ramsey\Uuid\Uuid::uuid4()->toString();
241
242 // add_option() is a no-op when the option already exists, so a
243 // concurrent request that won the race keeps its value.
244 if ( ! add_option( 'woocommerce_pos_uuid', $uuid ) ) {
245 $existing = get_option( 'woocommerce_pos_uuid', '' );
246 if ( \is_string( $existing ) && '' !== $existing ) {
247 return $existing;
248 }
249 update_option( 'woocommerce_pos_uuid', $uuid );
250 }
251
252 return $uuid;
253 }
254 }
255
256 /*
257 * Simple wrapper for json_encode.
258 *
259 * Use JSON_FORCE_OBJECT for PHP 5.3 or higher with fallback for
260 * PHP less than 5.3.
261 *
262 * @param mixed $data Data to encode.
263 * @return string|false JSON string or false on failure.
264 */
265 if ( ! \function_exists( 'wcpos_json_encode' ) ) {
266 /**
267 * Simple wrapper for json_encode with JSON_FORCE_OBJECT.
268 *
269 * @param mixed $data Data to encode.
270 *
271 * @return string|false JSON string or false on failure.
272 */
273 function wcpos_json_encode( $data ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
274 $args = array( $data, JSON_FORCE_OBJECT );
275
276 return \call_user_func_array( 'json_encode', $args );
277 }
278 }
279
280 /*
281 * Return template path for a given template.
282 *
283 * @param string $template Template name.
284 * @return string|null Template path or null if not found.
285 */
286 if ( ! \function_exists( 'wcpos_locate_template' ) ) {
287 /**
288 * Return template path for a given template.
289 *
290 * @param string $template Template name.
291 *
292 * @return string|null Template path or null if not found.
293 */
294 function wcpos_locate_template( $template = '' ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
295 // check theme directory first.
296 $path = locate_template(
297 array(
298 'woocommerce-pos/' . $template,
299 )
300 );
301
302 // if not, use plugin template.
303 if ( ! $path ) {
304 $path = PLUGIN_PATH . 'templates/' . $template;
305 }
306
307 /**
308 * Filters the template path.
309 *
310 * @hook woocommerce_pos_locate_template
311 *
312 * @since 1.0.0
313 *
314 * @param string $path The full path to the template.
315 * @param string $template The template name, eg: 'receipt.php'.
316 *
317 * @return string $path The full path to the template.
318 */
319 $filtered_path = apply_filters( 'woocommerce_pos_locate_template', $path, $template ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- legacy hook name.
320
321 // Check if the filtered template file exists.
322 if ( file_exists( $filtered_path ) ) {
323 return $filtered_path;
324 }
325
326 // Echo a message or handle the error as needed if the file path does not exist.
327 echo "The template file '" . esc_html( $filtered_path ) . "' does not exist.";
328
329 return null;
330 }
331 }
332
333 /*
334 * Remove newlines and code spacing.
335 *
336 * @param string $str HTML string to trim.
337 * @return string Trimmed string.
338 */
339 if ( ! \function_exists( 'wcpos_trim_html_string' ) ) {
340 /**
341 * Remove newlines and code spacing from an HTML string.
342 *
343 * @param string $str HTML string to trim.
344 *
345 * @return string Trimmed string.
346 */
347 function wcpos_trim_html_string( $str ): string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
348 return preg_replace( '/^\s+|\n|\r|\s+$/m', '', $str );
349 }
350 }
351
352 /*
353 * Get documentation URL.
354 *
355 * @param string $page Documentation page.
356 * @return string Documentation URL.
357 */
358 if ( ! \function_exists( 'wcpos_doc_url' ) ) {
359 /**
360 * Get documentation URL.
361 *
362 * @param string $page Documentation page.
363 *
364 * @return string Documentation URL.
365 */
366 function wcpos_doc_url( $page ): string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
367 return 'http://docs.wcpos.com/v/' . VERSION . '/en/' . $page;
368 }
369 }
370
371 /*
372 * Get FAQ URL.
373 *
374 * @param string $page FAQ page.
375 * @return string FAQ URL.
376 */
377 if ( ! \function_exists( 'wcpos_faq_url' ) ) {
378 /**
379 * Get FAQ URL.
380 *
381 * @param string $page FAQ page.
382 *
383 * @return string FAQ URL.
384 */
385 function wcpos_faq_url( $page ): string { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
386 return 'http://faq.wcpos.com/v/' . VERSION . '/en/' . $page;
387 }
388 }
389
390 /*
391 * Helper function to check whether an order is a POS order.
392 *
393 * @param \WC_Order|int $order Order object or ID.
394 * @return bool Whether the order is a POS order.
395 */
396 if ( ! \function_exists( 'wcpos_is_pos_order' ) ) {
397 /**
398 * Helper function to check whether an order is a POS order.
399 *
400 * @param \WC_Order|int $order Order object or ID.
401 *
402 * @return bool Whether the order is a POS order.
403 */
404 function wcpos_is_pos_order( $order ): bool { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
405 // Handle various input types and edge cases.
406 if ( ! $order instanceof WC_Order ) {
407 // Sometimes the order is passed as an ID.
408 if ( is_numeric( $order ) ) {
409 $order = wc_get_order( $order );
410 }
411
412 // If we still don't have a valid order, return false.
413 if ( ! $order instanceof WC_Order ) {
414 return false;
415 }
416 }
417
418 $legacy = $order->get_meta( '_pos', true );
419 $created_via = $order->get_created_via();
420
421 return 'woocommerce-pos' === $created_via || '1' === $legacy;
422 }
423 }
424
425 /*
426 * Get a default WooCommerce template.
427 *
428 * @param string $template_name Template name.
429 * @param array $args Arguments.
430 */
431 if ( ! \function_exists( 'wcpos_get_woocommerce_template' ) ) {
432 /**
433 * Get a default WooCommerce template.
434 *
435 * @param string $template_name Template name.
436 * @param array $args Arguments.
437 */
438 function wcpos_get_woocommerce_template( $template_name, $args = array() ): void { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- uses wcpos_ prefix.
439 $plugin_path = WC()->plugin_path();
440 $template = trailingslashit( $plugin_path . '/templates' ) . $template_name;
441
442 /**
443 * Filter the default WooCommerce template path.
444 *
445 * @param string $template Template path.
446 * @param string $template_name Template name.
447 * @param array $args Arguments.
448 */
449 $template = apply_filters( 'wcpos_locate_woocommerce_template', $template, $template_name, $args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- uses wcpos_ prefix.
450
451 if ( ! file_exists( $template ) ) {
452 Logger::log( \sprintf( 'WooCommerce default template not found: %s', $template ) );
453
454 return;
455 }
456
457 if ( $args && \is_array( $args ) ) {
458 extract( $args ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
459 }
460
461 include $template;
462 }
463 }
464
465 /*
466 * ============================================================================
467 * Legacy Aliases
468 * ============================================================================
469 *
470 * These functions use the old woocommerce_pos_ prefix.
471 * They are kept for backwards compatibility but new code should use wcpos_ prefix.
472 *
473 * @deprecated Use wcpos_* functions instead.
474 */
475
476 if ( ! \function_exists( 'woocommerce_pos_url' ) ) {
477 /**
478 * Legacy alias for wcpos_url().
479 *
480 * @deprecated Use wcpos_url() instead.
481 *
482 * @param mixed $page The page slug.
483 */
484 function woocommerce_pos_url( $page = '' ): string {
485 return wcpos_url( $page );
486 }
487 }
488
489 if ( ! \function_exists( 'woocommerce_pos_request' ) ) {
490 /**
491 * Legacy alias for wcpos_request().
492 *
493 * @deprecated Use wcpos_request() instead.
494 *
495 * @param mixed $type The request type.
496 */
497 function woocommerce_pos_request( $type = 'all' ): bool {
498 return wcpos_request( $type );
499 }
500 }
501
502 if ( ! \function_exists( 'woocommerce_pos_admin_request' ) ) {
503 /**
504 * Legacy alias for wcpos_admin_request().
505 *
506 * @deprecated Use wcpos_admin_request() instead.
507 */
508 function woocommerce_pos_admin_request() {
509 return wcpos_admin_request();
510 }
511 }
512
513 if ( ! \function_exists( 'woocommerce_pos_get_settings' ) ) {
514 /**
515 * Legacy alias for wcpos_get_settings().
516 *
517 * @deprecated Use wcpos_get_settings() instead.
518 *
519 * @param mixed $id The settings ID.
520 * @param null|mixed $key The settings key.
521 */
522 function woocommerce_pos_get_settings( $id, $key = null ) {
523 return wcpos_get_settings( $id, $key );
524 }
525 }
526
527 if ( ! \function_exists( 'woocommerce_pos_get_anon_id' ) ) {
528 /**
529 * Returns the anonymous analytics id (wcpos_anon_id), creating it on first use.
530 *
531 * Supported accessor for the Pro plugin's licence-activation request and the
532 * wcpos.com purchase reconciler join (landing-experiments spec §5.3c).
533 *
534 * @return string v4 UUID.
535 */
536 function woocommerce_pos_get_anon_id(): string {
537 return ( new \WCPOS\WooCommercePOS\Services\Anon_ID() )->get();
538 }
539 }
540
541 if ( ! \function_exists( 'woocommerce_pos_json_encode' ) ) {
542 /**
543 * Legacy alias for wcpos_json_encode().
544 *
545 * @deprecated Use wcpos_json_encode() instead.
546 *
547 * @param mixed $data The data to encode.
548 */
549 function woocommerce_pos_json_encode( $data ) {
550 return wcpos_json_encode( $data );
551 }
552 }
553
554 if ( ! \function_exists( 'woocommerce_pos_locate_template' ) ) {
555 /**
556 * Legacy alias for wcpos_locate_template().
557 *
558 * @deprecated Use wcpos_locate_template() instead.
559 *
560 * @param mixed $template The template name.
561 */
562 function woocommerce_pos_locate_template( $template = '' ) {
563 return wcpos_locate_template( $template );
564 }
565 }
566
567 if ( ! \function_exists( 'woocommerce_pos_trim_html_string' ) ) {
568 /**
569 * Legacy alias for wcpos_trim_html_string().
570 *
571 * @deprecated Use wcpos_trim_html_string() instead.
572 *
573 * @param mixed $str The HTML string.
574 */
575 function woocommerce_pos_trim_html_string( $str ): string {
576 return wcpos_trim_html_string( $str );
577 }
578 }
579
580 if ( ! \function_exists( 'woocommerce_pos_doc_url' ) ) {
581 /**
582 * Legacy alias for wcpos_doc_url().
583 *
584 * @deprecated Use wcpos_doc_url() instead.
585 *
586 * @param mixed $page The documentation page.
587 */
588 function woocommerce_pos_doc_url( $page ): string {
589 return wcpos_doc_url( $page );
590 }
591 }
592
593 if ( ! \function_exists( 'woocommerce_pos_faq_url' ) ) {
594 /**
595 * Legacy alias for wcpos_faq_url().
596 *
597 * @deprecated Use wcpos_faq_url() instead.
598 *
599 * @param mixed $page The FAQ page.
600 */
601 function woocommerce_pos_faq_url( $page ): string {
602 return wcpos_faq_url( $page );
603 }
604 }
605
606 if ( ! \function_exists( 'woocommerce_pos_is_pos_order' ) ) {
607 /**
608 * Legacy alias for wcpos_is_pos_order().
609 *
610 * @deprecated Use wcpos_is_pos_order() instead.
611 *
612 * @param mixed $order The order object or ID.
613 */
614 function woocommerce_pos_is_pos_order( $order ): bool {
615 return wcpos_is_pos_order( $order );
616 }
617 }
618