Skip to content

Conversation

@costasovo
Copy link
Contributor

@costasovo costasovo commented Nov 7, 2025

Changes proposed in this Pull Request:

This PR adds the settings/emails route to the experimental V4 API.

The endpoint was moved from the temporary endpoint and updated to align with other settings APIs (e.g. general settings). The main changes are:

  • separated schema and controller
  • the response format is aligned to other settings:
    • non-editable metadata are on top level (e.g. id, description, link, post_id, is_customer_email)
    • editable fields are generated dynamically based on WP_Email::get_form_fields and are nested in values
    • I added is_manual to be able to mark emails that are sent only manually
  • moved test for email settings to proper location
  • added test for the emails settings api

There are a few things that need to be addressed as follow-up:

  • historically, the recipient field is text and is not validated as a list of comma-separated email addresses
  • the api unwraps personalization tags in the subject and preheader in the GET response. I think the API should send the data as they are saved and let the client handle the unwrapping if it doesn't support the tags. I have briefly discussed this with @triple0t, and he had no strong opinion on that and is ok with the change. Other opinions are welcome.

Closes WOOPRD-926.

How to test the changes in this Pull Request:

The endpoint is covered by unit tests. It can also be tested with an app that uses it.

@github-actions github-actions bot added the plugin: woocommerce Issues related to the WooCommerce Core plugin. label Nov 7, 2025
@woocommercebot woocommercebot requested a review from a team November 7, 2025 11:53
@github-actions
Copy link
Contributor

github-actions bot commented Nov 7, 2025

Testing Guidelines

Hi @yuliyan @woocommerce/ballade,

Apart from reviewing the code changes, please make sure to review the testing instructions (Guide) and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed.

Reminder: PR reviewers are required to document testing performed. This includes:

  • 🖼️ Screenshots or screen recordings.
  • 📝 List of functionality tested / steps followed.
  • 🌐 Site details (environment attributes such as hosting type, plugins, theme, store size, store age, and relevant settings).
  • 🔍 Any analysis performed, such as assessing potential impacts on environment attributes and other plugins, conducting performance profiling, or using LLM/AI-based analysis.

⚠️ Within the testing details you provide, please ensure that no sensitive information (such as API keys, passwords, user data, etc.) is included in this public issue.

@claude
Copy link

claude bot commented Nov 7, 2025

Claude finished @costasovo's task —— View job


Backwards Compatibility Review

Summary

Overall Risk: None

This PR introduces a new experimental V4 REST API endpoint (/wc/v4/settings/emails) for managing email settings with an improved schema structure. All changes are strictly additive with no breaking modifications to existing APIs, hooks, or templates. The implementation is properly gated by feature flags and follows WooCommerce's established patterns for REST API endpoints.

The codebase remains fully backwards compatible with no deprecations required.

Detailed Analysis

1. REST API Changes (New endpoints only - No BC impact)

New Endpoint: GET/PUT /wc/v4/settings/emails and /wc/v4/settings/emails/{email_id}

  • Location: plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php:55-100
  • Registration: plugins/woocommerce/includes/rest-api/Server.php:245 (added alongside existing settings-email)
  • Impact: None - This is a parallel implementation that coexists with the existing single-email endpoint
  • Evidence: Both EmailSettingsController (singular) and EmailsSettingsController (plural) are registered in the V4 controller map
// plugins/woocommerce/includes/rest-api/Server.php:242-245
'settings-general'          => GeneralSettingsController::class,
'settings-email'            => EmailSettingsController::class,  // Existing
'settings-emails'           => EmailsSettingsController::class, // New (this PR)
'settings-products'         => SettingsProductsController::class,

Schema Differences:

  • Response format aligns with other V4 settings endpoints (general settings pattern)
  • Editable fields nested under values key (consistent with V4 patterns)
  • Non-editable metadata at top level
  • Personalization tag handling (unwrap on GET, wrap on PUT)
2. PHP API Changes (Additive only - No BC impact)

WC_Email Base Class:

  • Added: protected function get_preheader_field() (plugins/woocommerce/includes/emails/class-wc-email.php:1235-1244)
  • Modified: init_form_fields() to conditionally add preheader field
  • Gating: if ( $this->block_email_editor_enabled ) - feature flag protection
  • Impact: None - protected method addition is non-breaking for child classes
  • Evidence: The get_preheader() method already exists (since 9.9.0), this only adds the form field definition
// plugins/woocommerce/includes/emails/class-wc-email.php:1191-1193
if ( $this->block_email_editor_enabled ) {
    $this->form_fields['preheader'] = $this->get_preheader_field();
}

Email Subclasses (7 files modified):

  • All add the preheader field using the same feature-flag pattern
  • No signature changes, property changes, or method removals
  • Files: class-wc-email-{cancelled-order, customer-cancelled-order, customer-invoice, customer-pos-refunded-order, customer-refunded-order, failed-order, new-order}.php
3. Hook Changes (Reusing existing hook - No BC impact)

Hook Used: do_action( 'woocommerce_settings_updated', $updated_fields, $this->rest_base )

  • Location: plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php:280
  • Impact: None - This hook is already used by other V4 settings controllers
  • Evidence: Same hook exists in:
    • Settings/General/Controller.php
    • Settings/Email/Controller.php (existing single-email endpoint)
    • Settings/Products/Controller.php
    • Settings/PaymentGateways/Controller.php

No hooks removed or renamed.

4. Schema & Data Handling (Addressed concerns)

Recipient Field Validation (Mentioned in PR description as known issue):

  • Field Type: text (not email) in all admin email classes
  • Location: plugins/woocommerce/includes/emails/class-wc-email-new-order.php:215-217
  • Schema Handling: The new API respects the field's declared type (text), so comma-separated emails are not affected by email validation
  • Validation Logic: Only fields with type: 'email' trigger sanitize_email() and is_email() validation
  • Evidence: plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php:500-501, 540-550

Personalization Tag Handling:

  • Unwraps tags on GET (removes HTML comment wrappers for client editing)
  • Wraps tags on PUT (restores HTML comment wrappers for storage)
  • Only applies to fields in FIELDS_SUPPORTING_PERSONALIZATION_TAGS (subject, preheader)
  • No breaking changes to stored data format

Permalink Null Safety (Fixed in commit 00995de):

  • Previously: get_permalink($post_id) could return false for null post IDs
  • Now: Properly handles null by returning empty string for link field
  • Location: plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php:226-231
5. Template Changes

No template files modified - confirmed via git diff.

6. Ecosystem Impact Assessment

Extensions using WC_Email:

  • Subscriptions: No impact - adds protected method, no signature changes
  • Bookings: No impact - preheader field is optional and gated by feature flag
  • Memberships: No impact - child classes can ignore the new field
  • Payment Gateways: No impact - REST API permission checks unchanged

Extensions using REST API:

  • New endpoint does not interfere with existing integrations
  • Permission checks: wc_rest_check_manager_permissions('settings', 'read|edit') - standard pattern
  • Response format is self-describing via schema

Theme Customizations:

  • No template changes
  • Email rendering logic unchanged
  • Preheader field is purely administrative (settings form)
7. Database & Options

No schema changes - Uses existing WP options system ($email->update_option())
New options: woocommerce_*_preheader options created when preheader is set (standard pattern)

Testing Focus

Given the additive nature of these changes, testing should focus on:

  1. REST API Regression:

    • Verify existing /wc/v4/settings/email endpoint still works
    • Test new /wc/v4/settings/emails endpoint returns expected format
    • Confirm permission checks work correctly (manager permissions required)
    • Test filtering by post_id parameter
  2. Email Settings UI:

    • With block editor disabled: preheader field should NOT appear
    • With block editor enabled: preheader field should appear for all core emails
    • Verify personalization tags display correctly (unwrapped format)
    • Test saving with personalization tags preserves them
  3. Extension Compatibility:

    • Test Subscriptions renewal emails still render correctly
    • Verify custom email classes extending WC_Email don't break
    • Check payment gateway notification emails work
  4. Data Persistence:

    • Verify preheader values save to correct option names
    • Test updates via REST API persist correctly
    • Confirm woocommerce_settings_updated hook fires with correct parameters

Confidence

95% - High confidence in the backwards compatibility assessment.

Justification: All changes are purely additive (new endpoint, new protected method, conditional form fields). The implementation follows established WooCommerce patterns, reuses existing hooks, and includes proper feature flagging. The PR author has explicitly noted the recipient validation issue as a known follow-up item, and the current implementation correctly handles it by using type: 'text' instead of type: 'email'. Code review comments from CodeRabbit have been addressed in commit 00995de.

The 5% uncertainty accounts for potential edge cases in third-party extensions that might:

  • Override init_form_fields() without calling parent::init_form_fields()
  • Directly manipulate the form_fields array in unexpected ways
  • Use undocumented internal APIs

@costasovo costasovo force-pushed the wooprd-926-move-notifications-listing-api-to-woocommerce branch from 1528a5e to e7e330a Compare November 7, 2025 11:58
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 7, 2025

📝 Walkthrough

Walkthrough

Adds an experimental V4 REST API for email settings (listing, retrieval, update) with a schema that handles personalization-tag wrapping/unwrapping, validation and sanitization; adds conditional preheader form fields to multiple email classes; registers the new controller; includes changelog and comprehensive PHPUnit tests.

Changes

Cohort / File(s) Summary
Changelog Entry
plugins/woocommerce/changelog/wooprd-926-move-notifications-listing-api-to-woocommerce
Adds a patch-level changelog entry documenting the experimental V4 settings/emails API.
Email Classes: Preheader Field Support
plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php, plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php, plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php, plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php, plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php, plugins/woocommerce/includes/emails/class-wc-email-failed-order.php, plugins/woocommerce/includes/emails/class-wc-email-new-order.php
Each subclass conditionally adds a preheader form field in init_form_fields() when the block email editor feature flag is enabled, alongside existing CC/BCC fields.
Base Email Class
plugins/woocommerce/includes/emails/class-wc-email.php
Adds protected function get_preheader_field() and integrates conditional inclusion of the preheader field into init_form_fields() when the block email editor is enabled.
REST API Server
plugins/woocommerce/includes/rest-api/Server.php
Imports EmailsSettingsController and registers the new V4 controller mapping 'settings-emails' => EmailsSettingsController::class in get_v4_controllers().
Email Settings Controller
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php
New REST controller exposing GET /settings/emails and `GET
Email Settings Schema
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
New schema class defining item properties, value extraction, defaults, groups, personalization-tag wrap/unwrap, sanitization, and validation for email settings payloads.
Tests: Controller & Namespace Changes
plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php, plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
First file: namespace and class rename/relocation. Second file: new comprehensive PHPUnit test suite covering route registration, GET/PUT flows, sanitization, personalization tag handling, filtering, permissions, and error cases.

Sequence Diagram(s)

sequenceDiagram
    participant Client as REST Client
    participant Controller as EmailsSettingsController
    participant Schema as EmailsSettingsSchema
    participant Email as WC_Email
    participant Storage as Option Storage

    Note over Client,Storage: GET /wc/v4/settings/emails or /settings/emails/{id}
    Client->>Controller: GET request
    Controller->>Controller: permissions check
    Controller->>Email: locate email(s)
    Controller->>Schema: get_item_response(email)
    Schema->>Email: read form fields & values
    Schema->>Schema: unwrap personalization tags (subject, preheader)
    Schema->>Controller: formatted response
    Controller->>Client: 200 OK + payload

    Note over Client,Storage: PUT /wc/v4/settings/emails/{id}
    Client->>Controller: PUT request + payload
    Controller->>Controller: permissions check
    Controller->>Schema: validate_and_sanitize_settings(email, payload)
    Schema->>Schema: unwrap tags -> sanitize -> validate
    alt validation fails
        Schema-->>Controller: WP_Error
        Controller->>Client: 400 Bad Request
    else validation passes
        Controller->>Email: apply updated values
        Controller->>Storage: persist options
        Schema->>Schema: wrap personalization tags as needed
        Controller->>Client: 200 OK + updated payload
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • High-attention areas:
    • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php — complex parsing, tag wrap/unwrap, sanitization and validation logic.
    • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php — permissions, route handling, error responses, persistence.
    • plugins/woocommerce/tests/php/.../EmailsSettingsControllerTest.php — extensive assertions that must align with schema behavior.
  • Also verify: consistency of preheader inclusion across email classes and option persistence behavior.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description check ✅ Passed The PR description comprehensively explains the changes: adds settings/emails route to V4 API, details schema separation, response format alignment, and metadata structure.
Title check ✅ Passed The title accurately describes the main addition: an experimental emails settings API (V4). It directly aligns with the primary changes across the codebase.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wooprd-926-move-notifications-listing-api-to-woocommerce

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 7, 2025

Test using WordPress Playground

The changes in this pull request can be previewed and tested using a WordPress Playground instance.
WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Test this pull request with WordPress Playground.

Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php (1)

55-97: Restore the original block editor toggle instead of hard-coding it to “no” after tests

setUp() forces woocommerce_feature_block_email_editor_enabled to 'yes', but tearDown() always resets it to 'no'. If another test (or the default fixture) expects that option to remain 'yes' or to stay unset, this suite will leave it in the wrong state, causing order-dependent failures. Please capture the prior value in $this->prev_options before you flip it on, let the existing restoration loop put it back exactly as it was, and drop the hard-coded 'no'.

Apply something like:

  public function setUp(): void {
      // Enable the v4 REST API feature before bootstrapping.
      $this->feature_filter = function ( $features ) {
          $features[] = 'rest-api-v4';
          return $features;
      };

      add_filter( 'woocommerce_admin_features', $this->feature_filter );

-     parent::setUp();
-     // Enable block email editor feature to test reply-to fields.
-     update_option( 'woocommerce_feature_block_email_editor_enabled', 'yes' );
+     parent::setUp();
+     $this->prev_options['woocommerce_feature_block_email_editor_enabled']
+         = get_option( 'woocommerce_feature_block_email_editor_enabled', null );
+     update_option( 'woocommerce_feature_block_email_editor_enabled', 'yes' );

      // Snapshot current option values to restore on tearDown.
      $option_ids = array(
          'woocommerce_email_from_name',

and in tearDown() let the existing loop restore the saved value, deleting it when the previous value was null, instead of forcing 'no'.

🧹 Nitpick comments (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)

1230-1244: Consider enforcing the 150 character limit mentioned in the description.

The field description informs users about a "Max 150 characters" limit, but this constraint is not enforced in the field definition. While email clients will handle overly long preheaders gracefully, adding validation would improve the user experience and data quality.

Consider adding a maxlength attribute or custom validation:

 protected function get_preheader_field() {
 	return array(
 		'title'       => __( 'Preheader', 'woocommerce' ),
 		'description' => __( 'Shown as a preview in the Inbox, next to the subject line. (Max 150 characters).', 'woocommerce' ),
 		'placeholder' => '',
 		'type'        => 'text',
 		'default'     => '',
 		'desc_tip'    => true,
+		'custom_attributes' => array(
+			'maxlength' => 150,
+		),
 	);
 }

Alternatively, verify that the V4 REST API endpoint (mentioned in PR objectives) enforces this limit on the server side.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9dd85c and e7e330a.

📒 Files selected for processing (14)
  • plugins/woocommerce/changelog/wooprd-926-move-notifications-listing-api-to-woocommerce (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php (1 hunks)
  • plugins/woocommerce/includes/emails/class-wc-email.php (2 hunks)
  • plugins/woocommerce/includes/rest-api/Server.php (2 hunks)
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php (1 hunks)
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (1 hunks)
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php (1 hunks)
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)

**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable

Files:

  • plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php
  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/rest-api/Server.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php
  • plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
**/*.{php,js,jsx,tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/avoid-regex.mdc)

**/*.{php,js,jsx,tsx,ts}: Avoid using regular expressions unless absolutely necessary to favor readability and maintainability
Only consider regex when no built-in language alternative (string/array APIs) fits the need
Only use regex when performance is critical and faster than alternatives, with measurements to justify
Use regex for complex pattern matching only if the pattern is well-documented and thoroughly tested
Allow regex when maintaining legacy code where an existing, correct pattern is being modified
If regex is necessary, document the pattern extensively to explain what it matches
If regex is necessary, add comprehensive tests covering edge cases and potential security issues
Use named capture groups in regex to improve readability when supported
Validate input before applying regex to ensure it is safe
Assess and mitigate security risks when using regex, including ReDoS and injection vulnerabilities
Avoid regex patterns that can cause catastrophic backtracking (ReDoS)
Do not construct regex from untrusted input to prevent injection attacks
Ensure regex patterns do not overmatch and unintentionally capture unexpected inputs

Files:

  • plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php
  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/rest-api/Server.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php
  • plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
**/*.{php,js,ts,jsx,tsx}

⚙️ CodeRabbit configuration file

**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:

  • Guards against unexpected inputs.
  • Sanitizes and validates any potentially dangerous inputs.
  • Is backwards compatible.
  • Is readable and intuitive.
  • Has unit or E2E tests where applicable.
    When making any changes to code that deletes or modifies orders/products/customer data, make sure that there are
    sufficient checks in place to prevent accidental data loss. As an example, if deleting a draft order, check that
    the order status is indeed draft or checkout-draft. Also think about whether race conditions could occur and
    delete orders that don't belong to the current customer. When in doubt, ask for clarification in the PR comments.

Files:

  • plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php
  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/rest-api/Server.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php
  • plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
plugins/woocommerce/tests/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/woo-phpunit.mdc)

plugins/woocommerce/tests/**/*.php: Ensure test classes define public setUp() and tearDown() methods (not protected)
All PHPUnit test methods must be public, not protected
Add declare(strict_types=1); at the top of each test file
Test classes should extend WC_Unit_Test_Case

Files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
🧠 Learnings (13)
📚 Learning: 2025-08-27T21:13:11.131Z
Learnt from: allilevine
Repo: woocommerce/woocommerce PR: 60514
File: packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-table.php:253-255
Timestamp: 2025-08-27T21:13:11.131Z
Learning: In WooCommerce Email Editor table block renderer (packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-table.php), header and footer borders in the add_header_footer_borders method are intentionally always solid style, not meant to inherit custom border styles. Custom border styles will override these solid borders when applied, creating a proper styling hierarchy.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email.php
📚 Learning: 2025-06-23T16:55:58.246Z
Learnt from: lysyjan
Repo: woocommerce/woocommerce PR: 59070
File: packages/php/email-editor/src/Integrations/Core/class-initializer.php:103-141
Timestamp: 2025-06-23T16:55:58.246Z
Learning: The core/spacer block in the WooCommerce email editor intentionally does not have a dedicated renderer class and is handled by the fallback renderer instead of having an explicit render_email_callback assigned in the switch statement.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
📚 Learning: 2025-06-26T12:13:32.062Z
Learnt from: triple0t
Repo: woocommerce/woocommerce PR: 59186
File: packages/js/email-editor/src/store/initial-state.ts:9-10
Timestamp: 2025-06-26T12:13:32.062Z
Learning: In WooCommerce email editor store initialization (packages/js/email-editor/src/store/initial-state.ts), the current_post_id and current_post_type from window.WooCommerceEmailEditor are required parameters that should cause explicit errors if missing, rather than using fallback values or optional chaining. The design preference is to fail fast when critical initialization data is unavailable.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php
📚 Learning: 2025-08-21T07:39:42.952Z
Learnt from: NeosinneR
Repo: woocommerce/woocommerce PR: 60520
File: plugins/woocommerce/src/Internal/Admin/EmailPreview/EmailPreview.php:257-259
Timestamp: 2025-08-21T07:39:42.952Z
Learning: In WooCommerce email preview functionality (EmailPreview.php), rel attributes on links should be overwritten rather than preserved for safety reasons, and anchor links (#) can be treated the same as external links since they're not expected in email previews.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
📚 Learning: 2025-08-19T10:42:44.153Z
Learnt from: yuliyan
Repo: woocommerce/woocommerce PR: 60354
File: packages/php/email-editor/src/Engine/class-settings-controller.php:191-205
Timestamp: 2025-08-19T10:42:44.153Z
Learning: WooCommerce email editor supports WordPress versions newer than 5.5. WordPress 5.5 and older versions are outside the supported range, so backward compatibility considerations for those versions (such as including `wp-block-library-theme-css` for older WP theme styles) are not necessary.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
📚 Learning: 2025-08-08T13:47:37.272Z
Learnt from: lysyjan
Repo: woocommerce/woocommerce PR: 60165
File: plugins/woocommerce/src/Internal/EmailEditor/PageRenderer.php:100-104
Timestamp: 2025-08-08T13:47:37.272Z
Learning: In WooCommerce email editor PHP package (packages/php/email-editor), the localization data passed through the `woocommerce_email_editor_script_localization_data` filter always includes the `editor_settings` key as an array (prepared by `Assets_Manager`). This guarantees nested writes like `['editor_settings']['isFullScreenForced']` are safe in PageRenderer::update_localized_data().

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-07-15T15:39:21.856Z
Learnt from: jorgeatorres
Repo: woocommerce/woocommerce PR: 59675
File: .github/workflows/release-bump-as-requirement.yml:48-65
Timestamp: 2025-07-15T15:39:21.856Z
Learning: In WooCommerce core repository, changelog entries for all PRs live in `plugins/woocommerce/changelog/` directory and are processed during releases, not at the repository root level.

Applied to files:

  • plugins/woocommerce/changelog/wooprd-926-move-notifications-listing-api-to-woocommerce
📚 Learning: 2025-09-03T11:50:02.208Z
Learnt from: tpaksu
Repo: woocommerce/woocommerce PR: 60735
File: plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Fulfillments/class-wc-rest-fulfillments-v4-controller-tests.php:10-10
Timestamp: 2025-09-03T11:50:02.208Z
Learning: For REST API controller tests in plugins/woocommerce/tests/**/*.php, test classes should extend WC_REST_Unit_Test_Case instead of WC_Unit_Test_Case because REST routes need to be registered before tests run.

Applied to files:

  • plugins/woocommerce/includes/rest-api/Server.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php
📚 Learning: 2025-08-18T06:11:48.768Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/woo-phpunit.mdc:0-0
Timestamp: 2025-08-18T06:11:48.768Z
Learning: Applies to plugins/woocommerce/tests/**/*.php : Add declare(strict_types=1); at the top of each test file

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-08-18T06:11:48.768Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/woo-phpunit.mdc:0-0
Timestamp: 2025-08-18T06:11:48.768Z
Learning: Applies to plugins/woocommerce/tests/**/*.php : Test classes should extend WC_Unit_Test_Case

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Email/EmailSettingsControllerTest.php
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-10-23T01:44:03.397Z
Learnt from: peterwilsoncc
Repo: woocommerce/woocommerce PR: 60447
File: plugins/woocommerce/templates/emails/email-order-details.php:96-131
Timestamp: 2025-10-23T01:44:03.397Z
Learning: In WooCommerce email templates (plugins/woocommerce/templates/emails/), when displaying order details, the order items table and order totals should be separate tables rather than combined with <tfoot>. This follows accessibility guidance: the totals are semantically different information from the line items and should not be forced into a single table structure just for visual positioning. The split improves accessibility for assistive technology users.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
📚 Learning: 2025-06-26T14:25:08.421Z
Learnt from: NeosinneR
Repo: woocommerce/woocommerce PR: 0
File: :0-0
Timestamp: 2025-06-26T14:25:08.421Z
Learning: In WooCommerce transactional emails, product images have historically had display issues due to lazy loading attributes being applied, which email clients cannot process since they don't execute JavaScript. This issue existed in both old and new email templates, but became more visible with the new email template system. The fix involves preventing lazy loading on attachment images specifically during email generation by adding skip classes and data attributes.

Applied to files:

  • plugins/woocommerce/includes/emails/class-wc-email-new-order.php
  • plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
📚 Learning: 2025-07-29T08:05:14.107Z
Learnt from: lysyjan
Repo: woocommerce/woocommerce PR: 60072
File: packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php:110-118
Timestamp: 2025-07-29T08:05:14.107Z
Learning: In WooCommerce email editor personalization tags registry (packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php), the get_by_post_type method is designed to return tags with empty post_types arrays regardless of the input post_type parameter (even if empty/whitespace). This is the intended behavior as tags with empty post_types are considered universal tags that apply to all post types.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
🧬 Code graph analysis (11)
plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/includes/rest-api/Server.php (1)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php (1)
  • Controller (27-351)
plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php (5)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (2)
  • EmailsSettingsSchema (27-621)
  • init (61-63)
plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCTransactionalEmailPostsGenerator.php (1)
  • WCTransactionalEmailPostsGenerator (21-273)
packages/php/email-editor/src/class-email-editor-container.php (1)
  • Email_Editor_Container (45-304)
packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php (1)
  • Personalization_Tags_Registry (17-140)
packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tag.php (1)
  • Personalization_Tag (16-203)
plugins/woocommerce/includes/emails/class-wc-email-new-order.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/includes/emails/class-wc-email-failed-order.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php (1)
plugins/woocommerce/includes/emails/class-wc-email.php (1)
  • get_preheader_field (1235-1244)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php (5)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/AbstractController.php (1)
  • AbstractController (30-323)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (4)
  • EmailsSettingsSchema (27-621)
  • init (61-63)
  • get_item_response (219-246)
  • validate_and_sanitize_settings (440-476)
plugins/woocommerce/includes/rest-api/Server.php (1)
  • init (46-50)
plugins/woocommerce/includes/wc-rest-functions.php (1)
  • wc_rest_check_manager_permissions (341-355)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Email/Controller.php (1)
  • Controller (27-416)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (5)
packages/php/email-editor/src/class-email-editor-container.php (1)
  • Email_Editor_Container (45-304)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/AbstractSchema.php (1)
  • AbstractSchema (26-106)
packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php (1)
  • Personalization_Tags_Registry (17-140)
plugins/woocommerce/includes/emails/class-wc-email.php (6)
  • WC_Email (33-1710)
  • is_customer_email (828-830)
  • is_manual (819-821)
  • get_recipient (605-619)
  • get_preheader (565-580)
  • get_additional_content (522-533)
plugins/woocommerce/includes/wc-formatting-functions.php (1)
  • wc_bool_to_string (37-42)
🪛 PHPMD (2.15.0)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php

109-109: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)


136-136: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)

plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php

219-219: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (31)
  • GitHub Check: Blocks e2e tests - Legacy MiniCart 1/3 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 8/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests - Legacy MiniCart 2/3 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 6/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 7/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 4/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 5/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
  • GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 1/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
  • GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta3] 2/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta3] 1/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: build
🔇 Additional comments (11)
plugins/woocommerce/changelog/wooprd-926-move-notifications-listing-api-to-woocommerce (1)

1-5: LGTM!

The changelog entry is well-formed and appropriately categorized as a patch-level addition for the experimental V4 settings/emails API.

plugins/woocommerce/includes/emails/class-wc-email.php (1)

1191-1193: LGTM!

The conditional addition of the preheader field is properly gated behind the block_email_editor_enabled feature flag, ensuring backward compatibility.

plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php (1)

234-236: LGTM!

The preheader field is correctly added using the inherited method, following the same pattern as the cc/bcc fields above it.

plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php (1)

355-357: LGTM!

The preheader field addition follows the established pattern and is properly gated behind the block_email_editor_enabled flag.

plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php (1)

224-226: LGTM!

The implementation is consistent with the preheader field additions in the other email classes.

plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php (1)

374-376: LGTM!

The preheader field is correctly added to the POS refund email, maintaining consistency with the other email classes.

plugins/woocommerce/includes/emails/class-wc-email-new-order.php (1)

263-265: LGTM!

The preheader field addition is properly implemented following the consistent pattern across all email classes.

plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php (1)

258-260: LGTM!

The preheader field is correctly added to the customer invoice email, completing the consistent implementation across all email classes in this PR.

plugins/woocommerce/includes/emails/class-wc-email-failed-order.php (1)

235-237: Preheader field gating looks correct

Feature flag check lines up with other email classes, and reusing get_preheader_field() keeps the settings surface consistent with the shared schema.

plugins/woocommerce/includes/rest-api/Server.php (1)

27-246: New controller registration wired correctly

Import alias and get_v4_controllers() entry follow existing patterns, so the new /wc/v4/settings/emails routes will be discoverable once the feature flag is on.

plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php (1)

55-293: Endpoint implementation aligns with existing V4 patterns

Route registration, permission checks, and update flow mirror the other settings controllers, and delegating schema work keeps data shaping consistent.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php (1)

83-86: Nice fix: feature flag is now restored in tearDown().

Capturing the previous value before flipping the option prevents cross-test leakage. Good cleanup.

🧹 Nitpick comments (5)
plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php (2)

664-686: Assert link type to prevent regressions.

Add a strict type check so the API never emits a boolean for link again.

 		// Verify types.
 		$this->assertIsString( $item['id'] );
 		$this->assertIsString( $item['title'] );
+		$this->assertIsString( $item['link'] );
 		$this->assertTrue( is_int( $item['post_id'] ) || is_null( $item['post_id'] ), 'post_id should be int or null' );

598-601: Make preheader expectation explicit.

Block editor is enabled in setUp(); preheader should exist. Remove the conditional to catch regressions.

-		if ( isset( $data['values']['preheader'] ) ) {
-			$this->assertEquals( 'Check your order [woocommerce/order-number]', $data['values']['preheader'] );
-		}
+		$this->assertArrayHasKey( 'preheader', $data['values'] );
+		$this->assertEquals( 'Check your order [woocommerce/order-number]', $data['values']['preheader'] );
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (3)

219-252: Silence PHPMD: mark the request parameter as intentionally unused.

Rename the parameter to $_request to satisfy “UnusedFormalParameter”.

-	public function get_item_response( $email, WP_REST_Request $request, array $include_fields = array() ): array {
+	public function get_item_response( $email, WP_REST_Request $_request, array $include_fields = array() ): array {

345-365: Guard against preg_replace returning null.

preg_replace may return null on PCRE errors. Fall back to the original value.

-		$unwrapped_value = preg_replace( '/<!--(\[(?:' . $prefixes_pattern . ')\/[^\]]+\])-->/i', '$1', $value );
-		return $unwrapped_value;
+		$unwrapped_value = preg_replace( '/<!--(\[(?:' . $prefixes_pattern . ')\/[^\]]+\])-->/i', '$1', $value );
+		return is_string( $unwrapped_value ) ? $unwrapped_value : $value;

390-392: Same null-guard for wrapping.

Apply the same defensive check here.

-		return preg_replace( '/(?<!<!--)(\[(?:' . $prefixes_pattern . ')\/[^\]]+\])(?!-->)/i', '<!--$1-->', $value );
+		$wrapped = preg_replace( '/(?<!<!--)(\[(?:' . $prefixes_pattern . ')\/[^\]]+\])(?!-->)/i', '<!--$1-->', $value );
+		return is_string( $wrapped ) ? $wrapped : $value;
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7e330a and 00995de.

📒 Files selected for processing (2)
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (1 hunks)
  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)

**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable

Files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
plugins/woocommerce/tests/**/*.php

📄 CodeRabbit inference engine (.cursor/rules/woo-phpunit.mdc)

plugins/woocommerce/tests/**/*.php: Ensure test classes define public setUp() and tearDown() methods (not protected)
All PHPUnit test methods must be public, not protected
Add declare(strict_types=1); at the top of each test file
Test classes should extend WC_Unit_Test_Case

Files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
**/*.{php,js,jsx,tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/avoid-regex.mdc)

**/*.{php,js,jsx,tsx,ts}: Avoid using regular expressions unless absolutely necessary to favor readability and maintainability
Only consider regex when no built-in language alternative (string/array APIs) fits the need
Only use regex when performance is critical and faster than alternatives, with measurements to justify
Use regex for complex pattern matching only if the pattern is well-documented and thoroughly tested
Allow regex when maintaining legacy code where an existing, correct pattern is being modified
If regex is necessary, document the pattern extensively to explain what it matches
If regex is necessary, add comprehensive tests covering edge cases and potential security issues
Use named capture groups in regex to improve readability when supported
Validate input before applying regex to ensure it is safe
Assess and mitigate security risks when using regex, including ReDoS and injection vulnerabilities
Avoid regex patterns that can cause catastrophic backtracking (ReDoS)
Do not construct regex from untrusted input to prevent injection attacks
Ensure regex patterns do not overmatch and unintentionally capture unexpected inputs

Files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
**/*.{php,js,ts,jsx,tsx}

⚙️ CodeRabbit configuration file

**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:

  • Guards against unexpected inputs.
  • Sanitizes and validates any potentially dangerous inputs.
  • Is backwards compatible.
  • Is readable and intuitive.
  • Has unit or E2E tests where applicable.
    When making any changes to code that deletes or modifies orders/products/customer data, make sure that there are
    sufficient checks in place to prevent accidental data loss. As an example, if deleting a draft order, check that
    the order status is indeed draft or checkout-draft. Also think about whether race conditions could occur and
    delete orders that don't belong to the current customer. When in doubt, ask for clarification in the PR comments.

Files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
🧠 Learnings (18)
📚 Learning: 2025-09-03T11:50:02.208Z
Learnt from: tpaksu
Repo: woocommerce/woocommerce PR: 60735
File: plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Fulfillments/class-wc-rest-fulfillments-v4-controller-tests.php:10-10
Timestamp: 2025-09-03T11:50:02.208Z
Learning: For REST API controller tests in plugins/woocommerce/tests/**/*.php, test classes should extend WC_REST_Unit_Test_Case instead of WC_Unit_Test_Case because REST routes need to be registered before tests run.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-08-18T06:11:48.768Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/woo-phpunit.mdc:0-0
Timestamp: 2025-08-18T06:11:48.768Z
Learning: Applies to plugins/woocommerce/tests/**/*.php : Test classes should extend WC_Unit_Test_Case

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-08-12T14:22:05.865Z
Learnt from: NeosinneR
Repo: woocommerce/woocommerce PR: 60325
File: plugins/woocommerce/tests/php/includes/settings/class-wc-settings-accounts-test.php:0-0
Timestamp: 2025-08-12T14:22:05.865Z
Learning: In WooCommerce settings tests, the woocommerce_enable_delayed_account_creation setting is conditionally present based on wp_is_block_theme() being true OR (wp_is_block_theme() being false AND CartCheckoutUtils::is_checkout_block_default() being true). In test environments with block themes, checking only wp_is_block_theme() is sufficient to determine if the setting should be expected in the settings array.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-06-16T09:20:22.981Z
Learnt from: gigitux
Repo: woocommerce/woocommerce PR: 58846
File: plugins/woocommerce/client/blocks/tests/e2e/tests/all-products/all-products.block_theme.spec.ts:41-52
Timestamp: 2025-06-16T09:20:22.981Z
Learning: In WooCommerce E2E tests, the database is reset to the initial state for each test, so there's no need to manually restore global template changes (like clearing the header template) as the test infrastructure handles cleanup automatically.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-06-25T15:39:25.166Z
Learnt from: vladolaru
Repo: woocommerce/woocommerce PR: 59160
File: plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsProviders/WooPayments/WooPaymentsServiceTest.php:360-373
Timestamp: 2025-06-25T15:39:25.166Z
Learning: Test mocks should accurately simulate the behavior of the functions they replace, including return value semantics. For WordPress functions like `update_option`, the mock should properly return `false` when the value hasn't changed and `true` when it has, to avoid masking logic errors in tests.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-08-14T08:20:36.357Z
Learnt from: Aljullu
Repo: woocommerce/woocommerce PR: 60191
File: plugins/woocommerce/client/blocks/tests/e2e/tests/single-product-template/single-product-template-compatibility-layer.spec.ts:4-4
Timestamp: 2025-08-14T08:20:36.357Z
Learning: In WooCommerce e2e tests, some test files intentionally use hard-coded "woocommerce/woocommerce//" template IDs instead of BLOCK_THEME_SLUG to test backwards compatibility with the legacy plugin-scoped template ID format. These should not be updated to use the dynamic slug constant as they serve a specific testing purpose.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-10-24T13:25:49.900Z
Learnt from: hannahtinkler
Repo: woocommerce/woocommerce PR: 61384
File: plugins/woocommerce/tests/php/src/Internal/PushNotifications/Entities/PushTokenTest.php:208-216
Timestamp: 2025-10-24T13:25:49.900Z
Learning: In plugins/woocommerce/tests/**/*.php files, omit setUp() and tearDown() methods when they are not needed, as the project's linting configuration makes it easier to omit these methods than to add them with phpcs:ignore comments.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-08-14T08:22:34.886Z
Learnt from: Aljullu
Repo: woocommerce/woocommerce PR: 60191
File: plugins/woocommerce/client/blocks/tests/e2e/tests/product-filters/rating-filter-editor.block_theme.spec.ts:36-36
Timestamp: 2025-08-14T08:22:34.886Z
Learning: In WooCommerce e2e tests, some test files intentionally use hard-coded "woocommerce/woocommerce//" template slugs (not just template IDs) instead of BLOCK_THEME_SLUG to test backwards compatibility with the legacy plugin-scoped template slug format. These should not be updated to use the dynamic slug constant as they serve a specific backwards compatibility testing purpose.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-08-21T07:39:42.952Z
Learnt from: NeosinneR
Repo: woocommerce/woocommerce PR: 60520
File: plugins/woocommerce/src/Internal/Admin/EmailPreview/EmailPreview.php:257-259
Timestamp: 2025-08-21T07:39:42.952Z
Learning: In WooCommerce EmailPreview::ensure_links_open_in_new_tab(), the XML declaration removal regex should not be anchored to the beginning since DOCTYPE appears before the XML declaration in the HTML output.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-06-23T05:47:52.696Z
Learnt from: samueljseay
Repo: woocommerce/woocommerce PR: 59051
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/index.tsx:66-70
Timestamp: 2025-06-23T05:47:52.696Z
Learning: For WooCommerce mini-cart blocks in plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/, the standardized conditional pattern for experimental features should be `if ( isExperimentalMiniCartEnabled() ) { blockSettings.save = () => <InnerBlocks.Content />; }` - defaulting to the traditional Save component and only overriding when the experimental feature is enabled.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
📚 Learning: 2025-07-29T08:05:14.107Z
Learnt from: lysyjan
Repo: woocommerce/woocommerce PR: 60072
File: packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php:110-118
Timestamp: 2025-07-29T08:05:14.107Z
Learning: In WooCommerce email editor personalization tags registry (packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php), the get_by_post_type method is designed to return tags with empty post_types arrays regardless of the input post_type parameter (even if empty/whitespace). This is the intended behavior as tags with empty post_types are considered universal tags that apply to all post types.

Applied to files:

  • plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php
  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-08-21T07:39:42.952Z
Learnt from: NeosinneR
Repo: woocommerce/woocommerce PR: 60520
File: plugins/woocommerce/src/Internal/Admin/EmailPreview/EmailPreview.php:257-259
Timestamp: 2025-08-21T07:39:42.952Z
Learning: In WooCommerce email preview functionality (EmailPreview.php), rel attributes on links should be overwritten rather than preserved for safety reasons, and anchor links (#) can be treated the same as external links since they're not expected in email previews.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-06-26T12:13:32.062Z
Learnt from: triple0t
Repo: woocommerce/woocommerce PR: 59186
File: packages/js/email-editor/src/store/initial-state.ts:9-10
Timestamp: 2025-06-26T12:13:32.062Z
Learning: In WooCommerce email editor store initialization (packages/js/email-editor/src/store/initial-state.ts), the current_post_id and current_post_type from window.WooCommerceEmailEditor are required parameters that should cause explicit errors if missing, rather than using fallback values or optional chaining. The design preference is to fail fast when critical initialization data is unavailable.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-07-30T20:52:28.759Z
Learnt from: xristos3490
Repo: woocommerce/woocommerce PR: 59947
File: plugins/woocommerce/src/Internal/DataStores/StockNotifications/StockNotificationsDataStore.php:89-106
Timestamp: 2025-07-30T20:52:28.759Z
Learning: In WooCommerce database schema design, email field lengths should match WordPress Core's wp_users table (100 characters) for consistency, rather than following RFC 5321's maximum of 320 characters.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-10-03T09:27:22.888Z
Learnt from: dmallory42
Repo: woocommerce/woocommerce PR: 61244
File: plugins/woocommerce/src/RestApi/Routes/V4/PaymentGateways/Controller.php:236-239
Timestamp: 2025-10-03T09:27:22.888Z
Learning: In the WooCommerce REST API V4 Payment Gateways controller (`plugins/woocommerce/src/RestApi/Routes/V4/PaymentGateways/Controller.php`), the `title` and `description` fields are intentionally validated using `validate_setting_text_field` even when their form field definitions specify different field types. This is by design and should not be flagged as an inconsistency.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-08-27T14:31:54.181Z
Learnt from: allilevine
Repo: woocommerce/woocommerce PR: 60514
File: packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-table.php:478-515
Timestamp: 2025-08-27T14:31:54.181Z
Learning: wp_kses can be overly restrictive in email editor contexts and may strip out all caption content instead of sanitizing it. WP_HTML_Tag_Processor with custom security validation is preferred for HTML sanitization in WooCommerce email editor blocks.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-10-23T01:44:03.397Z
Learnt from: peterwilsoncc
Repo: woocommerce/woocommerce PR: 60447
File: plugins/woocommerce/templates/emails/email-order-details.php:96-131
Timestamp: 2025-10-23T01:44:03.397Z
Learning: In WooCommerce email templates (plugins/woocommerce/templates/emails/), when displaying order details, the order items table and order totals should be separate tables rather than combined with <tfoot>. This follows accessibility guidance: the totals are semantically different information from the line items and should not be forced into a single table structure just for visual positioning. The split improves accessibility for assistive technology users.

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
📚 Learning: 2025-08-08T13:47:37.272Z
Learnt from: lysyjan
Repo: woocommerce/woocommerce PR: 60165
File: plugins/woocommerce/src/Internal/EmailEditor/PageRenderer.php:100-104
Timestamp: 2025-08-08T13:47:37.272Z
Learning: In WooCommerce email editor PHP package (packages/php/email-editor), the localization data passed through the `woocommerce_email_editor_script_localization_data` filter always includes the `editor_settings` key as an array (prepared by `Assets_Manager`). This guarantees nested writes like `['editor_settings']['isFullScreenForced']` are safe in PageRenderer::update_localized_data().

Applied to files:

  • plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php
🧬 Code graph analysis (2)
plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Settings/Emails/EmailsSettingsControllerTest.php (5)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (2)
  • EmailsSettingsSchema (27-627)
  • init (61-63)
plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCTransactionalEmailPostsGenerator.php (1)
  • WCTransactionalEmailPostsGenerator (21-273)
packages/php/email-editor/src/class-email-editor-container.php (1)
  • Email_Editor_Container (45-304)
packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php (1)
  • Personalization_Tags_Registry (17-140)
packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tag.php (1)
  • Personalization_Tag (16-203)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (5)
packages/php/email-editor/src/class-email-editor-container.php (1)
  • Email_Editor_Container (45-304)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/AbstractSchema.php (1)
  • AbstractSchema (26-106)
packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php (1)
  • Personalization_Tags_Registry (17-140)
plugins/woocommerce/includes/emails/class-wc-email.php (6)
  • get_email_group_title (469-482)
  • is_customer_email (828-830)
  • is_manual (819-821)
  • get_recipient (605-619)
  • get_preheader (565-580)
  • get_additional_content (522-533)
plugins/woocommerce/includes/wc-formatting-functions.php (1)
  • wc_bool_to_string (37-42)
🪛 PHPMD (2.15.0)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php

219-219: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (33)
  • GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 1/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests - Legacy MiniCart - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 7/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 8/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 4/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 5/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 6/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
  • GitHub Check: Blocks e2e tests - Legacy MiniCart 1/3 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
  • GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta3] 2/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta3] 1/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: review-with-tracking
  • GitHub Check: build
🔇 Additional comments (1)
plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php (1)

226-231: Good hardening: normalize link to an empty string.

Prevents boolean leaks from get_permalink(false). LGTM.

@costasovo costasovo requested a review from yuliyan November 7, 2025 16:49
@costasovo costasovo changed the title Wooprd 926 move notifications listing api to woocommerce Add experimental emails settings API to V4 Nov 10, 2025
Copy link
Contributor

@yuliyan yuliyan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good and works as expected. LGTM!

Nit: Could you please update the PR title (or the commit message) before mergin? Just noticed it's already updated.

@yuliyan yuliyan assigned costasovo and unassigned yuliyan Nov 10, 2025
@costasovo costasovo merged commit 901da7e into trunk Nov 12, 2025
59 of 60 checks passed
@costasovo costasovo deleted the wooprd-926-move-notifications-listing-api-to-woocommerce branch November 12, 2025 08:22
@github-actions
Copy link
Contributor

⚠️ API Documentation Reminder

Hi @costasovo! Your PR contains REST API changes. Please consider updating the REST API documentation if your changes affect the public API.

Changed API files:

plugins/woocommerce/includes/rest-api/Server.php

@github-actions github-actions bot added this to the 10.4.0 milestone Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugin: woocommerce Issues related to the WooCommerce Core plugin.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants