From 9e4c2c8416e4dd91756eaf7207a64d1648eced05 Mon Sep 17 00:00:00 2001 From: Vishal Singh Date: Thu, 9 Apr 2026 11:20:43 +0530 Subject: [PATCH 1/2] Hooks/filters parity for preview & update functionality --- ...ass-wp-customize-nav-menu-item-setting.php | 36 ++++- .../tests/customize/nav-menu-item-setting.php | 125 ++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php b/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php index 1de7bfdc20581..d7be327e903d5 100644 --- a/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php +++ b/src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php @@ -471,7 +471,29 @@ public function preview() { add_filter( 'wp_get_nav_menu_items', array( __CLASS__, 'sort_wp_get_nav_menu_items' ), 1000, 3 ); } - // @todo Add get_post_metadata filters for plugins to add their data. + /** + * Fires when the WP_Customize_Nav_Menu_Item_Setting::preview() method is called + * for a specific nav menu item setting. + * + * The dynamic portion of the hook name, `$this->id`, refers to the setting ID. + * + * @since 7.1.0 + * + * @param WP_Customize_Nav_Menu_Item_Setting $setting WP_Customize_Nav_Menu_Item_Setting instance. + */ + do_action( "customize_preview_{$this->id}", $this ); + + /** + * Fires when the WP_Customize_Nav_Menu_Item_Setting::preview() method is called + * for nav menu item settings. + * + * The dynamic portion of the hook name, `$this->type`, refers to the setting type. + * + * @since 7.1.0 + * + * @param WP_Customize_Nav_Menu_Item_Setting $setting WP_Customize_Nav_Menu_Item_Setting instance. + */ + do_action( "customize_preview_{$this->type}", $this ); return true; } @@ -888,6 +910,18 @@ protected function update( $value ) { } } + /** + * Fires when the WP_Customize_Nav_Menu_Item_Setting::update() method is called. + * + * The dynamic portion of the hook name, `$this->type`, refers to the setting type. + * + * @since 7.1.0 + * + * @param array|false $value Value of the setting. False if the menu item is to be deleted. + * @param WP_Customize_Nav_Menu_Item_Setting $setting WP_Customize_Nav_Menu_Item_Setting instance. + */ + do_action( "customize_update_{$this->type}", $value, $this ); + return ( 'error' !== $this->update_status ); } diff --git a/tests/phpunit/tests/customize/nav-menu-item-setting.php b/tests/phpunit/tests/customize/nav-menu-item-setting.php index 85cf0f10f7b5b..5a2a02cf5eeaf 100644 --- a/tests/phpunit/tests/customize/nav-menu-item-setting.php +++ b/tests/phpunit/tests/customize/nav-menu-item-setting.php @@ -843,6 +843,131 @@ public function test_save_deleted() { $this->assertSame( 'deleted', $update_result['status'] ); } + /** + * Tests that preview() fires the customize_preview_{$id} and customize_preview_{$type} action hooks. + * + * @ticket 55051 + * + * @covers WP_Customize_Nav_Menu_Item_Setting::preview + */ + public function test_preview_fires_action_hooks() { + do_action( 'customize_register', $this->wp_customize ); + + $menu_id = wp_create_nav_menu( 'Primary' ); + $post_id = self::factory()->post->create( array( 'post_title' => 'Hello World' ) ); + $item_id = wp_update_nav_menu_item( + $menu_id, + 0, + array( + 'menu-item-type' => 'post_type', + 'menu-item-object' => 'post', + 'menu-item-object-id' => $post_id, + 'menu-item-title' => 'Hello World', + 'menu-item-status' => 'publish', + ) + ); + + $setting_id = "nav_menu_item[$item_id]"; + $setting = new WP_Customize_Nav_Menu_Item_Setting( $this->wp_customize, $setting_id ); + $this->wp_customize->set_post_value( + $setting_id, + array( + 'type' => 'post_type', + 'object' => 'post', + 'object_id' => $post_id, + 'title' => 'Updated Title', + 'status' => 'publish', + 'nav_menu_term_id' => $menu_id, + ) + ); + + $preview_id_action_count = 0; + $preview_type_action_count = 0; + $preview_id_setting = null; + $preview_type_setting = null; + + add_action( + "customize_preview_{$setting_id}", + function ( $s ) use ( &$preview_id_action_count, &$preview_id_setting ) { + ++$preview_id_action_count; + $preview_id_setting = $s; + } + ); + + add_action( + 'customize_preview_nav_menu_item', + function ( $s ) use ( &$preview_type_action_count, &$preview_type_setting ) { + ++$preview_type_action_count; + $preview_type_setting = $s; + } + ); + + $setting->preview(); + + $this->assertSame( 1, $preview_id_action_count, 'customize_preview_{$id} action was not fired exactly once.' ); + $this->assertSame( $setting, $preview_id_setting, 'customize_preview_{$id} action did not receive the setting instance.' ); + $this->assertSame( 1, $preview_type_action_count, 'customize_preview_{$type} action was not fired exactly once.' ); + $this->assertSame( $setting, $preview_type_setting, 'customize_preview_{$type} action did not receive the setting instance.' ); + } + + /** + * Tests that update() fires the customize_update_{$type} action hook. + * + * @ticket 55051 + * + * @covers WP_Customize_Nav_Menu_Item_Setting::update + */ + public function test_update_fires_action_hook() { + do_action( 'customize_register', $this->wp_customize ); + + $menu_id = wp_create_nav_menu( 'Primary' ); + $post_id = self::factory()->post->create( array( 'post_title' => 'Hello World' ) ); + $item_id = wp_update_nav_menu_item( + $menu_id, + 0, + array( + 'menu-item-type' => 'post_type', + 'menu-item-object' => 'post', + 'menu-item-object-id' => $post_id, + 'menu-item-title' => 'Hello World', + 'menu-item-status' => 'publish', + ) + ); + + $post_value = array( + 'type' => 'post_type', + 'object' => 'post', + 'object_id' => $post_id, + 'title' => 'Updated Title', + 'status' => 'publish', + 'nav_menu_term_id' => $menu_id, + ); + $setting_id = "nav_menu_item[$item_id]"; + $setting = new WP_Customize_Nav_Menu_Item_Setting( $this->wp_customize, $setting_id ); + $this->wp_customize->set_post_value( $setting_id, $post_value ); + + $update_action_count = 0; + $update_action_value = null; + $update_action_setting = null; + + add_action( + 'customize_update_nav_menu_item', + function ( $value, $s ) use ( &$update_action_count, &$update_action_value, &$update_action_setting ) { + ++$update_action_count; + $update_action_value = $value; + $update_action_setting = $s; + }, + 10, + 2 + ); + + $setting->save(); + + $this->assertSame( 1, $update_action_count, 'customize_update_{$type} action was not fired exactly once.' ); + $this->assertSame( $setting, $update_action_setting, 'customize_update_{$type} action did not receive the setting instance.' ); + $this->assertIsArray( $update_action_value, 'customize_update_{$type} action did not receive the value as an array.' ); + } + /** * @ticket 33665 */ From 6b0afe76183ecb9b2db252b9438eb630278716f4 Mon Sep 17 00:00:00 2001 From: Vishal Singh Date: Thu, 9 Apr 2026 12:52:09 +0530 Subject: [PATCH 2/2] Re-run CI