'', 'link_text' => __( 'Download receipt (PDF)', 'woocommerce-pos' ), 'format' => 'pdf', 'template' => '', 'id' => '', 'class' => 'wcpos-receipt-link', ), $attributes, 'wcpos_receipt' ); $explicit_order_id = '' !== trim( (string) $attributes['order_id'] ); if ( $explicit_order_id ) { $order_id = absint( $attributes['order_id'] ); if ( ! $this->can_view_order( $order_id ) ) { return ''; } $order = wc_get_order( $order_id ); } else { $order = $this->get_context_order(); } if ( ! $order ) { return ''; } $format = 'html' === sanitize_key( (string) $attributes['format'] ) ? 'html' : 'pdf'; $template = sanitize_text_field( (string) $attributes['template'] ); $url = self::get_receipt_url( $order, $format, $template ); $id = '' !== (string) $attributes['id'] ? ' id="' . esc_attr( (string) $attributes['id'] ) . '"' : ''; return sprintf( '%4$s', esc_url( $url ), $id, esc_attr( (string) $attributes['class'] ), esc_html( (string) $attributes['link_text'] ) ); } /** * Add the receipt download to My Account order actions. * * @param array> $actions Existing order actions. * @param WC_Abstract_Order $order Order object. * * @return array> Filtered order actions. */ public function add_my_account_action( array $actions, WC_Abstract_Order $order ): array { /* * Filters whether the My Account receipt button is enabled. * * Defaults to the `storefront_receipt_enabled` general setting (opt-in, * off by default). The filter still allows programmatic overrides, * including per-order decisions via the $order argument. * * @param bool $enabled Whether the button is enabled. * @param WC_Abstract_Order $order Order object. * * @returns bool Whether the button is enabled. * * @since 1.9.11 * * @hook woocommerce_pos_storefront_receipt_my_account_button */ $default_enabled = wp_validate_boolean( woocommerce_pos_get_settings( 'general', 'storefront_receipt_enabled' ) ); $enabled = (bool) apply_filters( 'woocommerce_pos_storefront_receipt_my_account_button', $default_enabled, $order ); if ( ! $enabled || null === Templates::get_active_template_id( 'receipt' ) ) { return $actions; } /* * Filters the order statuses that expose a storefront receipt. * * @param string[] $statuses Eligible order statuses. * @param WC_Abstract_Order $order Order object. * * @returns string[] Eligible order statuses. * * @since 1.9.11 * * @hook woocommerce_pos_storefront_receipt_order_statuses */ $statuses = (array) apply_filters( 'woocommerce_pos_storefront_receipt_order_statuses', array( 'processing', 'completed', 'refunded' ), $order ); if ( ! $order->has_status( $statuses ) ) { return $actions; } // An empty template means "use the active receipt template". A configured // value is passed through the existing, already-validated ?template= path // (published receipt templates only); an invalid value simply falls back // to the active template when the receipt renders. $template = sanitize_text_field( (string) woocommerce_pos_get_settings( 'general', 'storefront_receipt_template' ) ); $actions['wcpos-receipt'] = array( 'url' => self::get_receipt_url( $order, 'pdf', $template ), 'name' => __( 'Receipt', 'woocommerce-pos' ), /* translators: %s: order number. */ 'aria-label' => sprintf( __( 'Download receipt for order #%s', 'woocommerce-pos' ), $order->get_order_number() ), ); return $actions; } /** * Check whether the current user may view an order. * * @param int $order_id Order ID. * @return bool */ private function can_view_order( int $order_id ): bool { return 0 < $order_id && is_user_logged_in() && current_user_can( 'view_order', $order_id ); } /** * Resolve an order from a supported WooCommerce page context. * * @return WC_Abstract_Order|null Context order or null. */ private function get_context_order(): ?WC_Abstract_Order { if ( is_order_received_page() ) { $order = wc_get_order( absint( get_query_var( 'order-received' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $key = isset( $_GET['key'] ) ? sanitize_text_field( wp_unslash( $_GET['key'] ) ) : ''; return $order && '' !== $key && hash_equals( $order->get_order_key(), $key ) ? $order : null; } if ( is_account_page() && is_wc_endpoint_url( 'view-order' ) ) { $order_id = absint( get_query_var( 'view-order' ) ); if ( $this->can_view_order( $order_id ) ) { $order = wc_get_order( $order_id ); return $order ? $order : null; } } return null; } /** * Build a key-gated receipt URL. * * @param WC_Abstract_Order $order Order object. * @param string $format Receipt format. * @param string $template Optional template ID. * * @return string Receipt URL. */ private static function get_receipt_url( WC_Abstract_Order $order, string $format = 'pdf', string $template = '' ): string { $args = array( 'key' => $order->get_order_key() ); if ( 'pdf' === $format ) { $args['format'] = 'pdf'; } if ( '' !== $template ) { $args['template'] = $template; } return add_query_arg( $args, wcpos_checkout_url( 'wcpos-receipt/' . $order->get_id() ) ); } }