PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.17
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.17
1.10.20 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 All 164 releases
woocommerce-pos / includes / Templates / Renderers / Thermal_Html_Renderer.php

Thermal_Html_Renderer.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.17, at includes/Templates/Renderers/Thermal_Html_Renderer.php

111 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Thermal HTML receipt renderer.
4 *
5 * Renders a thermal (receipt-printer) template to HTML for the browser print
6 * surface. Thermal template content is stored raw — it is exempt from wp_kses
7 * because it is XML markup for printers, not HTML — so it must NEVER be executed
8 * as PHP. This renderer runs the content through the thermal pipeline
9 * (Mustache render -> XML AST -> HTML), which escapes receipt data and discards
10 * anything that is not recognised thermal markup (PHP processing instructions
11 * included). The include-based Legacy_Php_Renderer must never receive thermal
12 * content.
13 *
14 * @package WCPOS\WooCommercePOS\Templates\Renderers
15 */
16
17 namespace WCPOS\WooCommercePOS\Templates\Renderers;
18
19 use WCPOS\WooCommercePOS\Interfaces\Receipt_Renderer_Interface;
20 use WCPOS\WooCommercePOS\Logger;
21 use WCPOS\WooCommercePOS\Templates\Thermal\Html_Thermal_Emitter;
22 use WCPOS\WooCommercePOS\Templates\Thermal\Thermal_Renderer;
23 use WC_Abstract_Order;
24
25 /**
26 * Thermal_Html_Renderer class.
27 */
28 class Thermal_Html_Renderer implements Receipt_Renderer_Interface {
29 /**
30 * Render a thermal template to HTML.
31 *
32 * @param array $template Template metadata/content.
33 * @param WC_Abstract_Order|null $order Order object, or null for sample-data preview.
34 * @param array $receipt_data Canonical receipt payload (unused; the thermal pipeline rebuilds its own data).
35 */
36 public function render( array $template, ?WC_Abstract_Order $order, array $receipt_data ): void {
37 // The thermal pipeline builds its receipt data from a concrete order.
38 if ( ! $order instanceof WC_Abstract_Order ) {
39 echo '<!-- Thermal receipt preview requires an order -->';
40 return;
41 }
42
43 $paper_width_px = $this->paper_width_px( $template );
44
45 try {
46 $ast = ( new Thermal_Renderer() )->build_ast( $template, $order );
47 $html = ( new Html_Thermal_Emitter() )->emit(
48 $ast,
49 array( 'paper_width_px' => $paper_width_px )
50 );
51 } catch ( \Throwable $e ) {
52 // Malformed thermal markup (e.g. a raw PHP payload with no <receipt>
53 // root) throws during parsing. Fail closed with a harmless comment,
54 // but log the cause so a genuinely broken template is diagnosable.
55 Logger::log(
56 sprintf(
57 'Thermal receipt render failed for template %s: %s',
58 isset( $template['id'] ) ? (string) $template['id'] : 'unknown',
59 $e->getMessage()
60 )
61 );
62 echo '<!-- Thermal receipt could not be rendered -->';
63 return;
64 }
65
66 // The emitter leaves its output width-agnostic (the PDF path constrains it
67 // via the physical page size). On the browser-print surface the page can be
68 // wider than the roll, so constrain to the resolved paper width here or the
69 // row tables would stretch across the whole page.
70 $open = '<div style="width:' . esc_attr( $this->format_px( $paper_width_px ) )
71 . 'px;max-width:100%;margin:0 auto;">';
72
73 // $html is built by the thermal emitter, which escapes receipt data; $open
74 // is a fixed wrapper with an escaped numeric width.
75 echo $open . $html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
76 }
77
78 /**
79 * Format a pixel value for inline CSS without a trailing decimal point.
80 *
81 * @param float $px Pixel value.
82 *
83 * @return string
84 */
85 private function format_px( float $px ): string {
86 return rtrim( rtrim( number_format( $px, 2, '.', '' ), '0' ), '.' );
87 }
88
89 /**
90 * Resolve the template's paper width in CSS pixels (96dpi).
91 *
92 * Template metadata declares the physical roll ('58mm' / '80mm'); fall back
93 * to 80mm when absent or out of range so the emitter can scale the character
94 * grid to fit the page.
95 *
96 * @param array $template Template metadata/content.
97 *
98 * @return float Paper width in CSS px.
99 */
100 private function paper_width_px( array $template ): float {
101 $raw = isset( $template['paper_width'] ) ? (string) $template['paper_width'] : '';
102 $mm = (float) $raw; // Leading-number cast: '58mm' -> 58.0.
103
104 if ( $mm < 25.0 || $mm > 250.0 ) {
105 $mm = 80.0;
106 }
107
108 return round( $mm * 96 / 25.4, 2 );
109 }
110 }
111