# woo-postnl/5.9.12/src/Order/Single.php

PostNL for WooCommerce, version 5.9.12. 794 lines.

- Page: https://pluginprobe.com/plugins/woo-postnl/5.9.12/code/src/Order/Single.php
- Raw: https://pluginprobe.com/plugins/woo-postnl/5.9.12/raw/src/Order/Single.php
- Modified: 2026-08-31T09:58:16+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/woo-postnl/5.9.12/code/src/Order/Single.php#L10-L20`.

```php
<?php
/**
 * Class Order\Single file.
 *
 * @package PostNLWooCommerce\Order
 */

namespace PostNLWooCommerce\Order;

use PostNLWooCommerce\Utils;
use PostNLWooCommerce\Helper\Mapping;
use WC_Order_Item;
use WC_Order_Item_Product;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Single
 *
 * @package PostNLWooCommerce\Order
 */
class Single extends Base {
	/**
	 * Collection of hooks when initiation.
	 */
	public function init_hooks() {
		add_filter( 'woocommerce_admin_shipping_fields', array( $this, 'admin_address_fields' ) );
		add_filter( 'woocommerce_admin_billing_fields', array( $this, 'admin_address_fields' ) );
		add_filter( 'woocommerce_order_formatted_shipping_address', array( $this, 'display_shipping_house_number' ), 10, 2 );
		add_filter( 'woocommerce_order_formatted_billing_address', array( $this, 'display_billing_house_number' ), 10, 2 );

		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_order_single_css_script' ) );
		add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ), 20, 2 );

		add_action( 'wp_ajax_postnl_order_save_form', array( $this, 'save_meta_box_ajax' ) );
		add_action( 'wp_ajax_nopriv_postnl_order_save_form', array( $this, 'save_meta_box_ajax' ) );

		add_action( 'wp_ajax_postnl_order_delete_data', array( $this, 'delete_meta_data_ajax' ) );
		add_action( 'wp_ajax_nopriv_postnl_order_delete_data', array( $this, 'delete_meta_data_ajax' ) );

		add_action( 'init', array( $this, 'get_label_file' ), 10 );

		add_action( 'wp_ajax_postnl_activate_return_function', array( $this, 'postnl_activate_return_function' ) );
		add_action( 'wp_ajax_nopriv_postnl_activate_return_function', array( $this, 'postnl_activate_return_function' ) );

		add_action( 'wp_ajax_postnl_send_smart_return_email', array( $this, 'postnl_send_smart_return_email' ) );
		add_action( 'wp_ajax_nopriv_postnl_send_smart_return_email', array( $this, 'postnl_send_smart_return_email' ) );

		add_action( 'woocommerce_after_order_itemmeta', array( $this, 'add_adult_product_label_admin_order_page' ), 10, 2 );
	}

	/**
	 * Enqueue CSS file in order detail page.
	 */
	public function enqueue_order_single_css_script() {
		$screen = get_current_screen();

		if ( empty( $screen->id ) ) {
			return;
		}

		if ( ! empty( $screen->id ) && 'woocommerce_page_wc-settings' === $screen->id && ! empty( $_GET['section'] ) && POSTNL_SETTINGS_ID === wp_unslash( $_GET['section'] ) ) {
			wp_enqueue_script(
				'postnl-admin-settings',
				POSTNL_WC_PLUGIN_DIR_URL . '/assets/js/admin-settings.js',
				array( 'jquery' ),
				POSTNL_WC_VERSION,
				true
			);
			wp_enqueue_style(
				'postnl-admin-settings-styles',
				POSTNL_WC_PLUGIN_DIR_URL . '/assets/css/admin-settings.css',
				array(),
				POSTNL_WC_VERSION
			);
		}

		if ( ( 'shop_order' === $screen->id && 'post' === $screen->base ) || 'woocommerce_page_wc-orders' === $screen->id ) {
			wp_enqueue_style( 'postnl-admin-order-single', POSTNL_WC_PLUGIN_DIR_URL . '/assets/css/admin-order-single.css', array(), POSTNL_WC_VERSION );

			wp_enqueue_script(
				'postnl-admin-order-single',
				POSTNL_WC_PLUGIN_DIR_URL . '/assets/js/admin-order-single.js',
				array( 'jquery' ),
				POSTNL_WC_VERSION,
				true
			);

			wp_enqueue_script(
				'postnl-admin-shipment-track-trace',
				POSTNL_WC_PLUGIN_DIR_URL . '/assets/js/admin-shipment-track-trace.js',
				array( 'jquery' ),
				POSTNL_WC_VERSION,
				true
			);

			wp_localize_script(
				'postnl-admin-order-single',
				'postnl_admin_order_obj',
				array(
					'prefix' => $this->prefix,
					'fields' => array_map(
						function ( $meta_field ) {
							return empty( $meta_field['id'] ) ? '' : $meta_field['id'];
						},
						$this->meta_box_fields(),
					),
				)
			);
		}
	}

	/**
	 * Adding meta box in order admin page.
	 *
	 * @param String           $post_type Post type for current admin page.
	 * @param WP_POST|WC_Order $post_or_order_object Either WP_Post or WC_Order object.
	 */
	public function add_meta_box( $post_type, $post_or_order_object ) {
		$order = $this->init_order_object( $post_or_order_object );

		if ( ! is_a( $order, 'WC_Order' ) || ! $this->is_postnl_shipping_method( $order ) ) {
			return;
		}

		// translators: %s will be replaced by service name.
		add_meta_box(
			'woocommerce-shipment-postnl-label',
			esc_html__( 'Label & Tracking', 'postnl-for-woocommerce' ),
			array(
				$this,
				'meta_box_html',
			),
			Utils::get_order_screen_id(),
			'side',
			'high'
		);
	}

	/**
	 * Add value to meta box fields.
	 *
	 * @param WC_Order $order current order object.
	 *
	 * @return array
	 */
	public function add_meta_box_value( $order ) {
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return array();
		}
		$meta_fields = $this->meta_box_fields( $order );

		$order_data   = $order->get_meta( $this->meta_name );
		$option_map   = Mapping::option_available_list();
		$from_country = Utils::get_base_country();
		$to_country   = $order->get_shipping_country();
		$to_state     = $order->get_shipping_state();
		$destination  = Utils::get_shipping_zone( $to_country, $to_state );

		// The persisted backend collapses the 24h/48h choice onto the generic
		// 'letterbox' feature. Swap in the resolved variant so the override loop
		// below re-checks (and, once a label exists, locks) the correct checkbox
		// instead of re-checking the generic 24h box on top of the pre-selected
		// 48h box, which would show both letterbox variants as selected.
		if ( isset( $order_data['backend'] ) && is_array( $order_data['backend'] ) ) {
			$order_data['backend'] = $this->apply_letterbox_display_variant( $order_data['backend'], $order );
		}

		foreach ( $meta_fields as $index => $field ) {
			if ( isset( $field['nonce'] ) && true === $field['nonce'] ) {
				continue;
			}

			$field_name = Utils::remove_prefix_field( $this->prefix, $field['id'] );

			if ( ! empty( $order_data['frontend'][ $field_name ] ) ) {
				$meta_fields[ $index ]['value'] = $order_data['frontend'][ $field_name ];
			}

			if ( isset( $order_data['backend'][ $field_name ] ) ) {
				if ( $this->have_label_file( $order ) ) {
					$meta_fields[ $index ]['custom_attributes']['disabled'] = 'disabled';
				}
				$meta_fields[ $index ]['value'] = $order_data['backend'][ $field_name ];
			}

			if ( isset( $option_map[ $from_country ][ $destination ] ) ) {
				$meta_fields[ $index ]['standard_feat'] = in_array( $field_name, $option_map[ $from_country ][ $destination ] );
			} else {
				$meta_fields[ $index ]['standard_feat'] = false;
			}
		}

		return $meta_fields;
	}

	/**
	 * Filter the fields to display the available fields only.
	 *
	 * @param Array $meta_fields Order meta fields.
	 * @param Array $available_options Available fields based on the countries and chosen option in checkout page.
	 *
	 * @return array
	 */
	public function filter_available_fields( $meta_fields, $available_options ) {
		$meta_fields = array_filter(
			$meta_fields,
			function ( $field ) use ( $available_options ) {
				$field_name = Utils::remove_prefix_field( $this->prefix, $field['id'] );

				if ( true === $field['standard_feat'] ) {
					return true;
				}

				if ( true === $field['const_field'] ) {
					return true;
				}

				return in_array( $field_name, $available_options, true );
			}
		);

		return $meta_fields;
	}

	/**
	 * Get dropoff points information.
	 *
	 * @param WC_Order $order Order object.
	 *
	 * @return Array.
	 */
	public function get_pickup_points_info( $order ) {
		return $this->get_order_frontend_info( $order, 'dropoff_points_' );
	}

	/**
	 * Get delivery day information.
	 *
	 * @param WC_Order $order Order object.
	 *
	 * @return Array.
	 */
	public function get_delivery_day_info( $order ) {
		return $this->get_order_frontend_info( $order, 'delivery_day_' );
	}

	/**
	 * Generate the dropoff points html information.
	 *
	 * @param WC_Order $order Order object.
	 */
	public function generate_delivery_type_html( $order ) {
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return;
		}

		$delivery_type = $this->get_delivery_type( $order );

		if ( empty( $delivery_type ) ) {
			return;
		}
		?>
		<div class="postnl-info-container delivery-type-info">
			<label for="postnl_delivery_type"><?php esc_html_e( 'Delivery Type:', 'postnl-for-woocommerce' ); ?></label>
			<div class="postnl-info delivery-type">
				<?php echo esc_html( $delivery_type ); ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Generate the dropoff points html information.
	 *
	 * @param Array $infos Dropoff points informations.
	 */
	public function generate_delivery_date_html( $infos ) {
		$filtered_infos = array_filter(
			$infos,
			function ( $info ) {
				$displayed_info = array(
					'delivery_day_date',
				);

				return in_array( $info, $displayed_info, true );
			},
			ARRAY_FILTER_USE_KEY
		);

		if ( empty( $filtered_infos ) ) {
			return;
		}
		?>
		<div class="postnl-info-container delivery-date-info">
			<label for="postnl_pickup_points"><?php esc_html_e( 'Delivery Date:', 'postnl-for-woocommerce' ); ?></label>
			<?php
			foreach ( $filtered_infos as $info_idx => $info_val ) {
				// Convert to the Dutch date format, falling back to the stored value
				// when it does not parse as Y-m-d so a malformed date cannot fatal the
				// whole order edit screen via date_format( false, ... ).
				$date_obj   = date_create_from_format( 'Y-m-d', $info_val );
				$dutch_date = ( false !== $date_obj ) ? date_format( $date_obj, 'd/m/Y' ) : $info_val;
				?>
				<div class="postnl-info <?php echo esc_attr( $info_idx ); ?>">
					<?php echo esc_html( $dutch_date ); ?>
				</div>
				<?php
			}
			?>
		</div>
		<?php
	}

	/**
	 * Generate the dropoff points html information.
	 *
	 * @param Array $infos Dropoff points informations.
	 */
	public function generate_pickup_points_html( $infos ) {
		$filtered_infos = Utils::get_filtered_pickup_points_infos( $infos );

		if ( empty( $filtered_infos ) ) {
			return;
		}
		?>
		<div class="postnl-info-container pickup-points-info">
			<label for="postnl_pickup_points"><?php esc_html_e( 'Pickup Address:', 'postnl-for-woocommerce' ); ?></label>
			<?php
			foreach ( $filtered_infos as $info_idx => $info_val ) {
				switch ( $info_idx ) {
					case 'dropoff_points_date':
						$additional_text = esc_html__( 'Date:', 'postnl-for-woocommerce' );
						break;

					case 'dropoff_points_time':
						$additional_text = esc_html__( 'Time:', 'postnl-for-woocommerce' );
						break;

					default:
						$additional_text = '';
						break;
				}
				?>
				<div class="postnl-info <?php echo esc_attr( $info_idx ); ?>">
					<?php echo esc_html( $additional_text . ' ' . $info_val ); ?>
				</div>
				<?php
			}
			?>
		</div>
		<?php
	}

	/**
	 * Adds an 'Activate return function' button.
	 */
	public function activate_return_function_html( $order ) {
		if ( 'shipping_return' === $this->settings->get_return_shipment_and_labels() && 'no' === $this->settings->get_return_shipment_and_labels_all() && 'NL' === $order->get_shipping_country() && 'NL' === Utils::get_base_country() && ! Utils::is_order_eligible_auto_letterbox( $order ) ) {
			?>
			<hr id="postnl_break_2">
			<p class="form-field">

				<?php wp_nonce_field( 'postnl_activate_return_function', 'activate_return_function_nonce' ); ?>
				<button type="button" class="button button-activate-return" <?php disabled( $this->is_return_function_activated( $order ) ); ?>><?php esc_html_e( 'Activate return function', 'postnl-for-woocommerce' ); ?></button>

				<div class="postnl-info activated-return-info" <?php echo ( $this->is_return_function_activated( $order ) ) ? '' : 'style="display:none;"'; ?> >
					<?php esc_html_e( 'Return function is activated for this label', 'postnl-for-woocommerce' ); ?>
				</div>
				<div class="postnl-info activate-return-info" <?php echo ( $this->is_return_function_activated( $order ) ) ? 'style="display:none;"' : ''; ?> >
					<?php esc_html_e( 'Click here to activate the return function of this label', 'postnl-for-woocommerce' ); ?>
				</div>
			</p>
			<?php
		}
	}

	/**
	 * Adds an 'Send Smart Return' button.
	 */
	public function send_smart_return_email_html( $order ) {
		if ( 'NL' === $order->get_shipping_country() && $this->settings->is_smart_return_enabled() ) {
			$check_for_barcode = empty( $this->get_backend_data( $order->get_ID() ) );
			?>
			<hr id="postnl_break_2">
			<p class="form-field">
				<?php wp_nonce_field( 'postnl_send_smart_return_email', 'send_smart_return_email_nonce' ); ?>
				<button type="button"
						class="button button-send-smart-return" <?php disabled( $check_for_barcode ); ?>><?php esc_html_e( 'Send email with Smart Return', 'postnl-for-woocommerce' ); ?></button>
			</p>
			<?php
		}
	}

	/**
	 * Additional fields of the meta box for child class.
	 *
	 * @param WP_Post|WC_Order $post_or_order_object current order object.
	 */
	public function meta_box_html( $post_or_order_object ) {
		$order = $this->init_order_object( $post_or_order_object );
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return;
		}

		$form_class = ( $this->have_label_file( $order ) ) ? 'generated' : '';
		if ( $this->have_backend_data( $order, 'create_return_label' ) ) {
			$form_class .= ' has-return';
		}

		if ( $this->have_backend_data( $order, 'letterbox' ) ) {
			$form_class .= ' has-letterbox';
		}

		$pickup_info       = $this->get_pickup_points_info( $order );
		$delivery_info     = $this->get_delivery_day_info( $order );
		$fields_with_value = $this->add_meta_box_value( $order );
		$available_options = $this->get_available_options( $order );
		$available_fields  = $this->filter_available_fields( $fields_with_value, $available_options );
		?>
		<div id="shipment-postnl-label-form" class="<?php echo esc_attr( $form_class ); ?>">
			<?php $this->generate_delivery_type_html( $order ); ?>
			<?php $this->generate_delivery_date_html( $delivery_info ); ?>
			<?php $this->generate_pickup_points_html( $pickup_info ); ?>
			<?php Utils::fields_generator( $available_fields ); ?>
			<div class="button-container">
				<button class="button button-primary button-save-form"><?php esc_html_e( 'Create Shipment', 'postnl-for-woocommerce' ); ?></button>
				<a href="<?php echo esc_url( $this->get_download_label_url( $order->get_id() ) ); ?>"
					class="button button-primary button-download-label"><?php esc_html_e( 'Print Label', 'postnl-for-woocommerce' ); ?></a>
				<a class="button button-secondary delete-label"
					href="#"><?php esc_html_e( 'Delete Label', 'postnl-for-woocommerce' ); ?></a>
			</div>
			<?php $this->activate_return_function_html( $order ); ?>
			<?php $this->send_smart_return_email_html( $order ); ?>
			<!--
			<div class="button-container return-container">
				<a href="<?php echo esc_url( $this->get_download_label_url( $order->get_id(), 'return-label' ) ); ?>" class="button button-primary button-download-label"><?php esc_html_e( 'Print Return Label', 'postnl-for-woocommerce' ); ?></a>
			</div>
			-->
			<!--
			<div class="button-container letterbox-container">
				<a href="<?php echo esc_url( $this->get_download_label_url( $order->get_id(), 'buspakjeextra' ) ); ?>" class="button button-primary button-download-label"><?php esc_html_e( 'Print Letterbox', 'postnl-for-woocommerce' ); ?></a>
			</div>
			-->
			<div id="shipment-postnl-error-text"></div>
		</div>
		<?php
	}

	/**
	 * Saving meta box in order admin page using ajax.
	 *
	 * @throws \Exception Throw error for invalid nonce.
	 */
	public function save_meta_box_ajax() {
		try {
			// Get array of nonce fields.
			$nonce_fields = array_values( $this->get_nonce_fields() );

			if ( empty( $nonce_fields ) ) {
				throw new \Exception( esc_html__( 'Cannot find nonce field!', 'postnl-for-woocommerce' ) );
			}

			// Check nonce before proceed.
			$nonce_result = check_ajax_referer( $this->nonce_key, $nonce_fields[0]['id'], false );
			if ( false === $nonce_result ) {
				throw new \Exception( esc_html__( 'Nonce is invalid!', 'postnl-for-woocommerce' ) );
			}

			$order_id = ! empty( $_REQUEST['order_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order_id'] ) ) : 0;

			$result        = $this->save_meta_value( $order_id, $_REQUEST );
			$return_data   = $result['saved_data'];
			$labels        = $result['labels'];
			$tracking_note = $this->get_tracking_note( $order_id );

			if ( ! empty( $tracking_note ) ) {
				$return_data = array_merge(
					$result['saved_data'],
					array(
						'tracking_note' => $tracking_note,
						'note_type'     => $this->settings->is_woocommerce_email_enabled() ? 'customer' : 'private',
					)
				);
			}

			wp_send_json_success( $return_data );
		} catch ( \Exception $e ) {
			wp_send_json_error(
				array( 'message' => $e->getMessage() ),
			);
		}
	}

	/**
	 * Delete meta data in order admin page using ajax.
	 *
	 * @throws \Exception Throw error for invalid nonce.
	 */
	public function delete_meta_data_ajax() {
		try {
			// Get array of nonce fields.
			$nonce_fields = array_values( $this->get_nonce_fields() );

			if ( empty( $nonce_fields ) ) {
				throw new \Exception( esc_html__( 'Cannot find nonce field!', 'postnl-for-woocommerce' ) );
			}

			// Check nonce before proceed.
			$nonce_result = check_ajax_referer( $this->nonce_key, $nonce_fields[0]['id'], false );
			if ( false === $nonce_result ) {
				throw new \Exception( esc_html__( 'Nonce is invalid!', 'postnl-for-woocommerce' ) );
			}

			$order_id = ! empty( $_REQUEST['order_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order_id'] ) ) : 0;

			// Check if order id is really an ID from shop_order post type.
			$order = wc_get_order( $order_id );
			if ( ! is_a( $order, 'WC_Order' ) ) {
				throw new \Exception( esc_html__( 'Order does not exist!', 'postnl-for-woocommerce' ) );
			}

			$saved_data = $this->delete_meta_value( $order_id );
			wp_send_json_success( $saved_data );
		} catch ( \Exception $e ) {
			wp_send_json_error(
				array( 'message' => $e->getMessage() ),
			);
		}
	}

	/**
	 * Add house number field to the order address fields within the dashboard.
	 *
	 * @param array $fields address fields.
	 *
	 * @return array.
	 */
	public function admin_address_fields( $fields ) {
		$new_fields = array();
		foreach ( $fields as $key => $field ) {
			if ( 'address_1' === $key ) {
				$new_fields['house_number'] = array(
					'label' => __( 'House number', 'postnl-for-woocommerce' ),
					'show'  => false,
				);
			}

			$new_fields[ $key ] = $field;
		}

		return $new_fields;
	}

	/**
	 * Modify address and add house number.
	 *
	 * @param array     $address Array of shipping address.
	 * @param \WC_Order $order Order object.
	 * @param String    $type Address type.
	 *
	 * @return mixed
	 */
	public function add_house_number_to_address( $address, $order, $type = 'shipping' ) {
		if ( 'shipping' === $type ) {
			$house_number_meta = '_shipping_house_number';
		} else {
			$house_number_meta = '_billing_house_number';
		}

		$house_number = $order->get_meta( $house_number_meta );

		if ( $house_number ) {
			$address['address_1'] .= ' ' . $house_number;
		}

		return $address;
	}

	/**
	 * Add house number to the shipping address within the order.
	 *
	 * @param array     $address Array of shipping address.
	 * @param \WC_Order $order Order object.
	 *
	 * @return array
	 */
	public function display_shipping_house_number( $address, $order ) {
		return $this->add_house_number_to_address( $address, $order, 'shipping' );
	}

	/**
	 * Add house number to the billing address within the order.
	 *
	 * @param array     $address Array of shipping address.
	 * @param \WC_Order $order Order object.
	 *
	 * @return array
	 */
	public function display_billing_house_number( $address, $order ) {
		return $this->add_house_number_to_address( $address, $order, 'billing' );
	}

	/**
	 * Ajax action to activate return function.
	 *
	 * @return void
	 */
	public function postnl_activate_return_function() {
		try {
			if ( ! isset( $_POST['security'] ) ) {
				throw new \Exception( esc_html__( 'Cannot find nonce field!', 'postnl-for-woocommerce' ) );
			}

			// Check nonce before proceed.
			if ( ! wp_verify_nonce( $_POST['security'], 'postnl_activate_return_function' ) ) {
				throw new \Exception( esc_html__( 'Nonce is invalid', 'postnl-for-woocommerce' ) );
			}

			$order_id = ! empty( $_REQUEST['order_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order_id'] ) ) : 0;

			// Check if order id is really an ID from shop_order post type.
			$order = wc_get_order( $order_id );
			if ( ! is_a( $order, 'WC_Order' ) ) {
				throw new \Exception( esc_html__( 'Order does not exist!', 'postnl-for-woocommerce' ) );
			}

			if ( $this->is_return_function_activated( $order ) ) {
				throw new \Exception( esc_html__( 'Already activated!', 'postnl-for-woocommerce' ) );
			}

			$response = $this->service_factory()->return_label_service()->activate( (int) $order_id );

			if ( ! empty( $response['successFulBarcodes'] ) && is_array( $response['successFulBarcodes'] ) ) {
				$order->update_meta_data( $this->is_return_activated_meta, 'yes' );
				$order->save_meta_data();

				wp_send_json_success();

				return;
			}

			$error_message = esc_html__( 'Unknown error.', 'postnl-for-woocommerce' );
			$error_items   = array();

			if ( isset( $response['errorsPerBarcode'] ) && is_array( $response['errorsPerBarcode'] ) ) {
				foreach ( $response['errorsPerBarcode'] as $barcode_errors ) {
					if ( ! isset( $barcode_errors['errors'] ) || ! is_array( $barcode_errors['errors'] ) ) {
						continue;
					}

					foreach ( $barcode_errors['errors'] as $error ) {
						if ( empty( $error['description'] ) ) {
							continue;
						}

						$error_items[] = sprintf( '<li>%s</li>', esc_html( $error['description'] ) );
					}
				}
			}

			if ( ! empty( $error_items ) ) {
				$error_message = '<ul>' . implode( '', $error_items ) . '</ul>';
			}

			// Translators: %s is the error message.
			throw new \Exception( sprintf( esc_html__( 'Error: %s', 'postnl-for-woocommerce' ), $error_message ) );
		} catch ( \Exception $e ) {
			wp_send_json_error(
				array( 'message' => $e->getMessage() ),
			);
		}
	}

	/**
	 * Ajax action to send smart return email.
	 *
	 * @return void
	 */
	public function postnl_send_smart_return_email() {
		try {
			if ( ! isset( $_POST['security'] ) ) {
				throw new \Exception( esc_html__( 'Cannot find nonce field!', 'postnl-for-woocommerce' ) );
			}

			// Check nonce before proceed.
			if ( ! wp_verify_nonce( $_POST['security'], 'postnl_send_smart_return_email' ) ) {
				throw new \Exception( esc_html__( 'Nonce is invalid', 'postnl-for-woocommerce' ) );
			}

			$order_id = ! empty( $_REQUEST['order_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order_id'] ) ) : 0;

			// Check if order id is really an ID from shop_order post type.
			$order = wc_get_order( $order_id );
			if ( ! is_a( $order, 'WC_Order' ) ) {
				throw new \Exception( esc_html__( 'Order does not exist!', 'postnl-for-woocommerce' ) );
			}

			$response = $this->service_factory()->smart_returns_service()->generate( $order );

			$to     = $order->get_billing_email();
			$emails = WC()->mailer()->get_emails();

			if ( empty( $emails ) || ! isset( $emails['WC_Smart_Return_Email'] ) ) {
				throw new \Exception( esc_html__( 'Email could not be sent', 'postnl-for-woocommerce' ) );
			}

			$email            = $emails['WC_Smart_Return_Email'];
			$email->recipient = $to;

			if ( 'v4' === ( $response['api_version'] ?? '' ) ) {
				// V4 retailPrint: show the printcode/barcode image in the email body, no PDF attachment.
				if ( empty( $response['content'] ) ) {
					throw new \Exception( esc_html__( 'Printcode could not be found', 'postnl-for-woocommerce' ) );
				}

				$email->printcode_content = $response['content'];
				$email->printcode_mime    = $response['mime'] ?? 'image/png';
				$email->printcode_barcode = (string) ( $response['barcode'] ?? '' );
			} else {
				// Legacy: pull the PrintcodeLabel PDF from the response and attach it.
				$printcode_label_content = null;

				if ( ! empty( $response['ResponseShipments'] ) ) {
					foreach ( $response['ResponseShipments'] as $shipment ) {
						if ( empty( $shipment['Labels'] ) ) {
							continue;
						}

						foreach ( $shipment['Labels'] as $label ) {
							if ( isset( $label['Labeltype'] ) && 'PrintcodeLabel' === $label['Labeltype'] ) {
								$printcode_label_content = $label['Content'];
								break 2;
							}
						}
					}
				}

				if ( ! $printcode_label_content ) {
					throw new \Exception( esc_html__( 'The Smart Return printcode could not be found.', 'postnl-for-woocommerce' ) );
				}

				$upload_dir = wp_upload_dir();
				$file_path  = $upload_dir['path'] . '/printcode_label.pdf';

				// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents, WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- Writing the PostNL printcode PDF returned base64-encoded by the API.
				file_put_contents( $file_path, base64_decode( $printcode_label_content ) );

				$email->attachment = $file_path;
			}

			$is_successful = $email->trigger( $order_id );

			if ( $is_successful ) {
				wp_send_json_success( $to );
			}

			throw new \Exception( esc_html__( 'Email could not be sent', 'postnl-for-woocommerce' ) );
		} catch ( \Exception $e ) {
			wp_send_json_error(
				array( 'message' => $e->getMessage() ),
			);
		}
	}

	/**
	 * Add "18+" label beside adult products in the WooCommerce admin order page.
	 *
	 * @param int           $item_id Order item ID.
	 * @param WC_Order_Item $item    Order item object.
	 *
	 * @return void
	 */
	public function add_adult_product_label_admin_order_page( int $item_id, WC_Order_Item $item ): void {
		if ( ! $item instanceof WC_Order_Item_Product ) {
			return; // Only handle product items.
		}

		$product = $item->get_product();

		if ( ! $product ) {
			return;
		}

		$is_adult = Utils::is_adults_only_product( $product );

		if ( $is_adult ) {
			echo '<p>' . esc_html__( '18+ Adults Only', 'postnl-for-woocommerce' ) . '</p>';
		}
	}
}

```
