PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / trunk
WCPOS – Point of Sale (POS) plugin for WooCommerce vtrunk
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 1.9.13 1.9.12 1.9.11 1.9.10 1.9.9 All 158 releases
woocommerce-pos / includes / Storefront_Receipts.php

Storefront_Receipts.php in WCPOS – Point of Sale (POS) plugin for WooCommerce trunk, at includes/Storefront_Receipts.php

205 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Storefront receipt links.
4 *
5 * @package WCPOS\WooCommercePOS
6 */
7
8 namespace WCPOS\WooCommercePOS;
9
10 use WC_Abstract_Order;
11
12 /**
13 * Registers storefront receipt links and order actions.
14 */
15 class Storefront_Receipts {
16 /**
17 * Register storefront hooks.
18 */
19 public function __construct() {
20 add_shortcode( 'wcpos_receipt', array( $this, 'receipt_shortcode' ) );
21
22 if ( ! woocommerce_pos_request() ) {
23 add_filter( 'woocommerce_my_account_my_orders_actions', array( $this, 'add_my_account_action' ), 10, 2 );
24 }
25 }
26
27 /**
28 * Render a receipt link.
29 *
30 * @param array|string $attributes Shortcode attributes.
31 *
32 * @return string Receipt link or an empty string when no permitted order is available.
33 */
34 public function receipt_shortcode( $attributes ): string {
35 $attributes = shortcode_atts(
36 array(
37 'order_id' => '',
38 'link_text' => __( 'Download receipt (PDF)', 'woocommerce-pos' ),
39 'format' => 'pdf',
40 'template' => '',
41 'id' => '',
42 'class' => 'wcpos-receipt-link',
43 ),
44 $attributes,
45 'wcpos_receipt'
46 );
47
48 $explicit_order_id = '' !== trim( (string) $attributes['order_id'] );
49 if ( $explicit_order_id ) {
50 $order_id = absint( $attributes['order_id'] );
51 if ( ! $this->can_view_order( $order_id ) ) {
52 return '';
53 }
54
55 $order = wc_get_order( $order_id );
56 } else {
57 $order = $this->get_context_order();
58 }
59
60 if ( ! $order ) {
61 return '';
62 }
63
64 $format = 'html' === sanitize_key( (string) $attributes['format'] ) ? 'html' : 'pdf';
65 $template = sanitize_text_field( (string) $attributes['template'] );
66 $url = self::get_receipt_url( $order, $format, $template );
67 $id = '' !== (string) $attributes['id'] ? ' id="' . esc_attr( (string) $attributes['id'] ) . '"' : '';
68
69 return sprintf(
70 '<a href="%1$s"%2$s class="%3$s">%4$s</a>',
71 esc_url( $url ),
72 $id,
73 esc_attr( (string) $attributes['class'] ),
74 esc_html( (string) $attributes['link_text'] )
75 );
76 }
77
78 /**
79 * Add the receipt download to My Account order actions.
80 *
81 * @param array<string,array<string,string>> $actions Existing order actions.
82 * @param WC_Abstract_Order $order Order object.
83 *
84 * @return array<string,array<string,string>> Filtered order actions.
85 */
86 public function add_my_account_action( array $actions, WC_Abstract_Order $order ): array {
87 /*
88 * Filters whether the My Account receipt button is enabled.
89 *
90 * Defaults to the `storefront_receipt_enabled` general setting (opt-in,
91 * off by default). The filter still allows programmatic overrides,
92 * including per-order decisions via the $order argument.
93 *
94 * @param bool $enabled Whether the button is enabled.
95 * @param WC_Abstract_Order $order Order object.
96 *
97 * @returns bool Whether the button is enabled.
98 *
99 * @since 1.9.11
100 *
101 * @hook woocommerce_pos_storefront_receipt_my_account_button
102 */
103 $default_enabled = wp_validate_boolean( woocommerce_pos_get_settings( 'general', 'storefront_receipt_enabled' ) );
104 $enabled = (bool) apply_filters( 'woocommerce_pos_storefront_receipt_my_account_button', $default_enabled, $order );
105 if ( ! $enabled || null === Templates::get_active_template_id( 'receipt' ) ) {
106 return $actions;
107 }
108
109 /*
110 * Filters the order statuses that expose a storefront receipt.
111 *
112 * @param string[] $statuses Eligible order statuses.
113 * @param WC_Abstract_Order $order Order object.
114 *
115 * @returns string[] Eligible order statuses.
116 *
117 * @since 1.9.11
118 *
119 * @hook woocommerce_pos_storefront_receipt_order_statuses
120 */
121 $statuses = (array) apply_filters(
122 'woocommerce_pos_storefront_receipt_order_statuses',
123 array( 'processing', 'completed', 'refunded' ),
124 $order
125 );
126 if ( ! $order->has_status( $statuses ) ) {
127 return $actions;
128 }
129
130 // An empty template means "use the active receipt template". A configured
131 // value is passed through the existing, already-validated ?template= path
132 // (published receipt templates only); an invalid value simply falls back
133 // to the active template when the receipt renders.
134 $template = sanitize_text_field( (string) woocommerce_pos_get_settings( 'general', 'storefront_receipt_template' ) );
135
136 $actions['wcpos-receipt'] = array(
137 'url' => self::get_receipt_url( $order, 'pdf', $template ),
138 'name' => __( 'Receipt', 'woocommerce-pos' ),
139 /* translators: %s: order number. */
140 'aria-label' => sprintf( __( 'Download receipt for order #%s', 'woocommerce-pos' ), $order->get_order_number() ),
141 );
142
143 return $actions;
144 }
145
146 /**
147 * Check whether the current user may view an order.
148 *
149 * @param int $order_id Order ID.
150 * @return bool
151 */
152 private function can_view_order( int $order_id ): bool {
153 return 0 < $order_id && is_user_logged_in() && current_user_can( 'view_order', $order_id );
154 }
155
156 /**
157 * Resolve an order from a supported WooCommerce page context.
158 *
159 * @return WC_Abstract_Order|null Context order or null.
160 */
161 private function get_context_order(): ?WC_Abstract_Order {
162 if ( is_order_received_page() ) {
163 $order = wc_get_order( absint( get_query_var( 'order-received' ) ) );
164 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
165 $key = isset( $_GET['key'] ) ? sanitize_text_field( wp_unslash( $_GET['key'] ) ) : '';
166
167 return $order && '' !== $key && hash_equals( $order->get_order_key(), $key ) ? $order : null;
168 }
169
170 if ( is_account_page() && is_wc_endpoint_url( 'view-order' ) ) {
171 $order_id = absint( get_query_var( 'view-order' ) );
172 if ( $this->can_view_order( $order_id ) ) {
173 $order = wc_get_order( $order_id );
174
175 return $order ? $order : null;
176 }
177 }
178
179 return null;
180 }
181
182 /**
183 * Build a key-gated receipt URL.
184 *
185 * @param WC_Abstract_Order $order Order object.
186 * @param string $format Receipt format.
187 * @param string $template Optional template ID.
188 *
189 * @return string Receipt URL.
190 */
191 private static function get_receipt_url( WC_Abstract_Order $order, string $format = 'pdf', string $template = '' ): string {
192 $args = array( 'key' => $order->get_order_key() );
193
194 if ( 'pdf' === $format ) {
195 $args['format'] = 'pdf';
196 }
197
198 if ( '' !== $template ) {
199 $args['template'] = $template;
200 }
201
202 return add_query_arg( $args, wcpos_checkout_url( 'wcpos-receipt/' . $order->get_id() ) );
203 }
204 }
205