# woo-postnl/5.9.12/src/Shipping_Method/Settings.php

PostNL for WooCommerce, version 5.9.12. 2,168 lines.

- Page: https://pluginprobe.com/plugins/woo-postnl/5.9.12/code/src/Shipping_Method/Settings.php
- Raw: https://pluginprobe.com/plugins/woo-postnl/5.9.12/raw/src/Shipping_Method/Settings.php
- Modified: 2026-09-15T16:52:20+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/Shipping_Method/Settings.php#L10-L20`.

```php
<?php
/**
 * Class Shipping_Method/Settings file.
 *
 * @package PostNLWooCommerce\Shipping_Method
 */

namespace PostNLWooCommerce\Shipping_Method;

use PostNLWooCommerce\Rest_API\Barcode\Key_Validator;
use PostNLWooCommerce\Utils;

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

/**
 * Class Settings
 *
 * @package PostNLWooCommerce\Shipping_Method
 */
class Settings extends \WC_Settings_API {
	/**
	 * ID of the class extending the settings API. Used in option names.
	 *
	 * @var string
	 */
	public $id = POSTNL_SETTINGS_ID;

	/**
	 * The unique instance of the plugin.
	 *
	 * @var Settings
	 */
	private static $instance;

	/**
	 * Merchant codes option name
	 */
	const MERCHANT_CODES_OPTION = 'postnl_merchant_codes';

	/**
	 * Gets an instance of the settings.
	 *
	 * @return Settings
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Get all setting fields.
	 *
	 * @return array
	 */
	public function get_setting_fields() {
		$fields = array(
			// Manual.
			'user_manual'                     => array(
				'title'       => esc_html__( 'Manual', 'postnl-for-woocommerce' ),
				'type'        => 'title',
				// translators: %1$s & %2$s is replaced with <a> tag.
				'description' => sprintf( __( 'Consult the %1$smanual%2$s for help installing the plug-in.', 'postnl-for-woocommerce' ), '<a href="https://postnl.github.io/woocommerce/new-manual/?lang=nl" target="_blank">', '</a>' ),
			),
			// Account Settings.
			'account_settings_title'          => array(
				'title'       => esc_html__( 'Account Settings', 'postnl-for-woocommerce' ),
				'type'        => 'title',
				// translators: %1$s & %2$s is replaced with <a> tag.
				'description' => sprintf( __( 'Please configure your shipping parameters and your access towards the PostNL APIs by means of authentication. You can find the details of your PostNL account in Mijn %1$sPostNL%2$s under "My Account > API beheren".', 'postnl-for-woocommerce' ), '<a href="https://mijn.postnl.nl/c/BP2_Mod_Login.app" target="_blank">', '</a>' ),
			),
			'environment_mode'                => array(
				'title'       => esc_html__( 'Environment Mode', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Choose the environment mode.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'options'     => array(
					'production' => esc_html__( 'Production', 'postnl-for-woocommerce' ),
					'sandbox'    => esc_html__( 'Sandbox', 'postnl-for-woocommerce' ),
				),
				'class'       => 'wc-enhanced-select',
				'default'     => 'production',
				'placeholder' => '',
			),
			// Legacy production key. Renamed to "Old API Key" and only rendered when
			// a value is already stored (see the gating in get_setting_fields()); a
			// fresh install shows the "API Key" field alone. Kept read-only so
			// merchants enter their key in the new field ahead of the API migration.
			'api_keys'                        => array(
				'title'             => esc_html__( 'Old API Key', 'postnl-for-woocommerce' ),
				'type'              => 'text',
				'description'       => esc_html__( 'The key you were using before. It is locked because new keys go in the field below.', 'postnl-for-woocommerce' ),
				'desc_tip'          => false,
				'default'           => '',
				'placeholder'       => '',
				'custom_attributes' => array( 'readonly' => 'readonly' ),
			),
			'api_keys_new'                    => array(
				'title'       => esc_html__( 'API Key', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter your PostNL API key here. You can get it from the Self Service module on the PostNL Business Portal.', 'postnl-for-woocommerce' ),
				'desc_tip'    => false,
				'default'     => '',
				'placeholder' => '',
			),
			'api_keys_new_status'             => array(
				'type'        => 'postnl_new_key_status',
				'environment' => 'production',
			),
			'api_keys_sandbox'                => array(
				'title'             => esc_html__( 'Old Sandbox API Key', 'postnl-for-woocommerce' ),
				'type'              => 'text',
				'description'       => esc_html__( 'The sandbox key you were using before. It is locked because new keys go in the field below.', 'postnl-for-woocommerce' ),
				'desc_tip'          => false,
				'default'           => '',
				'placeholder'       => '',
				'custom_attributes' => array( 'readonly' => 'readonly' ),
			),
			'api_keys_sandbox_new'            => array(
				'title'       => esc_html__( 'Sandbox API Key', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter your PostNL sandbox API key here. You can get it from the Self Service module on the PostNL Business Portal.', 'postnl-for-woocommerce' ),
				'desc_tip'    => false,
				'default'     => '',
				'placeholder' => '',
			),
			'api_keys_sandbox_new_status'     => array(
				'type'        => 'postnl_new_key_status',
				'environment' => 'sandbox',
			),
			'enable_logging'                  => array(
				'title'       => esc_html__( 'Logging', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'description' => sprintf(
				// translators: %1$s is anchor opener tag and %2$s is anchor closer tag.
					esc_html__( 'A log file containing the communication to the PostNL server will be maintained if this option is checked. This can be used in case of technical issues and can be found %1$shere%2$s.', 'postnl-for-woocommerce' ),
					'<a href="' . esc_url( Utils::get_log_url() ) . '" target="_blank">',
					'</a>'
				),
				'label'       => esc_html__( 'Enable', 'postnl-for-woocommerce' ),
				'desc_tip'    => false,
				'default'     => '',
				'placeholder' => '',
			),
			'customer_num'                    => array(
				'title'       => esc_html__( 'Customer Number', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'e.g. "11223344"', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'placeholder' => '11223344',
			),
			'customer_code'                   => array(
				'title'             => esc_html__( 'Customer Code', 'postnl-for-woocommerce' ),
				'type'              => 'text',
				'description'       => esc_html__( 'e.g. "DEVC"', 'postnl-for-woocommerce' ),
				'desc_tip'          => true,
				'default'           => '',
				'placeholder'       => 'DEVC',
				'custom_attributes' => array( 'maxlength' => '10' ),
			),
			'return_company'                  => array(
				'title'       => esc_html__( 'Company Name', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter company name - this name will be noted as the sender on the label', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			/*
			Temporarily hardcoded.
			'location_code'             => array(
				'title'             => esc_html__( 'Location Code', 'postnl-for-woocommerce' ),
				'type'              => 'text',
				'description'       => esc_html__( 'e.g. "123456"', 'postnl-for-woocommerce' ),
				'desc_tip'          => true,
				'default'           => '',
				'placeholder'       => '123456',
				'custom_attributes' => array( 'maxlength' => '10' ),
			),
			*/

			// Return Settings.
			'return_settings_title'           => array(
				'title' => esc_html__( 'Return Settings', 'postnl-for-woocommerce' ),
				'type'  => 'title',
				// 'description' => esc_html__( 'If you have a reply number, only fill in the Zip code, City and Return code. If you want to return your shipments to a home address, also provide the address line (Street, Housenumber and HouseNrExt) of your return address.', 'postnl-for-woocommerce' ),
			),
			'return_shipment_and_labels'      => array(
				'title'       => esc_html__( 'Standard return option', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => esc_html__( '- None: return labels are not automatically created', 'postnl-for-woocommerce' ) . '<br>' .
								esc_html__( '- Label in the box: a separate return label is created at the same time as the label for the outward shipment and can be included in the box.', 'postnl-for-woocommerce' ),

				'options'     => array(
					'none'   => esc_html__( 'None', 'postnl-for-woocommerce' ),
					'in_box' => esc_html__( 'Label in the box', 'postnl-for-woocommerce' ),
				),
				'for_country' => array( 'NL' ),
			),
			// 'return_address_default'         => array(
			// 'title'       => esc_html__( 'Always print returnlabel together with shipping label', 'postnl-for-woocommerce' ),
			// 'type'        => 'checkbox',
			// 'description' => esc_html__( 'With this setting enabled, the return-label of a shipment will automatically be downloaded and printed when the shipping label created.', 'postnl-for-woocommerce' ),
			// 'desc_tip'    => true,
			// 'default'     => '',
			// 'label'       => esc_html__( 'Enable', 'postnl-for-woocommerce' ),
			// 'placeholder' => '',
			// ),
			'return_shipment_and_labels_all'  => array(
				'title'       => esc_html__( 'Directly activate return function for all labels', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'label'       => esc_html__( 'Enable', 'postnl-for-woocommerce' ),
				// 'description' => esc_html__( 'Tick this box if you want all labels to be activated for returning immediately. If you do not tick this box the return function can be activated on an order-by-order basis.', 'postnl-for-woocommerce' ),
				'options'     => array(
					'yes' => esc_html__( 'Yes, activate return function directly for all orders', 'postnl-for-woocommerce' ),
					'no'  => esc_html__( 'No, activate return function per individual order', 'postnl-for-woocommerce' ),
				),
				'for_country' => array( 'NL' ),
			),
			'activate_smart_return'           => array(
				'title'       => esc_html__( 'Activate Smart Return', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'default'     => '',
				'label'       => esc_html__( 'Activate', 'postnl-for-woocommerce' ),
				'placeholder' => '',
			),
			'return_address_or_reply_no'      => array(
				'title'       => esc_html__( 'Return to home address', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => esc_html__( 'Activate', 'postnl-for-woocommerce' ),
				'description' => esc_html__( 'Activate this setting to use a home address for return shipments', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'return_replynumber'              => array(
				'title'       => esc_html__( 'Replynumber', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter replynumber.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'for_country' => array( 'NL' ),
				'class'       => 'country-nl',
			),
			'freepost_zip'                    => array(
				'title'       => esc_html__( 'Freepost Zipcode', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter Freepost Zipcode.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'freepost_city'                   => array(
				'title'       => esc_html__( 'Freepost City', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter Freepost City.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'return_address_street'           => array(
				'title'       => esc_html__( 'Street Address', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter Return Street Address.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'return_address_house_no'         => array(
				'title'       => esc_html__( 'House Number', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter return house number.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'return_address_house_noext'      => array(
				'title'       => esc_html__( 'House Number Extension', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter return house number extension.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'return_address_zip'              => array(
				'title'       => esc_html__( 'Zipcode', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter Return Zipcode.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'return_address_city'             => array(
				'title'       => esc_html__( 'City', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Enter Return City.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			'return_customer_code'            => array(
				'title'       => esc_html__( 'Return Customer Code', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Be aware that the Return Customer Code differs from the regular Customer Code. You can find your Return customer code in Mijn PostNL.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
			),
			// Delivery Options Settings.
			'delivery_options_title'          => array(
				'title'       => esc_html__( 'Checkout Settings', 'postnl-for-woocommerce' ),
				'type'        => 'title',
				'description' => esc_html__( 'Please configure your checkout preferences.', 'postnl-for-woocommerce' ),
			),
			'supported_shipping_methods'      => array(
				'title'       => esc_html__( 'Shipping Methods', 'postnl-for-woocommerce' ),
				'type'        => 'multiselect',
				'description' => esc_html__( 'Select Shipping Methods can be associated with PostNL.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'options'     => $this->get_shipping_methods(),
				'class'       => 'wc-enhanced-select',
			),
			'letterbox_24_fee'                => array(
				'title'       => esc_html__( 'Extra fee for the letterboxparcel (24 hours)', 'postnl-for-woocommerce' ),
				'type'        => 'price',
				'description' => esc_html__( 'Extra fee added when Letterboxparcel Standard (24 hours) has been selected.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL' ),
				'class'       => 'wc_input_price country-nl',
			),
			'letterbox_fee'                   => array(
				'title'       => __( 'Letterbox fee', 'postnl-for-woocommerce' ),
				'type'        => 'price',
				'description' => __( 'Overrides the shipping cost when all items are eligible for letterbox delivery. Leave empty to use the standard shipping cost. The fee is set to €0 when free shipping applies.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL' ),
				'class'       => 'wc_input_price country-nl',
			),
			'enable_pickup_points'            => array(
				'title'       => __( 'PostNL Pick-up Points', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Enable', 'postnl-for-woocommerce' ),
				'description' => __( 'Show PostNL pick-up points in the checkout so that your customers can choose to get their orders delivered at a PostNL pick-up point.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => 'yes',
				'for_country' => array( 'NL', 'BE' ),
				'class'       => 'country-nl country-be',
			),
			'pickup_delivery_fee'             => array(
				'title'       => __( 'Extra fee pick-up delivery', 'postnl-for-woocommerce' ),
				'type'        => 'price',
				'description' => __( 'Extra fee added when the customer selects a PostNL pick-up point.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL', 'BE' ),
				'class'       => 'wc_input_price country-nl country-be',
			),
			/*
			Temporarily commented out.
			'number_pickup_points'      => array(
				'title'             => __( 'Number of Pickup Points', 'postnl-for-woocommerce' ),
				'type'              => 'number',
				'description'       => __( 'Number of pickup points displayed in the frontend. Maximum will be 20.', 'postnl-for-woocommerce' ),
				'desc_tip'          => true,
				'class'             => '',
				'default'           => '10',
				'custom_attributes' => array(
					'min' => '1',
					'max' => '20',
				),
				'for_country'       => array( 'NL', 'BE' ),
				'class'             => 'country-nl country-be',
			),
			*/

			'enable_delivery_days'            => array(
				'title'       => __( 'Delivery', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Enable', 'postnl-for-woocommerce' ),
				'description' => __( 'Show delivery days in the checkout so that your customers can choose which day to receive their order.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'for_country' => array( 'NL' ),
				'class'       => 'country-nl',
			),
			'delivery_days_fee'               => array(
				'title'       => __( 'Extra fee home delivery', 'postnl-for-woocommerce' ),
				'type'        => 'price',
				'description' => __( 'Extra fee added when the customer selects home delivery.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL', 'BE' ),
				'class'       => 'wc_input_price country-nl country-be',
			),
			'number_delivery_days'            => array(
				'title'             => __( 'Number of Delivery Days', 'postnl-for-woocommerce' ),
				'type'              => 'number',
				'description'       => __( 'Number of delivery days displayed in the frontend. Maximum will be 12.', 'postnl-for-woocommerce' ),
				'desc_tip'          => true,
				'default'           => '10',
				'for_country'       => array( 'NL' ),
				'custom_attributes' => array(
					'min' => '1',
					'max' => '12',
				),
				'class'             => 'country-nl',
			),
			'enable_morning_delivery'         => array(
				'title'       => __( 'Morning Delivery', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Enable', 'postnl-for-woocommerce' ),
				'description' => __( 'Enable morning delivery in the checkout so your customers can choose to receive their orders in the morning.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'for_country' => array( 'NL' ),
				'class'       => 'country-nl',
			),
			'morning_delivery_fee'            => array(
				'title'       => __( 'Morning Delivery Fee', 'postnl-for-woocommerce' ),
				'type'        => 'price',
				'description' => __( 'Fee for receiving orders in the morning.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL' ),
				'class'       => 'wc_input_price country-nl',
			),
			'enable_evening_delivery'         => array(
				'title'       => __( 'Evening Delivery', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Enable', 'postnl-for-woocommerce' ),
				'description' => __( 'Enable evening delivery in the checkout so your customers can choose to receive their orders in the evening.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'for_country' => array( 'NL' ),
				'class'       => 'country-nl',
			),
			'evening_delivery_fee'            => array(
				'title'       => __( 'Evening Delivery Fee', 'postnl-for-woocommerce' ),
				'type'        => 'price',
				'description' => __( 'Fee for receiving orders in the evening.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL' ),
				'class'       => 'wc_input_price country-nl',
			),
			'default_checkout_tab'            => array(
				'title'       => __( 'Default Delivery Options Tab', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Choose which tab is shown first in the delivery options menu at checkout.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => 'delivery_day',
				'options'     => array(
					'delivery_day'   => __( 'Home Delivery', 'postnl-for-woocommerce' ),
					'dropoff_points' => __( 'Pickup Points', 'postnl-for-woocommerce' ),
				),
				'for_country' => array( 'NL', 'BE' ),
				'class'       => 'country-nl country-be',
			),
			'transit_time'                    => array(
				'title'       => esc_html__( 'Transit Time', 'postnl-for-woocommerce' ),
				'type'        => 'number',
				'description' => esc_html__( 'The number of days it takes for the order to be delivered after the order has been placed.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '1',
				'placeholder' => '',
			),
			'cut_off_time'                    => array(
				'title'       => esc_html__( 'Cut Off Time', 'postnl-for-woocommerce' ),
				'type'        => 'time',
				'description' => esc_html__( 'If an order is ordered after this time, one day will be added to the transit time.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '18:00',
				'placeholder' => '',
			),
			'dropoff_day_mon'                 => array(
				'title'       => __( 'Drop off Days', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Monday', 'postnl-for-woocommerce' ),
				'description' => __( 'Select which days orders will be shipped.', 'postnl-for-woocommerce' ),
				'default'     => 'yes',
				'desc_tip'    => true,
			),
			'dropoff_day_tue'                 => array(
				'type'    => 'checkbox',
				'label'   => __( 'Tuesday', 'postnl-for-woocommerce' ),
				'default' => 'yes',
			),
			'dropoff_day_wed'                 => array(
				'type'    => 'checkbox',
				'label'   => __( 'Wednesday', 'postnl-for-woocommerce' ),
				'default' => 'yes',
			),
			'dropoff_day_thu'                 => array(
				'type'    => 'checkbox',
				'label'   => __( 'Thursday', 'postnl-for-woocommerce' ),
				'default' => 'yes',
			),
			'dropoff_day_fri'                 => array(
				'type'    => 'checkbox',
				'label'   => __( 'Friday', 'postnl-for-woocommerce' ),
				'default' => 'yes',
			),
			'dropoff_day_sat'                 => array(
				'type'    => 'checkbox',
				'label'   => __( 'Saturday', 'postnl-for-woocommerce' ),
				'default' => 'yes',
			),
			'dropoff_day_sun'                 => array(
				'type'  => 'checkbox',
				'label' => __( 'Sunday', 'postnl-for-woocommerce' ),
			),
			'validate_nl_address'             => array(
				'title'       => __( 'Validate Dutch addresses', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Enable', 'postnl-for-woocommerce' ),
				'description' => __( 'Based on zipcode and housenumber combination the address is checked.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => 'yes',
			),
			'reorder_nl_address'              => array(
				'title'       => __( 'Use PostNL address-field', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Enable', 'postnl-for-woocommerce' ),
				'description' => __( 'For zipcode, housenumber, housenumber extension and street separate address fields are displayed when this settings is enabled. This only applies for Dutch addresses.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => 'yes',
			),

			// Shipping Outside Europe Settings.
			'shipping_outside_eu_title'       => array(
				'title'       => esc_html__( 'Shipping Outside Europe Settings', 'postnl-for-woocommerce' ),
				'type'        => 'title',
				'description' => esc_html__( 'Please insert your Parcels non-EU credentials.', 'postnl-for-woocommerce' ),
			),
			'globalpack_barcode_type'         => array(
				'title'             => esc_html__( 'Parcels non-EU Barcode Type', 'postnl-for-woocommerce' ),
				'type'              => 'text',
				'description'       => '',
				'desc_tip'          => true,
				'default'           => '',
				'placeholder'       => esc_html__( 'CD', 'postnl-for-woocommerce' ),
				'custom_attributes' => array( 'maxlength' => '10' ),
			),
			'globalpack_customer_code'        => array(
				'title'             => esc_html__( 'Parcels non-EU Customer Code', 'postnl-for-woocommerce' ),
				'type'              => 'text',
				'description'       => '',
				'desc_tip'          => true,
				'default'           => '',
				'placeholder'       => esc_html__( '1234', 'postnl-for-woocommerce' ),
				'custom_attributes' => array( 'maxlength' => '10' ),
			),
			'hs_tariff_code'                  => array(
				'title'       => esc_html__( 'Default HS Tariff Code', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'The HS tariff code is used by customs to classify goods. The HS tariff code can be found on the website of the Dutch Chamber of Commerce.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'placeholder' => '',
			),
			'country_origin'                  => array(
				'title'       => esc_html__( 'Default Country of Origin', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => esc_html__( 'Default country of origin is used by customs.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => Utils::get_base_country(),
				'options'     => WC()->countries->get_countries(),
				'placeholder' => '',
			),
			'merchant_codes_repeater'         => array(
				'title'       => esc_html__( 'Merchant Customs Code', 'postnl-for-woocommerce' ),
				'type'        => 'repeater',
				'description' => esc_html__( 'Add merchant codes for specific non-EU countries.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'for_country' => array( 'NL', 'BE' ),

			),

			'printer_email_title'             => array(
				'title'       => esc_html__( 'Printer &amp; Email Settings', 'postnl-for-woocommerce' ),
				'type'        => 'title',
				'description' => esc_html__( 'Please configure your printer and email preferences.', 'postnl-for-woocommerce' ),
			),
			'printer_type'                    => array(
				'title'       => esc_html__( 'Printer Type', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => esc_html__( 'It is not recommended to send .pdf files/labels directly to a Zebra printer If you want to send it directly to your Zebra printer, please use .gif files or the native (generic) zpl printer type', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => 'PDF',
				'options'     => array(
					'PDF' => 'PDF',
					'GIF' => 'GIF',
					'JPG' => 'JPG',
					'ZPL' => 'ZPL',
				),
			),
			'printer_type_resolution'         => array(
				'title'   => esc_html__( 'DPI', 'postnl-for-woocommerce' ),
				'type'    => 'select',
				'default' => '600',
				'options' => array(
					'600' => '600',
					'300' => '300',
					'200' => '200',
				),
			),
			'label_format'                    => array(
				'title'       => esc_html__( 'Label Format', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => esc_html__( 'Use A6 format in case you use a labelprinter. Use A4 format for other regular printers.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => 'A6',
				'options'     => array(
					'A6' => 'A6',
					'A4' => 'A4',
				),
				'class'       => 'wc-enhanced-select',
			),
			'shipping_confirmation_email'     => array(
				'title'       => esc_html__( 'Shipping confirmation e-mail address', 'postnl-for-woocommerce' ),
				'type'        => 'email',
				'description' => esc_html__( 'This e-mail address will be used by PostNL for shipping confirmations. If left empty, no sender e-mail will be included.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'woocommerce_email'               => array(
				'title'       => esc_html__( 'WooCommerce Email', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => esc_html__( 'When PostNL label is created send email to customer.', 'postnl-for-woocommerce' ),
				'description' => esc_html__( 'When PostNL label is created send email to customer.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'placeholder' => '',
			),
			'woocommerce_email_text'          => array(
				'title'       => esc_html__( 'WooCommerce Email Text', 'postnl-for-woocommerce' ),
				'type'        => 'text',
				'description' => esc_html__( 'Text added for tracking note email.', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => esc_html__( 'This is your track and track link {tracking-link}', 'postnl-for-woocommerce' ),
				'placeholder' => esc_html__( 'This is your track and track link {tracking-link}', 'postnl-for-woocommerce' ),
			),
			// Default shipping Options Settings.
			'default_shipping_options_title'  => array(
				'title'       => esc_html__( 'Default shipping Options Settings', 'postnl-for-woocommerce' ),
				'type'        => 'title',
				'description' => esc_html__( 'Please select Default shipping Options.', 'postnl-for-woocommerce' ),
				'for_country' => array( 'NL' ),
			),
			'default_shipping_options_nl'     => array(
				'title'       => __( 'Shipping options domestic', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Select a default shipping option for domestic orders that are shipped with PostNL.', 'postnl-for-woocommerce' ),
				'default'     => 'standard_shipment',
				'for_country' => array( 'NL' ),
				'options'     => array(
					'standard_shipment'                  => __( 'Standard shipment', 'postnl-for-woocommerce' ),
					'id_check'                           => __( 'ID Check (18+)', 'postnl-for-woocommerce' ),
					'id_check|insured_shipping'          => __( 'ID Check (18+) + Insured Shipping', 'postnl-for-woocommerce' ),
					// 'insured_shipping'                                         => __( 'Insured Shipping', 'postnl-for-woocommerce' ),
					'return_no_answer'                   => __( 'Return if no answer', 'postnl-for-woocommerce' ),
					'signature_on_delivery'              => __( 'Signature on Delivery', 'postnl-for-woocommerce' ),
					'only_home_address'                  => __( 'Only Home Address', 'postnl-for-woocommerce' ),
					'letterbox'                          => __( 'Letterboxparcel Standard (24 hours)', 'postnl-for-woocommerce' ),
					'letterbox_48'                       => __( 'Letterboxparcel 48 hours', 'postnl-for-woocommerce' ),
					'signature_on_delivery|insured_shipping' => __( 'Signature on Delivery + Insured Shipping', 'postnl-for-woocommerce' ),
					'signature_on_delivery|return_no_answer' => __( 'Signature on Delivery + Return if no answer', 'postnl-for-woocommerce' ),
					'insured_shipping|return_no_answer|signature_on_delivery' => __( 'Insured Shipping + Return if no answer + Signature on Delivery', 'postnl-for-woocommerce' ),
					'only_home_address|return_no_answer' => __( 'Only Home Address + Return if no answer', 'postnl-for-woocommerce' ),
					'only_home_address|return_no_answer|signature_on_delivery' => __( 'Only Home Address + Return if no answer + Signature on Delivery', 'postnl-for-woocommerce' ),
					'only_home_address|signature_on_delivery' => __( 'Only Home Address + Signature on Delivery', 'postnl-for-woocommerce' ),
					'delivery_code_at_door|insured_shipping'  => esc_html__( 'Delivery Code at Door + Insured Shipping', 'postnl-for-woocommerce' ),
				),
			),
			'default_shipping_options_be'     => array(
				'title'       => __( 'Shipping options Belgium', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Select a default shipping option for the orders shipped to Belgium with PostNL.', 'postnl-for-woocommerce' ),
				'default'     => 'standard_belgium',
				'for_country' => array( 'NL' ),
				'options'     => array(
					'standard_belgium'                   => __( 'Standard Shipment Belgium', 'postnl-for-woocommerce' ),
					'standard_belgium|only_home_address' => __( 'Standard Shipment Belgium + Only Home Address', 'postnl-for-woocommerce' ),
					'standard_belgium|signature_on_delivery' => __( 'Standard Shipment Belgium + Signature on Delivery', 'postnl-for-woocommerce' ),
					'standard_belgium|insured_shipping'  => __( 'Standard Shipment Belgium + Insured Shipping', 'postnl-for-woocommerce' ),
					'mailboxpacket'                      => __( 'Boxable Packet', 'postnl-for-woocommerce' ),
					'mailboxpacket|track_and_trace'      => __( 'Boxable Packet + Track & Trace', 'postnl-for-woocommerce' ),
					'packets'                            => __( 'Packets', 'postnl-for-woocommerce' ),
					'packets|track_and_trace'            => __( 'Packets + Track & Trace', 'postnl-for-woocommerce' ),
					'packets|track_and_trace|insured_shipping' => __( 'Packets + Track & Trace + Insured', 'postnl-for-woocommerce' ),
				),
			),
			'default_shipping_options_eu'     => array(
				'title'       => __( 'Shipping options EU', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Select a default shipping option for the orders shipped within European Union zone.', 'postnl-for-woocommerce' ),
				'default'     => 'eu_parcel|track_and_trace',
				'for_country' => array( 'NL' ),
				'options'     => array(
					'eu_parcel|track_and_trace'     => __( 'EU Parcel + Track & Trace', 'postnl-for-woocommerce' ),
					'eu_parcel|track_and_trace|insured_shipping' => __( 'EU Parcel + Track & Trace + Insured', 'postnl-for-woocommerce' ),
					'eu_parcel|track_and_trace|insured_plus' => __( 'EU Parcel + Track & Trace + Insured Plus', 'postnl-for-woocommerce' ),
					'mailboxpacket'                 => __( 'Boxable Packet', 'postnl-for-woocommerce' ),
					'mailboxpacket|track_and_trace' => __( 'Boxable Packet + Track & Trace', 'postnl-for-woocommerce' ),
					'packets'                       => __( 'Packets', 'postnl-for-woocommerce' ),
					'packets|track_and_trace'       => __( 'Packets + Track & Trace', 'postnl-for-woocommerce' ),
					'packets|track_and_trace|insured_shipping' => __( 'Packets + Track & Trace + Insured', 'postnl-for-woocommerce' ),
				),
			),
			'default_shipping_options_row'    => array(
				'title'       => __( 'Default Shipping International', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Shipping options non-EU (outside the EU borders).', 'postnl-for-woocommerce' ),
				'default'     => 'parcel_non_eu|track_and_trace',
				'for_country' => array( 'NL' ),
				'options'     => array(
					'parcel_non_eu|track_and_trace' => __( 'Parcel non-EU + Track & Trace', 'postnl-for-woocommerce' ),
					'parcel_non_eu|track_and_trace|insured_shipping' => __( 'Parcel non-EU + Track & Trace + Insured', 'postnl-for-woocommerce' ),
					'parcel_non_eu|track_and_trace|insured_plus' => __( 'Parcel non-EU + Track & Trace + Insured Plus', 'postnl-for-woocommerce' ),
					'mailboxpacket'                 => __( 'Boxable Packet', 'postnl-for-woocommerce' ),
					'mailboxpacket|track_and_trace' => __( 'Boxable Packet + Track & Trace', 'postnl-for-woocommerce' ),
					'packets'                       => __( 'Packets', 'postnl-for-woocommerce' ),
					'packets|track_and_trace'       => __( 'Packets + Track & Trace', 'postnl-for-woocommerce' ),
					'packets|track_and_trace|insured_shipping' => __( 'Packets + Track & Trace + Insured', 'postnl-for-woocommerce' ),
				),
			),
			'default_shipping_options_pickup' => array(
				'title'       => __( 'Default Shipping Pickup', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Shipping options Pickup.', 'postnl-for-woocommerce' ),
				'default'     => 'id_check',
				'for_country' => array( 'NL' ),
				'options'     => array(
					''                          => esc_html__( 'Standard Shipping', 'postnl-for-woocommerce' ),
					'id_check'                  => esc_html__( 'ID Check (18+)', 'postnl-for-woocommerce' ),
					'insured_shipping'          => esc_html__( 'Insured Shipping', 'postnl-for-woocommerce' ),
					'id_check|insured_shipping' => esc_html__( 'ID Check (18+) + Insured Shipping', 'postnl-for-woocommerce' ),
				),
			),
			'default_automatic_letterboxparcel_product' => array(
				'title'       => esc_html__( 'Default automatic letterboxparcel product', 'postnl-for-woocommerce' ),
				'type'        => 'select',
				'description' => '',
				'default'     => 'letterbox',
				'for_country' => array( 'NL' ),
				'options'     => array(
					'letterbox'       => esc_html__( 'Letterboxparcel Standard (24 hours)', 'postnl-for-woocommerce' ),
					'letterbox_48'    => esc_html__( 'Letterboxparcel 48 hours', 'postnl-for-woocommerce' ),
					'customer_decide' => esc_html__( 'Let customer decide', 'postnl-for-woocommerce' ),
				),
			),
			'auto_complete_order'             => array(
				'title'       => esc_html__( 'Automatically change order status to Completed', 'postnl-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => esc_html__( 'Automatically change order status to Completed once an order has been pre-alerted and printed', 'postnl-for-woocommerce' ),
				'description' => esc_html__( 'Automatically change order status to Completed once an order has been pre-alerted and printed', 'postnl-for-woocommerce' ),
				'desc_tip'    => true,
				'default'     => '',
				'placeholder' => '',
			),

		);

		// The legacy key fields are shown only when a key is already stored: a
		// fresh install enters its key in the new "API Key" field alone. The
		// decision is made on the saved value (not the posted one) so a failed
		// save does not make the field flicker in and out. Reading the raw option
		// directly avoids recursing through get_country_option()/filter_setting_fields().
		if ( '' === trim( (string) $this->get_option( 'api_keys' ) ) ) {
			unset( $fields['api_keys'] );
		}

		if ( '' === trim( (string) $this->get_option( 'api_keys_sandbox' ) ) ) {
			unset( $fields['api_keys_sandbox'] );
		}

		return $fields;
	}

	/**
	 * Filter the setting fields based on store country.
	 *
	 * @param String $country Two characters country code.
	 * @param bool   $only_field_country Flag to check if it only return for the field with 'for_country' array exists.
	 *
	 * @return array
	 */
	public function filter_setting_fields( $country, $only_field_country = false, $settings = false ) {
		$setting_fields = $this->get_setting_fields();
		if ( $country == 'BE' && ! $settings ) {
			$setting_fields['default_shipping_options_title'] =
				array(
					'title'       => esc_html__( 'Default shipping Options Settings', 'postnl-for-woocommerce' ),
					'type'        => 'title',
					'description' => esc_html__( 'Please select Default shipping Options.', 'postnl-for-woocommerce' ),
					'for_country' => array( 'BE' ),
				);

			$setting_fields['default_shipping_options_row'] =
				array(
					'title'       => __( 'Default Shipping International', 'postnl-for-woocommerce' ),
					'type'        => 'select',
					'description' => __( 'Select a default shipping option for the orders shipped internationally (outside the EU borders).', 'postnl-for-woocommerce' ),
					'default'     => 'parcel_non_eu|track_and_trace|insured_plus',
					'for_country' => array( 'BE' ),
					'options'     => array(
						'parcel_non_eu|track_and_trace|insured_plus' => __( 'Parcel non-EU + Track & Trace + Insured Plus', 'postnl-for-woocommerce' ),
					),
				);
		}
		$country_fields = array_filter(
			$setting_fields,
			function ( $field ) use ( $country, $only_field_country ) {
				if ( empty( $field['for_country'] ) && false === $only_field_country ) {
					return true;
				}

				if ( ! empty( $field['for_country'] ) && is_array( $field['for_country'] ) && in_array( $country, $field['for_country'], true ) ) {
					return true;
				}

				if ( ! empty( $field['for_country'] ) && $field['for_country'] === $country ) {
					return true;
				}

				return false;
			}
		);

		return $country_fields;
	}

	/**
	 * Return NL setting fields only.
	 *
	 * @param bool $only_field_country Flag to check if it only return for the field with 'for_country' array exists.
	 *
	 * @return array
	 */
	public function nl_setting_fields( $only_field_country = false ) {
		return $this->filter_setting_fields( 'NL', $only_field_country );
	}

	/**
	 * Return BE setting fields only.
	 *
	 * @param bool $only_field_country Flag to check if it only return for the field with 'for_country' array exists.
	 *
	 * @return array
	 */
	public function be_setting_fields( $only_field_country = false ) {
		return $this->filter_setting_fields( 'BE', $only_field_country, true );
	}

	/**
	 * Get setting option value based on country.
	 *
	 * @param String $field Field name.
	 * @param String $default_value Default value if the field value is empty.
	 *
	 * @return String
	 */
	public function get_country_option( $field, $default_value = '' ) {
		$base_country   = Utils::get_base_country();
		$fields_country = array_keys( $this->filter_setting_fields( $base_country, false ) );

		return in_array( $field, $fields_country, true ) ? $this->get_option( $field, $default_value ) : '';
	}

	/**
	 * Get API Key from the settings.
	 *
	 * @return String
	 */
	public function get_api_key() {
		return $this->get_country_option( 'api_keys', '' );
	}

	/**
	 * Get sandbox API Key from the settings.
	 *
	 * @return String
	 */
	public function get_api_key_sandbox() {
		return $this->get_country_option( 'api_keys_sandbox', '' );
	}

	/**
	 * Option storing the SHA-256 hash of the new API key value that last
	 * passed validation. Storing a hash (rather than a global yes/no flag)
	 * binds the validated state to the exact key value, so any out-of-band
	 * edit or partial save naturally invalidates the flag.
	 */
	const NEW_API_KEY_VALIDATED_HASH_OPTION = 'postnl_api_keys_new_validated_hash';

	/**
	 * Get the raw value of the new sandbox API key as entered by the merchant.
	 *
	 * @return string
	 */
	public function get_api_key_sandbox_new() {
		return trim( (string) $this->get_country_option( 'api_keys_sandbox_new', '' ) );
	}

	/**
	 * Get the raw value of the new API key for the current environment.
	 *
	 * PostNL issues environment-scoped keys, so sandbox and production each have
	 * their own new-key field. Returning the field that matches the active
	 * environment keeps every V4 consumer (Service_Factory, the adoption header,
	 * the effective-key fallback) pointed at the right key without each caller
	 * having to branch on the environment itself.
	 *
	 * @return string
	 */
	public function get_api_key_new() {
		if ( $this->is_sandbox() ) {
			return $this->get_api_key_sandbox_new();
		}

		return trim( (string) $this->get_country_option( 'api_keys_new', '' ) );
	}

	/**
	 * The original (pre-migration) API key for the current environment.
	 *
	 * @return string
	 */
	public function get_original_api_key() {
		return $this->is_sandbox()
			? trim( (string) $this->get_api_key_sandbox() )
			: trim( (string) $this->get_api_key() );
	}

	/**
	 * Name of the option storing the validated-key hash for a given environment.
	 *
	 * The validated flag is environment-scoped: a key validated in production must
	 * not be treated as validated in sandbox (and vice versa), otherwise the V4
	 * gate would route a production key against the sandbox host, or the reverse.
	 * A single option cannot hold both, since validating one environment would
	 * overwrite the other, so each environment gets its own option.
	 *
	 * @param bool|null $is_sandbox Environment to scope to, or null for the current one.
	 *
	 * @return string
	 */
	protected function validated_hash_option_name( $is_sandbox = null ) {
		$is_sandbox = ( null === $is_sandbox ) ? $this->is_sandbox() : (bool) $is_sandbox;

		return self::NEW_API_KEY_VALIDATED_HASH_OPTION . ( $is_sandbox ? '_sandbox' : '' );
	}

	/**
	 * Whether the currently-entered new API key matches the key that last
	 * passed validation against the PostNL API for the current environment.
	 *
	 * @return bool
	 */
	public function is_api_key_new_validated() {
		return $this->is_api_key_new_validated_value( $this->get_api_key_new() );
	}

	/**
	 * Whether a specific key value matches the key that last passed
	 * validation. Takes the value explicitly so callers (e.g. the save-time
	 * handler) can check the freshly-entered key without relying on the
	 * settings object's in-memory cache being up to date.
	 *
	 * @param string    $key        Candidate key value.
	 * @param bool|null $is_sandbox Environment to check, or null for the current one.
	 *
	 * @return bool
	 */
	public function is_api_key_new_validated_value( $key, $is_sandbox = null ) {
		$key = trim( (string) $key );
		if ( '' === $key ) {
			return false;
		}

		$stored = (string) get_option( $this->validated_hash_option_name( $is_sandbox ), '' );
		if ( '' === $stored ) {
			return false;
		}

		return hash_equals( $stored, hash( 'sha256', $key ) );
	}

	/**
	 * Record that the currently-entered new API key has passed validation,
	 * or clear the flag entirely. The hash binds the flag to the exact key
	 * value the merchant just successfully tested, scoped to its environment.
	 *
	 * @param bool        $validated  Validation outcome.
	 * @param string|null $key        The exact key value that was validated. When
	 *                                omitted, falls back to the stored setting —
	 *                                but callers running mid-save should pass the
	 *                                freshly-entered value to avoid hashing a
	 *                                stale cached value.
	 * @param bool|null   $is_sandbox Environment to scope to, or null for the current one.
	 */
	public function set_api_key_new_validated( $validated, $key = null, $is_sandbox = null ) {
		$option = $this->validated_hash_option_name( $is_sandbox );

		if ( ! $validated ) {
			delete_option( $option );
			return;
		}

		$key = trim( (string) ( null === $key ? $this->get_api_key_new() : $key ) );
		if ( '' === $key ) {
			delete_option( $option );
			return;
		}

		update_option( $option, hash( 'sha256', $key ) );
	}

	/**
	 * Return the API key the plugin should actually send to PostNL for the
	 * current environment. Falls back to the original key whenever the new
	 * key is empty, identical, or has not been validated.
	 *
	 * @return string
	 */
	public function get_effective_api_key() {
		$original = $this->get_original_api_key();
		$new_key  = $this->get_api_key_new();

		if ( '' === $new_key ) {
			return $original;
		}

		if ( $new_key === $original ) {
			return $original;
		}

		if ( ! $this->is_api_key_new_validated() ) {
			return $original;
		}

		return $new_key;
	}

	/**
	 * Option storing the reason the new key last failed validation, so the
	 * settings status row can tell "key rejected" apart from "could not reach
	 * PostNL" or "customer details missing" — all of which report the same
	 * "Entered" header value. Only consulted when the header value is "Entered".
	 */
	const NEW_API_KEY_STATUS_OPTION = 'postnl_api_keys_new_status';

	/**
	 * Map the new-key state to its NewKey header value. Kept as one pure method
	 * so the outgoing header and the settings status row can never disagree.
	 *
	 *  - "No"      : the new-key field is empty.
	 *  - "Same"    : the new-key field matches the original key.
	 *  - "Entered" : a distinct key was entered but has not passed validation.
	 *  - "Yes"     : a distinct new key has been entered and validated.
	 *
	 * "Yes" is gated on validation because PostNL defines it as a key that
	 * "works"; a key that failed our validation reports "Entered" so PostNL does
	 * not count the merchant as ready to migrate.
	 *
	 * @param string $new_key   The entered new key.
	 * @param string $original  The original (pre-migration) key.
	 * @param bool   $validated Whether the new key passed validation.
	 *
	 * @return string
	 */
	protected function derive_new_key_header_value( $new_key, $original, $validated ) {
		if ( '' === $new_key ) {
			return 'No';
		}

		if ( $new_key === $original ) {
			return 'Same';
		}

		if ( ! $validated ) {
			return 'Entered';
		}

		return 'Yes';
	}

	/**
	 * Value for the NewKey header sent on every outgoing API call, computed for
	 * the current environment.
	 *
	 * @return string
	 */
	public function get_new_key_header_value() {
		return $this->derive_new_key_header_value(
			$this->get_api_key_new(),
			$this->get_original_api_key(),
			$this->is_api_key_new_validated()
		);
	}

	/**
	 * Persist (or clear) the reason the new key last failed validation, scoped
	 * to the given environment.
	 *
	 * @param string    $reason     One of 'invalid', 'rejected', 'unreachable', 'missing', or '' to clear.
	 * @param bool|null $is_sandbox Environment to scope to, or null for the current one.
	 */
	public function set_new_key_status_reason( $reason, $is_sandbox = null ) {
		$option = self::NEW_API_KEY_STATUS_OPTION . ( $this->resolve_is_sandbox( $is_sandbox ) ? '_sandbox' : '' );

		if ( '' === $reason ) {
			delete_option( $option );
			return;
		}

		update_option( $option, $reason );
	}

	/**
	 * PostNL developer portal page for the API migration. It explains how to
	 * upgrade PHP, how to request a new API key via the Self Service (SSAM)
	 * module, and when to update the plug-in for API v4. Confirmed by PostNL as
	 * the destination for the migration banners (in place of the Self Service
	 * portal directly), so customers get the full step-by-step instructions first.
	 */
	const SELF_SERVICE_URL = 'https://developer.postnl.nl/integration-with-postnl/api-overview/future-proof-api-s/plug-ins/';

	/**
	 * Link to the PostNL Business Portal Self Service module, reused across the
	 * status row and the migration banner.
	 *
	 * @return string
	 */
	public function self_service_link() {
		return sprintf(
			'<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
			esc_url( self::SELF_SERVICE_URL ),
			esc_html__( 'Self Service module on the PostNL Business Portal', 'postnl-for-woocommerce' )
		);
	}

	/**
	 * Resolve the status of the new key for a given environment: the header value
	 * plus a colour, label, a one-line summary and a "what to do next" paragraph
	 * for the settings status row. The label and colour derive from the same
	 * header value the API calls send, so the screen and PostNL's adoption count
	 * can never contradict each other.
	 *
	 * @param bool|null $is_sandbox Environment to describe, or null for the current one.
	 *
	 * @return array{header:string,label:string,color:string,summary:string,description:string}
	 */
	public function get_new_key_status( $is_sandbox = null ) {
		$is_sandbox = $this->resolve_is_sandbox( $is_sandbox );

		$new_key   = $is_sandbox ? $this->get_api_key_sandbox_new() : trim( (string) $this->get_country_option( 'api_keys_new', '' ) );
		$original  = $is_sandbox ? trim( (string) $this->get_api_key_sandbox() ) : trim( (string) $this->get_api_key() );
		$validated = $this->is_api_key_new_validated_value( $new_key, $is_sandbox );

		// The rendered row describes what is actually stored, so the validated
		// state it shows is a saved one.
		return $this->build_new_key_status( $new_key, $original, $validated, $is_sandbox, true, $this->resolve_new_key_status_reason( $is_sandbox ) );
	}

	/**
	 * Map a new-key state to the status row's colour, label, one-line summary and
	 * "what to do next" paragraph. Pure: every input is passed in, so the settings
	 * render path and the on-blur endpoint produce identical copy for the same
	 * state and cannot drift. The label and colour follow the same header value
	 * the API calls send, so the screen and PostNL's adoption count agree.
	 *
	 * @param string $new_key    The entered new key.
	 * @param string $original   The original (pre-migration) key; '' on a fresh install.
	 * @param bool   $validated  Whether the new key has passed validation.
	 * @param bool   $is_sandbox Environment being described.
	 * @param bool   $saved      Whether $validated reflects a saved state. A key that
	 *                           validates on blur but has not been saved yet gets the
	 *                           amber "works, not saved" state instead of green.
	 * @param string $reason     Persisted/derived failure reason for an entered key.
	 *
	 * @return array{header:string,label:string,color:string,summary:string,description:string}
	 */
	public function build_new_key_status( $new_key, $original, $validated, $is_sandbox, $saved, $reason = '' ) {
		unset( $is_sandbox );

		$header  = $this->derive_new_key_header_value( $new_key, $original, $validated );
		$link    = $this->self_service_link();
		$has_old = '' !== trim( (string) $original );

		switch ( $header ) {
			case 'Yes':
				if ( ! $saved ) {
					return array(
						'header'      => $header,
						'label'       => __( 'Works, not saved yet', 'postnl-for-woocommerce' ),
						'color'       => '#dba617',
						'summary'     => __( 'This key works. Save changes to start using it.', 'postnl-for-woocommerce' ),
						'description' => '',
					);
				}

				return array(
					'header'      => $header,
					'label'       => __( 'Valid', 'postnl-for-woocommerce' ),
					'color'       => '#008a20',
					'summary'     => __( 'Your API key is working and will be used for the new PostNL APIs.', 'postnl-for-woocommerce' ),
					'description' => '',
				);

			case 'Same':
				return array(
					'header'      => $header,
					'label'       => __( 'Same as old key', 'postnl-for-woocommerce' ),
					'color'       => '#dba617',
					'summary'     => __( 'This is the key you already had, not a new one.', 'postnl-for-woocommerce' ),
					// translators: %s is a link to the PostNL Business Portal Self Service module.
					'description' => sprintf( __( 'You need a separate key. Request one from the %s, then paste it into the field above.', 'postnl-for-woocommerce' ), $link ),
				);

			case 'Entered':
				return array_merge(
					array( 'header' => $header ),
					$this->get_new_key_invalid_copy( $reason, $has_old, $link )
				);

			default:
				return array(
					'header'      => $header,
					'label'       => __( 'Not set', 'postnl-for-woocommerce' ),
					'color'       => '#757575',
					'summary'     => __( 'You have not entered your API key yet.', 'postnl-for-woocommerce' ),
					'description' => $has_old
						// translators: %s is a link to the PostNL Business Portal Self Service module.
						? sprintf( __( 'Request your new key from the %s and enter it above to switch over from your old key.', 'postnl-for-woocommerce' ), $link )
						// translators: %s is a link to the PostNL Business Portal Self Service module.
						: sprintf( __( 'Request your key from the %s and enter it above — the plug-in needs it to connect to PostNL.', 'postnl-for-woocommerce' ), $link ),
				);
		}
	}

	/**
	 * The failure reason to describe in the status row. Missing customer details
	 * is decided live — if they are blank now, that is the reason whatever the
	 * last save recorded — otherwise the reason persisted at save time is used.
	 *
	 * @param bool $is_sandbox Environment to resolve for.
	 *
	 * @return string One of the Key_Validator REASON_* slugs, or ''.
	 */
	protected function resolve_new_key_status_reason( $is_sandbox ) {
		if ( '' === trim( (string) $this->get_customer_code() ) || '' === trim( (string) $this->get_customer_num() ) ) {
			return Key_Validator::REASON_MISSING;
		}

		return (string) get_option( self::NEW_API_KEY_STATUS_OPTION . ( $is_sandbox ? '_sandbox' : '' ), '' );
	}

	/**
	 * Label, colour, summary and description for an entered key that is not in
	 * use, per reason. Only a genuine rejection is red "Not valid"; an outage, a
	 * mismatch or missing details read as amber "could not check", so an outage
	 * never tells the merchant their key is invalid. Whether an old key is still
	 * carrying the plugin is passed in rather than re-read, so the copy is correct
	 * on a fresh install (where nothing is in use).
	 *
	 * @param string $reason  One of the Key_Validator REASON_* slugs.
	 * @param bool   $has_old Whether a usable old key is still stored.
	 * @param string $link    Self Service link markup.
	 *
	 * @return array{label:string,color:string,summary:string,description:string}
	 */
	protected function get_new_key_invalid_copy( $reason, $has_old, $link ) {
		$tail = $has_old
			? __( ' The plug-in is still using your old key.', 'postnl-for-woocommerce' )
			: __( ' The plug-in has no working key to connect with yet.', 'postnl-for-woocommerce' );

		switch ( $reason ) {
			case Key_Validator::REASON_REJECTED:
				return array(
					'label'       => __( 'Could not check', 'postnl-for-woocommerce' ),
					'color'       => '#dba617',
					'summary'     => __( 'PostNL could not process the check.', 'postnl-for-woocommerce' ) . $tail,
					'description' => __( 'This usually means the Customer Code or Customer Number does not match this key. Check them and save again.', 'postnl-for-woocommerce' ),
				);

			case Key_Validator::REASON_MISSING:
				return array(
					'label'       => __( 'Not checked', 'postnl-for-woocommerce' ),
					'color'       => '#dba617',
					'summary'     => __( 'We have not checked this key yet.', 'postnl-for-woocommerce' ) . $tail,
					'description' => __( 'Fill in your Customer Code and Customer Number, then save again.', 'postnl-for-woocommerce' ),
				);

			case Key_Validator::REASON_UNREACHABLE:
				return array(
					'label'       => __( 'Could not check', 'postnl-for-woocommerce' ),
					'color'       => '#dba617',
					'summary'     => __( 'We could not reach PostNL to check this key.', 'postnl-for-woocommerce' ) . $tail,
					'description' => __( 'This is usually temporary. Save again in a few minutes.', 'postnl-for-woocommerce' ),
				);

			case Key_Validator::REASON_INVALID:
			default:
				return array(
					'label'       => __( 'Not valid', 'postnl-for-woocommerce' ),
					'color'       => '#d63638',
					'summary'     => __( 'PostNL rejected this key.', 'postnl-for-woocommerce' ) . $tail,
					// translators: %s is a link to the PostNL Business Portal Self Service module.
					'description' => sprintf( __( 'Check that you copied the whole key with no extra spaces, then save again. If it keeps failing, request a new key from the %s.', 'postnl-for-woocommerce' ), $link ),
				);
		}
	}

	/**
	 * Normalise a nullable environment flag to the current environment.
	 *
	 * @param bool|null $is_sandbox Environment flag, or null for the current one.
	 *
	 * @return bool
	 */
	protected function resolve_is_sandbox( $is_sandbox ) {
		return ( null === $is_sandbox ) ? $this->is_sandbox() : (bool) $is_sandbox;
	}

	/**
	 * Get customer number from the settings.
	 *
	 * @return String
	 */
	public function get_customer_num() {
		return $this->get_country_option( 'customer_num', '' );
	}

	/**
	 * Get customer code from the settings.
	 *
	 * @return String
	 */
	public function get_customer_code() {
		return $this->get_country_option( 'customer_code', '' );
	}

	/**
	 * Get location code from the settings.
	 *
	 * @return String
	 */
	public function get_location_code() {
		/*
		Temporarily hardcoded.
		return $this->get_country_option( 'location_code', '' );
		*/

		return '123456';
	}

	/**
	 * Return true if sandbox mode is ticked.
	 *
	 * @return String
	 */
	public function get_environment_mode() {
		return $this->get_country_option( 'environment_mode', '' );
	}

	/**
	 * Return true if sandbox mode is ticked.
	 *
	 * @return Bool
	 */
	public function is_sandbox() {
		return ( 'sandbox' === $this->get_environment_mode() );
	}

	/**
	 * Get return address default from the settings.
	 *
	 * @return String
	 */
	public function get_return_address_default() {
		return $this->get_country_option( 'return_address_default', '' );
	}

	/**
	 * Get return company name from the settings.
	 *
	 * @return String
	 */
	public function get_return_company_name() {
		return $this->get_country_option( 'return_company', '' );
	}

	/**
	 * Get value of the return address or reply number.
	 *
	 * @return bool
	 */
	public function is_return_to_home_enabled() {
		if ( 'yes' === $this->get_country_option( 'return_address_or_reply_no', '' ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Get value of the return address or reply number.
	 *
	 * @return bool
	 */
	public function is_smart_return_enabled() {
		if ( 'yes' === $this->get_country_option( 'activate_smart_return', '' ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Get return reply number from the settings.
	 *
	 * @return String
	 */
	public function get_return_reply_number() {
		return $this->get_country_option( 'return_replynumber', '' );
	}

	/**
	 * Get freepost city from the settings.
	 *
	 * @return String
	 */
	public function get_freepost_city() {
		return $this->get_country_option( 'freepost_city', '' );
	}

	/**
	 * Get freepost zipcode from the settings.
	 *
	 * @return String
	 */
	public function get_freepost_zipcode() {
		return $this->get_country_option( 'freepost_zip', '' );
	}

	/**
	 * Get return street address from the settings.
	 *
	 * @return String
	 */
	public function get_return_address_street() {
		return $this->get_country_option( 'return_address_street', '' );
	}

	/**
	 * Get return house number address from the settings.
	 *
	 * @return String
	 */
	public function get_return_address_house_no() {
		return $this->get_country_option( 'return_address_house_no', '' );
	}

	/**
	 * Get return house number extension address from the settings.
	 *
	 * @return String
	 */
	public function get_return_address_house_noext() {
		return $this->get_country_option( 'return_address_house_noext', '' );
	}

	/**
	 * Get return city address from the settings.
	 *
	 * @return String
	 */
	public function get_return_city() {
		return $this->get_country_option( 'return_address_city', '' );
	}

	/**
	 * Get return state address from the settings.
	 *
	 * @return String
	 */
	public function get_return_state() {
		return $this->get_country_option( 'return_address_state', '' );
	}

	/**
	 * Get return state address from the settings.
	 *
	 * @return String
	 */
	public function get_return_zipcode() {
		return $this->get_country_option( 'return_address_zip', '' );
	}

	/**
	 * Get return phone number from the settings.
	 *
	 * @return String
	 */
	public function get_return_phone() {
		return $this->get_country_option( 'return_phone', '' );
	}

	/**
	 * Get return email from the settings.
	 *
	 * @return String
	 */
	public function get_return_email() {
		return $this->get_country_option( 'return_email', '' );
	}

	/**
	 * Get return customer code from the settings.
	 *
	 * @return String
	 */
	public function get_return_customer_code() {
		return $this->get_country_option( 'return_customer_code', '' );
	}

	/**
	 * Get return shipment and labels select value.
	 *
	 * PostNL discontinues the "Shipment & Return" label product on 1 July 2026.
	 * Any value still stored as 'shipping_return' is coerced to 'none' at read
	 * time so outbound label generation never requests the discontinued product,
	 * even on stores the one-time revert migration has not reached.
	 *
	 * @return String
	 */
	public function get_return_shipment_and_labels() {
		$value = $this->get_country_option( 'return_shipment_and_labels', '' );

		return 'shipping_return' === $value ? 'none' : $value;
	}

	/**
	 * Get value of the return shipment and labels all checkbox.
	 *
	 * @return String
	 */
	public function get_return_shipment_and_labels_all() {
		return $this->get_country_option( 'return_shipment_and_labels_all', '' );
	}

	/**
	 * Get return customer code from the settings.
	 *
	 * @return String
	 */
	public function get_return_direct_print_label() {
		return $this->get_country_option( 'return_direct_print_label', '' );
	}

	/**
	 * Return true if 'print returnlabel directly with shipping label' field is ticked.
	 *
	 * @return Bool
	 */
	public function is_return_direct_print_enabled() {
		return ( 'yes' === $this->get_return_direct_print_label() );
	}

	/**
	 * Get the letterboxparcel (24 hours) extra fee from the settings.
	 *
	 * @since 5.9.6
	 *
	 * @return float
	 */
	public function get_letterbox_24_fee() {
		return (float) $this->get_country_option( 'letterbox_24_fee' );
	}

	/**
	 * Get enable delivery from the settings.
	 *
	 * @return String
	 */
	public function get_enable_delivery() {
		return $this->get_country_option( 'enable_delivery', '' );
	}

	/**
	 * Return true if delivery field is ticked.
	 *
	 * @return Bool
	 */
	public function is_delivery_enabled() {
		return ( 'yes' === $this->get_enable_delivery() );
	}

	/**
	 * Get enable pickup points from the settings.
	 *
	 * @return String
	 */
	public function get_enable_pickup_points() {
		return $this->get_country_option( 'enable_pickup_points' );
	}

	/**
	 * Get pick-up delivery fee from the settings.
	 *
	 * @return float
	 */
	public function get_pickup_delivery_fee() {
		return (float) $this->get_country_option( 'pickup_delivery_fee' );
	}

	/**
	 * Return true if delivery days field is ticked.
	 *
	 * @return Bool
	 */
	public function is_pickup_points_enabled() {
		return ( 'yes' === $this->get_enable_pickup_points() );
	}

	/**
	 * Get number pickup points from the settings.
	 *
	 * @return Int
	 */
	public function get_number_pickup_points() {
		/*
		Temporarily hardcoded.
		return $this->get_country_option( 'number_pickup_points' );
		*/

		return 3;
	}

	/**
	 * Get enable delivery days from the settings.
	 *
	 * @return String
	 */
	public function get_enable_delivery_days() {
		return $this->get_country_option( 'enable_delivery_days' );
	}

	/**
	 * Return true if delivery days field is ticked.
	 *
	 * @return Bool
	 */
	public function is_delivery_days_enabled() {
		return ( 'yes' === $this->get_enable_delivery_days() );
	}

	/**
	 * Get delivery days fees the settings.
	 *
	 * @return float
	 */
	public function get_delivery_days_fee() {
		return (float) $this->get_country_option( 'delivery_days_fee' );
	}

	/**
	 * Get letterbox fee from the settings.
	 * Returns null when the field is empty (meaning: do not override).
	 *
	 * @return float|null
	 */
	public function get_letterbox_fee() {
		$value = $this->get_country_option( 'letterbox_fee' );
		return ( '' !== $value ) ? (float) $value : null;
	}

	/**
	 * Get number delivery days from the settings.
	 *
	 * @return Int
	 */
	public function get_number_delivery_days() {
		return $this->get_country_option( 'number_delivery_days' );
	}

	/**
	 * Get default checkout tab from the settings.
	 *
	 * @return string 'delivery_day' or 'dropoff_points'
	 */
	public function get_default_checkout_tab() {
		$value = $this->get_country_option( 'default_checkout_tab' );
		if ( in_array( $value, array( 'delivery_day', 'dropoff_points' ), true ) ) {
			return $value;
		}
		if ( 'BE' === Utils::get_base_country() ) {
			// TODO: gate on is_pickup_points_enabled(). When pickup is disabled
			// we still return 'dropoff_points' here, an id no tab list contains.
			// Container.php and the React resolver both fall back, so it's
			// harmless today, but the contract should be: never return an id
			// that can't render. See PR #306 review.
			return 'dropoff_points';
		}
		return 'delivery_day';
	}

	/**
	 * Get enable evening delivery from the settings.
	 *
	 * @return String
	 */
	public function get_enable_evening_delivery() {
		return $this->get_country_option( 'enable_evening_delivery' );
	}

	/**
	 * Return true if evening delivery field is ticked.
	 *
	 * @return Bool
	 */
	public function is_evening_delivery_enabled() {
		return ( 'yes' === $this->get_enable_evening_delivery() );
	}

	/**
	 * Get evening delivery fee from the settings.
	 *
	 * @return String
	 */
	public function get_evening_delivery_fee() {
		return $this->get_country_option( 'evening_delivery_fee' );
	}

	/**
	 * Get enable morning delivery from the settings.
	 *
	 * @return String
	 */
	public function get_enable_morning_delivery() {
		return $this->get_country_option( 'enable_morning_delivery' );
	}

	/**
	 * Return true if evening delivery field is ticked.
	 *
	 * @return Bool
	 */
	public function is_morning_delivery_enabled() {
		return ( 'yes' === $this->get_enable_morning_delivery() );
	}

	/**
	 * Get evening delivery fee from the settings.
	 *
	 * @return String
	 */
	public function get_morning_delivery_fee() {
		return $this->get_country_option( 'morning_delivery_fee' );
	}

	/**
	 * Get transit time value from the settings.
	 *
	 * @return String
	 */
	public function get_transit_time() {
		return $this->get_country_option( 'transit_time', '' );
	}

	/**
	 * Get cut off time value from the settings.
	 *
	 * @return String
	 */
	public function get_cut_off_time() {
		return $this->get_country_option( 'cut_off_time', '' );
	}

	/**
	 * Get dropoff monday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_monday() {
		return $this->get_country_option( 'dropoff_day_mon', '' );
	}

	/**
	 * Return true if dropoff monday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_monday_enabled() {
		return ( 'yes' === $this->get_dropoff_monday() );
	}

	/**
	 * Get dropoff tuesday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_tuesday() {
		return $this->get_country_option( 'dropoff_day_tue', '' );
	}

	/**
	 * Return true if dropoff tuesday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_tuesday_enabled() {
		return ( 'yes' === $this->get_dropoff_tuesday() );
	}

	/**
	 * Get dropoff wednesday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_wednesday() {
		return $this->get_country_option( 'dropoff_day_wed', '' );
	}

	/**
	 * Return true if dropoff wednesday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_wednesday_enabled() {
		return ( 'yes' === $this->get_dropoff_wednesday() );
	}

	/**
	 * Get dropoff thursday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_thursday() {
		return $this->get_country_option( 'dropoff_day_thu', '' );
	}

	/**
	 * Return true if dropoff thursday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_thursday_enabled() {
		return ( 'yes' === $this->get_dropoff_thursday() );
	}

	/**
	 * Get dropoff friday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_friday() {
		return $this->get_country_option( 'dropoff_day_fri', '' );
	}

	/**
	 * Return true if dropoff friday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_friday_enabled() {
		return ( 'yes' === $this->get_dropoff_friday() );
	}

	/**
	 * Get dropoff saturday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_saturday() {
		return $this->get_country_option( 'dropoff_day_sat', '' );
	}

	/**
	 * Return true if dropoff saturday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_saturday_enabled() {
		return ( 'yes' === $this->get_dropoff_saturday() );
	}

	/**
	 * Get dropoff sunday value from the settings.
	 *
	 * @return String
	 */
	public function get_dropoff_sunday() {
		return $this->get_country_option( 'dropoff_day_sun', '' );
	}

	/**
	 * Return true if dropoff sunday field is ticked.
	 *
	 * @return Bool
	 */
	public function is_dropoff_sunday_enabled() {
		return ( 'yes' === $this->get_dropoff_sunday() );
	}

	/**
	 * Get dropoff days from the settings.
	 *
	 * @return array
	 */
	public function get_dropoff_days() {
		$dropoff_days = array();

		if ( $this->is_dropoff_monday_enabled() ) {
			$dropoff_days[] = 'mon';
		}

		if ( $this->is_dropoff_tuesday_enabled() ) {
			$dropoff_days[] = 'tue';
		}

		if ( $this->is_dropoff_wednesday_enabled() ) {
			$dropoff_days[] = 'wed';
		}

		if ( $this->is_dropoff_thursday_enabled() ) {
			$dropoff_days[] = 'thu';
		}

		if ( $this->is_dropoff_friday_enabled() ) {
			$dropoff_days[] = 'fri';
		}

		if ( $this->is_dropoff_saturday_enabled() ) {
			$dropoff_days[] = 'sat';
		}

		if ( $this->is_dropoff_sunday_enabled() ) {
			$dropoff_days[] = 'sun';
		}

		return $dropoff_days;
	}

	/**
	 * Get excluded dropoff days from the settings.
	 *
	 * @return array
	 */
	public function get_excluded_dropoff_days() {
		$completed_days = array_keys( Utils::days_of_week() );
		$dropoff_days   = $this->get_dropoff_days();

		return array_diff( $completed_days, $dropoff_days );
	}

	/**
	 * Get globalpack type barcode from the settings.
	 *
	 * @return String
	 */
	public function get_globalpack_barcode_type() {
		return $this->get_country_option( 'globalpack_barcode_type', '' );
	}

	/**
	 * Get globalpack customer code from the settings.
	 *
	 * @return String
	 */
	public function get_globalpack_customer_code() {
		return $this->get_country_option( 'globalpack_customer_code', '' );
	}

	/**
	 * Get HS Tariff code from the settings.
	 *
	 * @return String
	 */
	public function get_hs_tariff_code() {
		return $this->get_country_option( 'hs_tariff_code', '' );
	}

	/**
	 * Get HS Tariff code from the settings.
	 *
	 * @return String
	 */
	public function get_country_origin() {
		return $this->get_country_option( 'country_origin', '' );
	}

	/**
	 * Get label format from the settings.
	 *
	 * @return String
	 */
	public function get_label_format() {
		return $this->get_country_option( 'label_format', '' );
	}

	/**
	 * Get printer type from the settings.
	 * PDF by default.
	 *
	 * @return String
	 */
	public function get_printer_type() {
		$printer_type = $this->get_country_option( 'printer_type', '' );
		$resolution   = (int) $this->get_country_option( 'printer_type_resolution', 600 );

		switch ( $printer_type ) {
			case 'JPG':
				return sprintf( 'GraphicFile|JPG %d dpi', $resolution );
			case 'GIF':
				return sprintf( 'GraphicFile|GIF %d dpi', $resolution );
			case 'ZPL':
				return sprintf( 'Zebra|Generic ZPL II %d dpi', $resolution );
			default:
				return 'GraphicFile|PDF';
		}
	}

	/**
	 * Get shipping confirmation email text value from the settings.
	 *
	 * @return String
	 */
	public function get_shipping_confirmation_email() {
		return $this->get_country_option( 'shipping_confirmation_email', '' );
	}

	/**
	 * Get woocommerce email checkbox value from the settings.
	 *
	 * @return String
	 */
	public function get_woocommerce_email() {
		return $this->get_country_option( 'woocommerce_email', '' );
	}

	/**
	 * Return true if woocommerce email field is ticked.
	 *
	 * @return Bool
	 */
	public function is_woocommerce_email_enabled() {
		return ( 'yes' === $this->get_woocommerce_email() );
	}

	/**
	 * Get woocommerce email text value from the settings.
	 *
	 * @return String
	 */
	public function get_woocommerce_email_text() {
		return $this->get_country_option( 'woocommerce_email_text', '' );
	}

	/**
	 * Get check Netherlands address value from the settings.
	 *
	 * @return String
	 */
	public function get_validate_nl_address() {
		return $this->get_country_option( 'validate_nl_address', '' );
	}

	/**
	 * Return true if check Netherlands address field is ticked.
	 *
	 * @return Bool
	 */
	public function is_validate_nl_address_enabled() {
		return ( 'yes' === $this->get_validate_nl_address() );
	}

	/**
	 * Get reorder Netherlands address value from the settings.
	 *
	 * @return String
	 */
	public function get_reorder_nl_address() {
		return $this->get_country_option( 'reorder_nl_address', '' );
	}

	/**
	 * Return true if reorder Netherlands address field is ticked.
	 *
	 * @return Bool
	 */
	public function is_reorder_nl_address_enabled() {
		return ( 'yes' === $this->get_reorder_nl_address() );
	}

	/**
	 * Get enable logging value from the settings.
	 *
	 * @return String
	 */
	public function get_enable_logging() {
		return $this->get_country_option( 'enable_logging', '' );
	}

	/**
	 * Return true if enable logging field is ticked.
	 *
	 * @return Bool
	 */
	public function is_logging_enabled() {
		return ( 'yes' === $this->get_enable_logging() );
	}

	/**
	 * Get all shipping options.
	 *
	 * @param string $zone Shipping zone, available options: 'ne' - to Netherlands, 'be' - to Belgium, 'eu' - to European Union, 'row' - international shipping.
	 *
	 * @return array
	 */
	public function get_default_shipping_options( $zone ) {
		$shipping_options = $this->get_country_option( 'default_shipping_options_' . strtolower( $zone ), '' );

		return Utils::prepare_shipping_options( $shipping_options );
	}

	/**
	 * Get default automatic letterboxparcel product from the settings.
	 *
	 * @since 5.9.6
	 *
	 * @return String
	 */
	public function get_default_automatic_letterboxparcel_product() {
		return $this->get_country_option( 'default_automatic_letterboxparcel_product', 'letterbox' );
	}

	/**
	 * Return array of shipping methods.
	 *
	 * @return array.
	 */
	public function get_shipping_methods() {
		return wp_list_pluck( WC()->shipping()->shipping_methods, 'method_title', 'id' );
	}

	/**
	 * Get supported shipping methods from the settings.
	 *
	 * @return array.
	 */
	public function get_supported_shipping_methods() {
		$suppoted_shipping_methods = (array) $this->get_option( 'supported_shipping_methods' );
		// Add PostNL method by default
		$suppoted_shipping_methods[] = POSTNL_SETTINGS_ID;

		return $suppoted_shipping_methods;
	}

	/**
	 * Get Automatically change order status to Completed value from the settings.
	 *
	 * @return String
	 */
	public function get_auto_complete_order() {
		return $this->get_country_option( 'auto_complete_order', '' );
	}

	/**
	 * Return true if Automatically change order status to Completed is ticked.
	 *
	 * @return Bool
	 */
	public function is_auto_complete_order_enabled() {
		return ( 'yes' === $this->get_auto_complete_order() );
	}
}

```
