Commit 67d4cc147d for woocommerce

commit 67d4cc147d6461724052fb67f9220470755efcb1
Author: Seun Olorunsola <30554163+triple0t@users.noreply.github.com>
Date:   Wed Dec 10 12:33:21 2025 +0100

    Add a filter to customize the personalizer context (#62337)

    * Add a filter to customize the personalizer context

    * Fix lint errors

    * Fit lint error

    * Refactor prepare_context_data method to improve clarity and context handling

    - Renamed parameter from $context to $previous_context for better understanding.
    - Updated logic to ensure $context is initialized correctly from $previous_context.
    - Enhanced filtering of context data for email personalization.

    * Update email editor integration documentation for clarity on context data accessibility

diff --git a/docs/extensions/settings-and-config/email-editor-integration.md b/docs/extensions/settings-and-config/email-editor-integration.md
index 011a98d85c..2cceb7e7df 100644
--- a/docs/extensions/settings-and-config/email-editor-integration.md
+++ b/docs/extensions/settings-and-config/email-editor-integration.md
@@ -307,6 +307,94 @@ add_filter( 'woocommerce_email_editor_register_personalization_tags', 'your_plug

 To learn more about personalization tags, please see the [personalization tags documentation](https://github.com/woocommerce/woocommerce/blob/trunk/packages/php/email-editor/docs/personalization-tags.md) in the `woocommerce/email-editor` package.

+### Providing custom context for personalization tags
+
+Use the `woocommerce_email_editor_integration_personalizer_context_data` filter to provide custom context data to your personalization tags. This is useful when your extension needs to pass additional data (such as subscription details, loyalty points, or custom order metadata) that your personalization tag callbacks can access.
+
+**Filter details:**
+
+| Property | Value |
+| -------- | ----- |
+| Hook name | `woocommerce_email_editor_integration_personalizer_context_data` |
+| Since | 10.5.0 |
+| Parameters | `$context` (array), `$email` (\WC_Email) |
+| Returns | array |
+
+**Parameters:**
+
+- `$context` *(array)* – The existing context data array. This may already contain data from WooCommerce core or other extensions.
+- `$email` *(\WC_Email)* – The WooCommerce email object being processed. You can use this to access the email ID, recipient, and the object associated with the email (such as an order or customer).
+
+**Return value:**
+
+Return an array of custom context data along with Woo core context data. This array will be accessible to all personalization tag callbacks through the `$context` parameter.
+
+#### Example: Adding subscription data to context
+
+```php
+/**
+ * Add subscription-related context data for personalization tags.
+ *
+ * @param array     $context The existing context data.
+ * @param \WC_Email $email   The WooCommerce email object.
+ * @return array Modified context data.
+ */
+function your_plugin_add_subscription_context( $context, $email ) {
+    // Only add context for subscription-related emails.
+    if ( strpos( $email->id, 'subscription' ) === false ) {
+        return $context;
+    }
+
+    // Get the order from the email object.
+    $order = $email->object instanceof WC_Order ? $email->object : null;
+
+    if ( ! $order ) {
+        return $context;
+    }
+
+    // Add your custom subscription data to context.
+    $context['subscription_id']       = $order->get_meta( '_subscription_id' );
+    $context['subscription_end_date'] = $order->get_meta( '_subscription_end_date' );
+    $context['renewal_count']         = (int) $order->get_meta( '_renewal_count' );
+
+    return $context;
+}
+add_filter( 'woocommerce_email_editor_integration_personalizer_context_data', 'your_plugin_add_subscription_context', 10, 2 );
+```
+
+#### Example: Using custom context in a personalization tag callback
+
+Once you've added custom data to the context, your personalization tag callbacks can access it:
+
+```php
+/**
+ * Personalization tag callback that uses custom context data.
+ *
+ * @param array $context The context data (includes your custom data).
+ * @param array $args    Optional attributes passed to the tag.
+ * @return string The personalized value.
+ */
+function your_plugin_get_subscription_end_date( $context, $args = array() ) {
+    // Access the custom context data you added via the filter.
+    $end_date = $context['subscription_end_date'] ?? '';
+
+    if ( empty( $end_date ) ) {
+        return __( 'N/A', 'your-plugin' );
+    }
+
+    // Format the date according to site settings.
+    return date_i18n( get_option( 'date_format' ), strtotime( $end_date ) );
+}
+```
+
+**Important notes:**
+
+- The filter is called during email personalization, so your context data is available when personalization tags are processed.
+- Always check if the email type is relevant before adding context data to avoid unnecessary processing.
+- Use unique keys for your context data to prevent conflicts with WooCommerce core or other extensions.
+- The `$email->object` property typically contains the main object associated with the email (e.g., `WC_Order` for order emails, `WP_User` for user-related emails).
+- When using context data in personalization tags, ensure proper escaping based on the output context (e.g., `esc_html()`, `esc_attr()`, `esc_url()`).
+
 ## Complete example

 Below is an example of a loyalty program welcome email implementation:
diff --git a/plugins/woocommerce/changelog/add-a-hook-for-woo-extensions-to-set-the-personalizer-context-for-their-tags b/plugins/woocommerce/changelog/add-a-hook-for-woo-extensions-to-set-the-personalizer-context-for-their-tags
new file mode 100644
index 0000000000..9e99967f19
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-a-hook-for-woo-extensions-to-set-the-personalizer-context-for-their-tags
@@ -0,0 +1,4 @@
+Significance: patch
+Type: tweak
+
+Add a hook enabling Woo extensions to set the Personalizer context for their personalization tags.
diff --git a/plugins/woocommerce/src/Internal/EmailEditor/TransactionalEmailPersonalizer.php b/plugins/woocommerce/src/Internal/EmailEditor/TransactionalEmailPersonalizer.php
index d9549adac0..a042a569bf 100644
--- a/plugins/woocommerce/src/Internal/EmailEditor/TransactionalEmailPersonalizer.php
+++ b/plugins/woocommerce/src/Internal/EmailEditor/TransactionalEmailPersonalizer.php
@@ -60,11 +60,27 @@ class TransactionalEmailPersonalizer {
 	 * Prepare context data for email personalization.
 	 * Adds new order specific context data.
 	 *
-	 * @param array     $context Previous version of context data.
+	 * @param array     $previous_context Previous version of context data.
 	 * @param \WC_Email $email The WooCommerce email object.
 	 * @return array Context data for personalization
 	 */
-	public function prepare_context_data( array $context, \WC_Email $email ): array {
+	public function prepare_context_data( array $previous_context, \WC_Email $email ): array {
+		$context = $previous_context;
+
+		/**
+		 * Filters the context data for email personalization.
+		 *
+		 * @since 10.5.0
+		 * @param array     $context Previous version of context data.
+		 * @param \WC_Email $email The WooCommerce email object.
+		 * @return array Context data for personalization
+		 */
+		$context = apply_filters( 'woocommerce_email_editor_integration_personalizer_context_data', $context, $email );
+
+		if ( ! is_array( $context ) ) {
+			$context = $previous_context;
+		}
+
 		$context['recipient_email'] = $email->get_recipient();
 		$context['order']           = $email->object instanceof \WC_Order ? $email->object : null;
 		// For emails of type new_user or reset_password we want to set user directly from the object.