wp/wp-admin/js/customize-nav-menus.js
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
--- a/wp/wp-admin/js/customize-nav-menus.js	Fri Sep 05 18:40:08 2025 +0200
+++ b/wp/wp-admin/js/customize-nav-menus.js	Fri Sep 05 18:52:52 2025 +0200
@@ -223,6 +223,9 @@
 
 			this.$el.on( 'input', '#custom-menu-item-name.invalid, #custom-menu-item-url.invalid', function() {
 				$( this ).removeClass( 'invalid' );
+				var errorMessageId = $( this ).attr( 'aria-describedby' );
+				$( '#' + errorMessageId ).hide();
+				$( this ).removeAttr( 'aria-invalid' ).removeAttr( 'aria-describedby' );
 			});
 
 			// Load available items if it looks like we'll need them.
@@ -546,8 +549,11 @@
 			var menuItem,
 				itemName = $( '#custom-menu-item-name' ),
 				itemUrl = $( '#custom-menu-item-url' ),
+				urlErrorMessage = $( '#custom-url-error' ),
+				nameErrorMessage = $( '#custom-name-error' ),
 				url = itemUrl.val().trim(),
-				urlRegex;
+				urlRegex,
+				errorText;
 
 			if ( ! this.currentMenuControl ) {
 				return;
@@ -566,15 +572,37 @@
 			 * so this pattern does not need to be complete.
 			 */
 			urlRegex = /^((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#)/;
-
-			if ( '' === itemName.val() ) {
-				itemName.addClass( 'invalid' );
-				return;
-			} else if ( ! urlRegex.test( url ) ) {
-				itemUrl.addClass( 'invalid' );
+			if ( ! urlRegex.test( url ) || '' === itemName.val() ) {
+				if ( ! urlRegex.test( url ) ) {
+					itemUrl.addClass( 'invalid' )
+						.attr( 'aria-invalid', 'true' )
+						.attr( 'aria-describedby', 'custom-url-error' );
+					urlErrorMessage.show();
+					errorText = urlErrorMessage.text();
+					// Announce error message via screen reader
+					wp.a11y.speak( errorText, 'assertive' );
+				}
+				if ( '' === itemName.val() ) {
+					itemName.addClass( 'invalid' )
+						.attr( 'aria-invalid', 'true' )
+						.attr( 'aria-describedby', 'custom-name-error' );
+					nameErrorMessage.show();
+					errorText = ( '' === errorText ) ? nameErrorMessage.text() : errorText + nameErrorMessage.text();
+					// Announce error message via screen reader
+					wp.a11y.speak( errorText, 'assertive' );
+				}
 				return;
 			}
 
+			urlErrorMessage.hide();
+			nameErrorMessage.hide();
+			itemName.removeClass( 'invalid' )
+				.removeAttr( 'aria-invalid', 'true' )
+				.removeAttr( 'aria-describedby', 'custom-name-error' );
+			itemUrl.removeClass( 'invalid' )
+				.removeAttr( 'aria-invalid', 'true' )
+				.removeAttr( 'aria-describedby', 'custom-name-error' );
+
 			menuItem = {
 				'title': itemName.val(),
 				'url': url,
@@ -1107,7 +1135,7 @@
 			var section = this,
 				$title;
 
-			$title = section.container.find( '.accordion-section-title:first' );
+			$title = section.container.find( '.accordion-section-title button:first' );
 			$title.find( '.menu-in-location' ).remove();
 			_.each( themeLocationSlugs, function( themeLocationSlug ) {
 				var $label, locationName;