Commit bf7b2d51705 for woocommerce
commit bf7b2d517055496b3a4af8ad6760cd270322ebc9
Author: Pavel Dohnal <pavel.dohnal@automattic.com>
Date: Mon Apr 6 12:05:45 2026 +0200
Fix post_types missing from view context on WP 7.0 (#64023)
The compatibility guard in register_post_types_to_api() only checked
whether post_types existed in the schema. On WP 7.0 RC2 the property
is present but without a view context, so the guard returned early
and register_rest_field was never called. Downstream JS consumers
requesting context=view then received no post_types field, breaking
the template-select modal.
Check for view in the context array instead of mere presence so
the field is still registered when WP adds post_types without
exposing it in view context.
diff --git a/packages/php/email-editor/changelog/fix-register-post-types-view-context-check b/packages/php/email-editor/changelog/fix-register-post-types-view-context-check
new file mode 100644
index 00000000000..22902d83fcf
--- /dev/null
+++ b/packages/php/email-editor/changelog/fix-register-post-types-view-context-check
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix `register_post_types_to_api()` to verify view context availability before skipping field registration on WordPress 7.0+
diff --git a/packages/php/email-editor/src/Engine/Templates/class-templates.php b/packages/php/email-editor/src/Engine/Templates/class-templates.php
index 083265060c1..8b892e2c761 100644
--- a/packages/php/email-editor/src/Engine/Templates/class-templates.php
+++ b/packages/php/email-editor/src/Engine/Templates/class-templates.php
@@ -107,8 +107,11 @@ class Templates {
public function register_post_types_to_api(): void {
$controller = new \WP_REST_Templates_Controller( 'wp_template' );
$schema = $controller->get_item_schema();
- // Future compatibility check if the post_types property is already registered.
- if ( isset( $schema['properties']['post_types'] ) ) {
+ // Skip registration only when post_types is natively available in the view context.
+ // WP 7.0 adds the property but only in the edit context; we must still register
+ // the field so that context=view responses include it.
+ $post_types_context = $schema['properties']['post_types']['context'] ?? array();
+ if ( in_array( 'view', $post_types_context, true ) ) {
return;
}
register_rest_field(
diff --git a/packages/php/email-editor/tests/unit/Engine/Templates/Templates_Test.php b/packages/php/email-editor/tests/unit/Engine/Templates/Templates_Test.php
new file mode 100644
index 00000000000..ce30a39f772
--- /dev/null
+++ b/packages/php/email-editor/tests/unit/Engine/Templates/Templates_Test.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * This file is part of the WooCommerce Email Editor package.
+ *
+ * @package Automattic\WooCommerce\EmailEditor
+ */
+
+declare(strict_types=1);
+
+use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates;
+use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates_Registry;
+
+/**
+ * Test cases for Templates::register_post_types_to_api().
+ */
+class Templates_Test extends Email_Editor_Unit_Test {
+
+ /**
+ * The System Under Test.
+ *
+ * @var Templates
+ */
+ private Templates $sut;
+
+ /**
+ * Set up test fixtures.
+ */
+ protected function setUp(): void {
+ parent::setUp();
+ $GLOBALS['wc_ee_rest_field_registered'] = false;
+ $GLOBALS['wc_ee_test_schema'] = array( 'properties' => array() );
+ $this->sut = new Templates( new Templates_Registry() );
+ }
+
+ /**
+ * Tear down test fixtures.
+ */
+ protected function tearDown(): void {
+ unset( $GLOBALS['wc_ee_rest_field_registered'], $GLOBALS['wc_ee_test_schema'] );
+ parent::tearDown();
+ }
+
+ /**
+ * Test that the field is registered when post_types is absent.
+ *
+ * @testdox Should register the field when post_types is absent from the schema (WP ≤ 6.9).
+ */
+ public function test_registers_field_when_post_types_absent_from_schema(): void {
+ $GLOBALS['wc_ee_test_schema'] = array( 'properties' => array() );
+
+ $this->sut->register_post_types_to_api();
+
+ $this->assertTrue( $GLOBALS['wc_ee_rest_field_registered'], 'Field should be registered when post_types is absent from the schema.' );
+ }
+
+ /**
+ * Test that registration is skipped when view context is present.
+ *
+ * @testdox Should skip registration when post_types is present with view context (future WP).
+ */
+ public function test_skips_registration_when_view_context_present(): void {
+ $GLOBALS['wc_ee_test_schema'] = array(
+ 'properties' => array(
+ 'post_types' => array( 'context' => array( 'view', 'edit', 'embed' ) ),
+ ),
+ );
+
+ $this->sut->register_post_types_to_api();
+
+ $this->assertFalse( $GLOBALS['wc_ee_rest_field_registered'], 'Field should not be registered when post_types is natively available in the view context.' );
+ }
+
+ /**
+ * Test that the field is registered when view context is missing (WP 7.0 scenario).
+ *
+ * @testdox Should register the field when post_types is present but view context is missing (WP 7.0).
+ */
+ public function test_registers_field_when_post_types_present_but_view_context_missing(): void {
+ $GLOBALS['wc_ee_test_schema'] = array(
+ 'properties' => array(
+ 'post_types' => array( 'context' => array( 'edit' ) ),
+ ),
+ );
+
+ $this->sut->register_post_types_to_api();
+
+ $this->assertTrue( $GLOBALS['wc_ee_rest_field_registered'], 'Field should be registered when post_types is present but only in the edit context.' );
+ }
+
+ /**
+ * Test that the field is registered when post_types has no context key.
+ *
+ * @testdox Should register the field when post_types is present but has no context key.
+ */
+ public function test_registers_field_when_post_types_present_but_no_context_key(): void {
+ $GLOBALS['wc_ee_test_schema'] = array(
+ 'properties' => array(
+ 'post_types' => array( 'type' => 'array' ),
+ ),
+ );
+
+ $this->sut->register_post_types_to_api();
+
+ $this->assertTrue( $GLOBALS['wc_ee_rest_field_registered'], 'Field should be registered when post_types has no context key.' );
+ }
+}
diff --git a/packages/php/email-editor/tests/unit/stubs.php b/packages/php/email-editor/tests/unit/stubs.php
index af8677c2fcd..7fcb591b7eb 100644
--- a/packages/php/email-editor/tests/unit/stubs.php
+++ b/packages/php/email-editor/tests/unit/stubs.php
@@ -451,3 +451,40 @@ if ( ! class_exists( \IntegrationTester::class ) ) {
}
}
}
+
+if ( ! class_exists( \WP_REST_Templates_Controller::class ) ) {
+ /**
+ * Stub for WP_REST_Templates_Controller used in unit tests.
+ */
+ class WP_REST_Templates_Controller {
+ /**
+ * Constructor.
+ *
+ * @param string $post_type Post type slug.
+ */
+ public function __construct( string $post_type ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
+ }
+
+ /**
+ * Returns the schema configured via $GLOBALS['wc_ee_test_schema'].
+ *
+ * @return array
+ */
+ public function get_item_schema(): array {
+ return $GLOBALS['wc_ee_test_schema'] ?? array( 'properties' => array() );
+ }
+ }
+}
+
+if ( ! function_exists( 'register_rest_field' ) ) {
+ /**
+ * Mock register_rest_field function.
+ *
+ * @param string|array $object_type Object type or array of types.
+ * @param string $attribute Attribute name.
+ * @param array $args Optional. Field arguments.
+ */
+ function register_rest_field( $object_type, $attribute, $args = array() ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
+ $GLOBALS['wc_ee_rest_field_registered'] = true;
+ }
+}