Commit 5db53df0a8 for wordpress.org

commit 5db53df0a8af6a06b594d4e83dff51bda93ce48d
Author: Weston Ruter <weston@xwp.co>
Date:   Wed Feb 4 07:03:44 2026 +0000

    Code Editor: Allow saving with Ctrl/Cmd+S in Theme/Plugin Editors.

    * Keyboard shortcuts work when CodeMirror is not enabled (due to syntax highlighting not being enabled), and when the user is not focused inside the CodeMirror editor.
    * The autocomplete trigger is switched from `keyup` to `inputRead` to improve reliability, support IME composition, and prevent conflicts with modifier keys (e.g., releasing `Ctrl`/`Cmd` before `s` after a save).
    * A `updateErrorNotice` method is exposed on the code editor instance to ensure validation errors are displayed when a save via shortcut is attempted, preventing "silent" failures. Otherwise, the linting error notice is only shown when focus leaves the editor.
    * The form submission is modernized by replacing the deprecated jQuery `.submit()` shorthand with `.trigger( 'submit' )`.

    Developed in https://github.com/WordPress/wordpress-develop/pull/10851

    Props westonruter, Junaidkbr, evansolomon, desrosj, mukesh27, jonsurrell, spiraltee, chexee, andrewryno, tusharaddweb, gauri87, huzaifaalmesbah, ocean90, karmatosed, johnbillion, scribu, jcnetsys.
    Fixes #17133.

    Built from https://develop.svn.wordpress.org/trunk@61588


    git-svn-id: http://core.svn.wordpress.org/trunk@60899 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-admin/js/code-editor.js b/wp-admin/js/code-editor.js
index 4266f39292..bc57026385 100644
--- a/wp-admin/js/code-editor.js
+++ b/wp-admin/js/code-editor.js
@@ -46,7 +46,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 	 * @param {Function}   settings.onChangeLintingErrors - Callback for when there are changes to linting errors.
 	 * @param {Function}   settings.onUpdateErrorNotice - Callback to update error notice.
 	 *
-	 * @return {void}
+	 * @return {Function} Update error notice function.
 	 */
 	function configureLinting( editor, settings ) { // eslint-disable-line complexity
 		var currentErrorAnnotations = [], previouslyShownErrorAnnotations = [];
@@ -82,7 +82,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 			}

 			/*
-			 * Note that rules must be sent in the "deprecated" lint.options property
+			 * Note that rules must be sent in the "deprecated" lint.options property
 			 * to prevent linter from complaining about unrecognized options.
 			 * See <https://github.com/codemirror/CodeMirror/pull/4944>.
 			 */
@@ -209,6 +209,8 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 				updateErrorNotice();
 			}
 		});
+
+		return updateErrorNotice;
 	}

 	/**
@@ -261,6 +263,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 	 * @typedef {object} wp.codeEditor~CodeEditorInstance
 	 * @property {object} settings - The code editor settings.
 	 * @property {CodeMirror} codemirror - The CodeMirror instance.
+	 * @property {Function} updateErrorNotice - Force update the error notice.
 	 */

 	/**
@@ -282,7 +285,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 	 * @return {CodeEditorInstance} Instance.
 	 */
 	wp.codeEditor.initialize = function initialize( textarea, settings ) {
-		var $textarea, codemirror, instanceSettings, instance;
+		var $textarea, codemirror, instanceSettings, instance, updateErrorNotice;
 		if ( 'string' === typeof textarea ) {
 			$textarea = $( '#' + textarea );
 		} else {
@@ -294,16 +297,33 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {

 		codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror );

-		configureLinting( codemirror, instanceSettings );
+		updateErrorNotice = configureLinting( codemirror, instanceSettings );

 		instance = {
 			settings: instanceSettings,
-			codemirror: codemirror
+			codemirror,
+			updateErrorNotice,
 		};

 		if ( codemirror.showHint ) {
-			codemirror.on( 'keyup', function( editor, event ) { // eslint-disable-line complexity
-				var shouldAutocomplete, isAlphaKey = /^[a-zA-Z]$/.test( event.key ), lineBeforeCursor, innerMode, token;
+			codemirror.on( 'inputRead', function( editor, change ) {
+				var shouldAutocomplete, isAlphaKey, lineBeforeCursor, innerMode, token, char;
+
+				// Only trigger autocompletion for typed input or IME composition.
+				if ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) {
+					return;
+				}
+
+				// Only trigger autocompletion for single-character inputs.
+				// The text property is an array of strings, one for each line.
+				// We check that there is only one line and that line has only one character.
+				if ( 1 !== change.text.length || 1 !== change.text[0].length ) {
+					return;
+				}
+
+				char = change.text[0];
+				isAlphaKey = /^[a-zA-Z]$/.test( char );
+
 				if ( codemirror.state.completionActive && isAlphaKey ) {
 					return;
 				}
@@ -318,11 +338,11 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 				lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).substr( 0, codemirror.doc.getCursor().ch );
 				if ( 'html' === innerMode || 'xml' === innerMode ) {
 					shouldAutocomplete = (
-						'<' === event.key ||
-						( '/' === event.key && 'tag' === token.type ) ||
+						'<' === char ||
+						( '/' === char && 'tag' === token.type ) ||
 						( isAlphaKey && 'tag' === token.type ) ||
 						( isAlphaKey && 'attribute' === token.type ) ||
-						( '=' === event.key && (
+						( '=' === char && (
 							token.state.htmlState?.tagName ||
 							token.state.curState?.htmlState?.tagName
 						) )
@@ -330,17 +350,17 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
 				} else if ( 'css' === innerMode ) {
 					shouldAutocomplete =
 						isAlphaKey ||
-						':' === event.key ||
-						( ' ' === event.key && /:\s+$/.test( lineBeforeCursor ) );
+						':' === char ||
+						( ' ' === char && /:\s+$/.test( lineBeforeCursor ) );
 				} else if ( 'javascript' === innerMode ) {
-					shouldAutocomplete = isAlphaKey || '.' === event.key;
+					shouldAutocomplete = isAlphaKey || '.' === char;
 				} else if ( 'clike' === innerMode && 'php' === codemirror.options.mode ) {
 					shouldAutocomplete = isAlphaKey && ( 'keyword' === token.type || 'variable' === token.type );
 				}
 				if ( shouldAutocomplete ) {
 					codemirror.showHint( { completeSingle: false } );
 				}
-			});
+			} );
 		}

 		// Facilitate tabbing out of the editor.
diff --git a/wp-admin/js/code-editor.min.js b/wp-admin/js/code-editor.min.js
index e16666ef3a..e89d6f9d3a 100644
--- a/wp-admin/js/code-editor.min.js
+++ b/wp-admin/js/code-editor.min.js
@@ -1,2 +1,2 @@
 /*! This file is auto-generated */
-void 0===window.wp&&(window.wp={}),void 0===window.wp.codeEditor&&(window.wp.codeEditor={}),function(u,d){"use strict";function s(r,s){var a=[],d=[];function c(){s.onUpdateErrorNotice&&!_.isEqual(a,d)&&(s.onUpdateErrorNotice(a,r),d=a)}function i(){var i,t=r.getOption("lint");return!!t&&(!0===t?t={}:_.isObject(t)&&(t=u.extend({},t)),t.options||(t.options={}),"javascript"===s.codemirror.mode&&s.jshint&&u.extend(t.options,s.jshint),"css"===s.codemirror.mode&&s.csslint&&u.extend(t.options,s.csslint),"htmlmixed"===s.codemirror.mode&&s.htmlhint&&(t.options.rules=u.extend({},s.htmlhint),s.jshint&&(t.options.rules.jshint=s.jshint),s.csslint)&&(t.options.rules.csslint=s.csslint),t.onUpdateLinting=(i=t.onUpdateLinting,function(t,e,n){var o=_.filter(t,function(t){return"error"===t.severity});i&&i.apply(t,e,n),!_.isEqual(o,a)&&(a=o,s.onChangeLintingErrors&&s.onChangeLintingErrors(o,t,e,n),!r.state.focused||0===a.length||0<d.length)&&c()}),t)}r.setOption("lint",i()),r.on("optionChange",function(t,e){var n,o="CodeMirror-lint-markers";"lint"===e&&(e=r.getOption("gutters")||[],!0===(n=r.getOption("lint"))?(_.contains(e,o)||r.setOption("gutters",[o].concat(e)),r.setOption("lint",i())):n||r.setOption("gutters",_.without(e,o)),r.getOption("lint")?r.performLint():(a=[],c()))}),r.on("blur",c),r.on("startCompletion",function(){r.off("blur",c)}),r.on("endCompletion",function(){r.on("blur",c),_.delay(function(){r.state.focused||c()},500)}),u(document.body).on("mousedown",function(t){!r.state.focused||u.contains(r.display.wrapper,t.target)||u(t.target).hasClass("CodeMirror-hint")||c()})}d.codeEditor.defaultSettings={codemirror:{},csslint:{},htmlhint:{},jshint:{},onTabNext:function(){},onTabPrevious:function(){},onChangeLintingErrors:function(){},onUpdateErrorNotice:function(){}},d.codeEditor.initialize=function(t,e){var a,n,o,i,t=u("string"==typeof t?"#"+t:t),r=u.extend({},d.codeEditor.defaultSettings,e);return r.codemirror=u.extend({},r.codemirror),s(a=d.CodeMirror.fromTextArea(t[0],r.codemirror),r),t={settings:r,codemirror:a},a.showHint&&a.on("keyup",function(t,e){var n,o,i,r,s=/^[a-zA-Z]$/.test(e.key);a.state.completionActive&&s||"string"!==(r=a.getTokenAt(a.getCursor())).type&&"comment"!==r.type&&(i=d.CodeMirror.innerMode(a.getMode(),r.state).mode.name,o=a.doc.getLine(a.doc.getCursor().line).substr(0,a.doc.getCursor().ch),"html"===i||"xml"===i?n="<"===e.key||"/"===e.key&&"tag"===r.type||s&&"tag"===r.type||s&&"attribute"===r.type||"="===e.key&&(r.state.htmlState?.tagName||r.state.curState?.htmlState?.tagName):"css"===i?n=s||":"===e.key||" "===e.key&&/:\s+$/.test(o):"javascript"===i?n=s||"."===e.key:"clike"===i&&"php"===a.options.mode&&(n=s&&("keyword"===r.type||"variable"===r.type)),n)&&a.showHint({completeSingle:!1})}),o=e,i=u((n=a).getTextArea()),n.on("blur",function(){i.data("next-tab-blurs",!1)}),n.on("keydown",function(t,e){27===e.keyCode?i.data("next-tab-blurs",!0):9===e.keyCode&&i.data("next-tab-blurs")&&(e.shiftKey?o.onTabPrevious(n,e):o.onTabNext(n,e),i.data("next-tab-blurs",!1),e.preventDefault())}),t}}(window.jQuery,window.wp);
\ No newline at end of file
+void 0===window.wp&&(window.wp={}),void 0===window.wp.codeEditor&&(window.wp.codeEditor={}),function(u,d){"use strict";function s(r,s){var a=[],d=[];function c(){s.onUpdateErrorNotice&&!_.isEqual(a,d)&&(s.onUpdateErrorNotice(a,r),d=a)}function i(){var i,t=r.getOption("lint");return!!t&&(!0===t?t={}:_.isObject(t)&&(t=u.extend({},t)),t.options||(t.options={}),"javascript"===s.codemirror.mode&&s.jshint&&u.extend(t.options,s.jshint),"css"===s.codemirror.mode&&s.csslint&&u.extend(t.options,s.csslint),"htmlmixed"===s.codemirror.mode&&s.htmlhint&&(t.options.rules=u.extend({},s.htmlhint),s.jshint&&(t.options.rules.jshint=s.jshint),s.csslint)&&(t.options.rules.csslint=s.csslint),t.onUpdateLinting=(i=t.onUpdateLinting,function(t,n,e){var o=_.filter(t,function(t){return"error"===t.severity});i&&i.apply(t,n,e),!_.isEqual(o,a)&&(a=o,s.onChangeLintingErrors&&s.onChangeLintingErrors(o,t,n,e),!r.state.focused||0===a.length||0<d.length)&&c()}),t)}return r.setOption("lint",i()),r.on("optionChange",function(t,n){var e,o="CodeMirror-lint-markers";"lint"===n&&(n=r.getOption("gutters")||[],!0===(e=r.getOption("lint"))?(_.contains(n,o)||r.setOption("gutters",[o].concat(n)),r.setOption("lint",i())):e||r.setOption("gutters",_.without(n,o)),r.getOption("lint")?r.performLint():(a=[],c()))}),r.on("blur",c),r.on("startCompletion",function(){r.off("blur",c)}),r.on("endCompletion",function(){r.on("blur",c),_.delay(function(){r.state.focused||c()},500)}),u(document.body).on("mousedown",function(t){!r.state.focused||u.contains(r.display.wrapper,t.target)||u(t.target).hasClass("CodeMirror-hint")||c()}),c}d.codeEditor.defaultSettings={codemirror:{},csslint:{},htmlhint:{},jshint:{},onTabNext:function(){},onTabPrevious:function(){},onChangeLintingErrors:function(){},onUpdateErrorNotice:function(){}},d.codeEditor.initialize=function(t,n){var a,e,o,i,t=u("string"==typeof t?"#"+t:t),r=u.extend({},d.codeEditor.defaultSettings,n);return r.codemirror=u.extend({},r.codemirror),t=s(a=d.CodeMirror.fromTextArea(t[0],r.codemirror),r),r={settings:r,codemirror:a,updateErrorNotice:t},a.showHint&&a.on("inputRead",function(t,n){var e,o,i,r,s;"+input"!==n.origin&&!n.origin.startsWith("*compose")||1!==n.text.length||1!==n.text[0].length||(n=n.text[0],o=/^[a-zA-Z]$/.test(n),a.state.completionActive&&o)||"string"!==(s=a.getTokenAt(a.getCursor())).type&&"comment"!==s.type&&(r=d.CodeMirror.innerMode(a.getMode(),s.state).mode.name,i=a.doc.getLine(a.doc.getCursor().line).substr(0,a.doc.getCursor().ch),"html"===r||"xml"===r?e="<"===n||"/"===n&&"tag"===s.type||o&&"tag"===s.type||o&&"attribute"===s.type||"="===n&&(s.state.htmlState?.tagName||s.state.curState?.htmlState?.tagName):"css"===r?e=o||":"===n||" "===n&&/:\s+$/.test(i):"javascript"===r?e=o||"."===n:"clike"===r&&"php"===a.options.mode&&(e=o&&("keyword"===s.type||"variable"===s.type)),e)&&a.showHint({completeSingle:!1})}),o=n,i=u((e=a).getTextArea()),e.on("blur",function(){i.data("next-tab-blurs",!1)}),e.on("keydown",function(t,n){27===n.keyCode?i.data("next-tab-blurs",!0):9===n.keyCode&&i.data("next-tab-blurs")&&(n.shiftKey?o.onTabPrevious(e,n):o.onTabNext(e,n),i.data("next-tab-blurs",!1),n.preventDefault())}),r}}(window.jQuery,window.wp);
\ No newline at end of file
diff --git a/wp-admin/js/theme-plugin-editor.js b/wp-admin/js/theme-plugin-editor.js
index 1e3ac0d904..7bcff376e9 100644
--- a/wp-admin/js/theme-plugin-editor.js
+++ b/wp-admin/js/theme-plugin-editor.js
@@ -2,7 +2,9 @@
  * @output wp-admin/js/theme-plugin-editor.js
  */

-/* eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1] }] */
+/* eslint-env es2020 */
+
+/* eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1, 9, 1000] }] */

 if ( ! window.wp ) {
 	window.wp = {};
@@ -81,6 +83,18 @@ wp.themePluginEditor = (function( $ ) {
 				component.docsLookUpButton.prop( 'disabled', false );
 			}
 		} );
+
+		// Initiate saving the file when not focused in CodeMirror or when the user has syntax highlighting turned off.
+		$( window ).on( 'keydown', function( event ) {
+			if (
+				( event.ctrlKey || event.metaKey ) &&
+				( 's' === event.key.toLowerCase() ) &&
+				( ! component.instance || ! component.instance.codemirror.hasFocus() )
+			) {
+				event.preventDefault();
+				component.form.trigger( 'submit' );
+			}
+		} );
 	};

 	/**
@@ -191,6 +205,10 @@ wp.themePluginEditor = (function( $ ) {
 			return;
 		}

+		if ( component.instance && component.instance.updateErrorNotice ) {
+			component.instance.updateErrorNotice();
+		}
+
 		// Scroll to the line that has the error.
 		if ( component.lintErrors.length ) {
 			component.instance.codemirror.setCursor( component.lintErrors[0].from.line );
@@ -399,6 +417,16 @@ wp.themePluginEditor = (function( $ ) {
 		editor = wp.codeEditor.initialize( $( '#newcontent' ), codeEditorSettings );
 		editor.codemirror.on( 'change', component.onChange );

+		function onSaveShortcut() {
+			component.form.trigger( 'submit' );
+		}
+
+		editor.codemirror.setOption( 'extraKeys', {
+			...( editor.codemirror.getOption( 'extraKeys' ) || {} ),
+			'Ctrl-S': onSaveShortcut,
+			'Cmd-S': onSaveShortcut,
+		} );
+
 		// Improve the editor accessibility.
 		$( editor.codemirror.display.lineDiv )
 			.attr({
diff --git a/wp-admin/js/theme-plugin-editor.min.js b/wp-admin/js/theme-plugin-editor.min.js
index 5d93871f2f..50c5693be8 100644
--- a/wp-admin/js/theme-plugin-editor.min.js
+++ b/wp-admin/js/theme-plugin-editor.min.js
@@ -1,2 +1,2 @@
 /*! This file is auto-generated */
-window.wp||(window.wp={}),wp.themePluginEditor=function(i){"use strict";var t,o=wp.i18n.__,s=wp.i18n._n,r=wp.i18n.sprintf,n={codeEditor:{},instance:null,noticeElements:{},dirty:!1,lintErrors:[],init:function(e,t){n.form=e,t&&i.extend(n,t),n.noticeTemplate=wp.template("wp-file-editor-notice"),n.noticesContainer=n.form.find(".editor-notices"),n.submitButton=n.form.find(":input[name=submit]"),n.spinner=n.form.find(".submit .spinner"),n.form.on("submit",n.submit),n.textarea=n.form.find("#newcontent"),n.textarea.on("change",n.onChange),n.warning=i(".file-editor-warning"),n.docsLookUpButton=n.form.find("#docs-lookup"),n.docsLookUpList=n.form.find("#docs-list"),0<n.warning.length&&n.showWarning(),!1!==n.codeEditor&&_.defer(function(){n.initCodeEditor()}),i(n.initFileBrowser),i(window).on("beforeunload",function(){if(n.dirty)return o("The changes you made will be lost if you navigate away from this page.")}),n.docsLookUpList.on("change",function(){""===i(this).val()?n.docsLookUpButton.prop("disabled",!0):n.docsLookUpButton.prop("disabled",!1)})},showWarning:function(){var e=n.warning.find(".file-editor-warning-message").text();i("#wpwrap").attr("aria-hidden","true"),i(document.body).addClass("modal-open").append(n.warning.detach()),n.warning.removeClass("hidden").find(".file-editor-warning-go-back").trigger("focus"),n.warningTabbables=n.warning.find("a, button"),n.warningTabbables.on("keydown",n.constrainTabbing),n.warning.on("click",".file-editor-warning-dismiss",n.dismissWarning),setTimeout(function(){wp.a11y.speak(wp.sanitize.stripTags(e.replace(/\s+/g," ")),"assertive")},1e3)},constrainTabbing:function(e){var t,i;9===e.which&&(t=n.warningTabbables.first()[0],(i=n.warningTabbables.last()[0])!==e.target||e.shiftKey?t===e.target&&e.shiftKey&&(i.focus(),e.preventDefault()):(t.focus(),e.preventDefault()))},dismissWarning:function(){wp.ajax.post("dismiss-wp-pointer",{pointer:n.themeOrPlugin+"_editor_notice"}),n.warning.remove(),i("#wpwrap").removeAttr("aria-hidden"),i("body").removeClass("modal-open")},onChange:function(){n.dirty=!0,n.removeNotice("file_saved")},submit:function(e){var t={};e.preventDefault(),i.each(n.form.serializeArray(),function(){t[this.name]=this.value}),n.instance&&(t.newcontent=n.instance.codemirror.getValue()),n.isSaving||(n.lintErrors.length?n.instance.codemirror.setCursor(n.lintErrors[0].from.line):(n.isSaving=!0,n.textarea.prop("readonly",!0),n.instance&&n.instance.codemirror.setOption("readOnly",!0),n.spinner.addClass("is-active"),e=wp.ajax.post("edit-theme-plugin-file",t),n.lastSaveNoticeCode&&n.removeNotice(n.lastSaveNoticeCode),e.done(function(e){n.lastSaveNoticeCode="file_saved",n.addNotice({code:n.lastSaveNoticeCode,type:"success",message:e.message,dismissible:!0}),n.dirty=!1}),e.fail(function(e){e=i.extend({code:"save_error",message:o("An error occurred while saving your changes. Please try again. If the problem persists, you may need to manually update the file via FTP.")},e,{type:"error",dismissible:!0});n.lastSaveNoticeCode=e.code,n.addNotice(e)}),e.always(function(){n.spinner.removeClass("is-active"),n.isSaving=!1,n.textarea.prop("readonly",!1),n.instance&&n.instance.codemirror.setOption("readOnly",!1)})))},addNotice:function(e){var t;if(e.code)return n.removeNotice(e.code),(t=i(n.noticeTemplate(e))).hide(),t.find(".notice-dismiss").on("click",function(){n.removeNotice(e.code),e.onDismiss&&e.onDismiss(e)}),wp.a11y.speak(e.message),n.noticesContainer.append(t),t.slideDown("fast"),n.noticeElements[e.code]=t;throw new Error("Missing code.")},removeNotice:function(e){return!!n.noticeElements[e]&&(n.noticeElements[e].slideUp("fast",function(){i(this).remove()}),delete n.noticeElements[e],!0)},initCodeEditor:function(){var e,t=i.extend({},n.codeEditor);t.onTabPrevious=function(){i("#templateside").find(":tabbable").last().trigger("focus")},t.onTabNext=function(){i("#template").find(":tabbable:not(.CodeMirror-code)").first().trigger("focus")},t.onChangeLintingErrors=function(e){0===(n.lintErrors=e).length&&n.submitButton.toggleClass("disabled",!1)},t.onUpdateErrorNotice=function(e){n.submitButton.toggleClass("disabled",0<e.length),0!==e.length?n.addNotice({code:"lint_errors",type:"error",message:r(s("There is %s error which must be fixed before you can update this file.","There are %s errors which must be fixed before you can update this file.",e.length),String(e.length)),dismissible:!1}).find("input[type=checkbox]").on("click",function(){t.onChangeLintingErrors([]),n.removeNotice("lint_errors")}):n.removeNotice("lint_errors")},(e=wp.codeEditor.initialize(i("#newcontent"),t)).codemirror.on("change",n.onChange),i(e.codemirror.display.lineDiv).attr({role:"textbox","aria-multiline":"true","aria-labelledby":"theme-plugin-editor-label","aria-describedby":"editor-keyboard-trap-help-1 editor-keyboard-trap-help-2 editor-keyboard-trap-help-3 editor-keyboard-trap-help-4"}),i("#theme-plugin-editor-label").on("click",function(){e.codemirror.focus()}),n.instance=e},initFileBrowser:function(){var e=i("#templateside");e.find('[role="group"]').parent().attr("aria-expanded",!1),e.find(".notice").parents("[aria-expanded]").attr("aria-expanded",!0),e.find('[role="tree"]').each(function(){new t(this).init()}),e.find(".current-file:first").each(function(){this.scrollIntoViewIfNeeded?this.scrollIntoViewIfNeeded():this.scrollIntoView(!1)})}},a=(e.prototype.init=function(){this.domNode.tabIndex=-1,this.domNode.getAttribute("role")||this.domNode.setAttribute("role","treeitem"),this.domNode.addEventListener("keydown",this.handleKeydown.bind(this)),this.domNode.addEventListener("click",this.handleClick.bind(this)),this.domNode.addEventListener("focus",this.handleFocus.bind(this)),this.domNode.addEventListener("blur",this.handleBlur.bind(this)),(this.isExpandable?(this.domNode.firstElementChild.addEventListener("mouseover",this.handleMouseOver.bind(this)),this.domNode.firstElementChild):(this.domNode.addEventListener("mouseover",this.handleMouseOver.bind(this)),this.domNode)).addEventListener("mouseout",this.handleMouseOut.bind(this))},e.prototype.isExpanded=function(){return!!this.isExpandable&&"true"===this.domNode.getAttribute("aria-expanded")},e.prototype.handleKeydown=function(e){e.currentTarget;var t=!1,i=e.key;function o(e){return 1===e.length&&e.match(/\S/)}function s(e){"*"==i?(e.tree.expandAllSiblingItems(e),t=!0):o(i)&&(e.tree.setFocusByFirstCharacter(e,i),t=!0)}if(this.stopDefaultClick=!1,!(e.altKey||e.ctrlKey||e.metaKey)){if(e.shift)e.keyCode==this.keyCode.SPACE||e.keyCode==this.keyCode.RETURN?(e.stopPropagation(),this.stopDefaultClick=!0):o(i)&&s(this);else switch(e.keyCode){case this.keyCode.SPACE:case this.keyCode.RETURN:this.isExpandable?(this.isExpanded()?this.tree.collapseTreeitem(this):this.tree.expandTreeitem(this),t=!0):(e.stopPropagation(),this.stopDefaultClick=!0);break;case this.keyCode.UP:this.tree.setFocusToPreviousItem(this),t=!0;break;case this.keyCode.DOWN:this.tree.setFocusToNextItem(this),t=!0;break;case this.keyCode.RIGHT:this.isExpandable&&(this.isExpanded()?this.tree.setFocusToNextItem(this):this.tree.expandTreeitem(this)),t=!0;break;case this.keyCode.LEFT:this.isExpandable&&this.isExpanded()?(this.tree.collapseTreeitem(this),t=!0):this.inGroup&&(this.tree.setFocusToParentItem(this),t=!0);break;case this.keyCode.HOME:this.tree.setFocusToFirstItem(),t=!0;break;case this.keyCode.END:this.tree.setFocusToLastItem(),t=!0;break;default:o(i)&&s(this)}t&&(e.stopPropagation(),e.preventDefault())}},e.prototype.handleClick=function(e){e.target!==this.domNode&&e.target!==this.domNode.firstElementChild||this.isExpandable&&(this.isExpanded()?this.tree.collapseTreeitem(this):this.tree.expandTreeitem(this),e.stopPropagation())},e.prototype.handleFocus=function(e){var t=this.domNode;(t=this.isExpandable?t.firstElementChild:t).classList.add("focus")},e.prototype.handleBlur=function(e){var t=this.domNode;(t=this.isExpandable?t.firstElementChild:t).classList.remove("focus")},e.prototype.handleMouseOver=function(e){e.currentTarget.classList.add("hover")},e.prototype.handleMouseOut=function(e){e.currentTarget.classList.remove("hover")},e);function e(e,t,i){if("object"==typeof e){e.tabIndex=-1,this.tree=t,this.groupTreeitem=i,this.domNode=e,this.label=e.textContent.trim(),this.stopDefaultClick=!1,e.getAttribute("aria-label")&&(this.label=e.getAttribute("aria-label").trim()),this.isExpandable=!1,this.isVisible=!1,this.inGroup=!1,i&&(this.inGroup=!0);for(var o=e.firstElementChild;o;){if("ul"==o.tagName.toLowerCase()){o.setAttribute("role","group"),this.isExpandable=!0;break}o=o.nextElementSibling}this.keyCode=Object.freeze({RETURN:13,SPACE:32,PAGEUP:33,PAGEDOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40})}}function d(e){"object"==typeof e&&(this.domNode=e,this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null)}return d.prototype.init=function(){this.domNode.getAttribute("role")||this.domNode.setAttribute("role","tree"),function e(t,i,o){for(var s=t.firstElementChild,r=o;s;)("li"===s.tagName.toLowerCase()&&"span"===s.firstElementChild.tagName.toLowerCase()||"a"===s.tagName.toLowerCase())&&((r=new a(s,i,o)).init(),i.treeitems.push(r),i.firstChars.push(r.label.substring(0,1).toLowerCase())),s.firstElementChild&&e(s,i,r),s=s.nextElementSibling}(this.domNode,this,!1),this.updateVisibleTreeitems(),this.firstTreeitem.domNode.tabIndex=0},d.prototype.setFocusToItem=function(e){for(var t=0;t<this.treeitems.length;t++){var i=this.treeitems[t];i===e?(i.domNode.tabIndex=0,i.domNode.focus()):i.domNode.tabIndex=-1}},d.prototype.setFocusToNextItem=function(e){for(var t=!1,i=this.treeitems.length-1;0<=i;i--){var o=this.treeitems[i];if(o===e)break;o.isVisible&&(t=o)}t&&this.setFocusToItem(t)},d.prototype.setFocusToPreviousItem=function(e){for(var t=!1,i=0;i<this.treeitems.length;i++){var o=this.treeitems[i];if(o===e)break;o.isVisible&&(t=o)}t&&this.setFocusToItem(t)},d.prototype.setFocusToParentItem=function(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)},d.prototype.setFocusToFirstItem=function(){this.setFocusToItem(this.firstTreeitem)},d.prototype.setFocusToLastItem=function(){this.setFocusToItem(this.lastTreeitem)},d.prototype.expandTreeitem=function(e){e.isExpandable&&(e.domNode.setAttribute("aria-expanded",!0),this.updateVisibleTreeitems())},d.prototype.expandAllSiblingItems=function(e){for(var t=0;t<this.treeitems.length;t++){var i=this.treeitems[t];i.groupTreeitem===e.groupTreeitem&&i.isExpandable&&this.expandTreeitem(i)}},d.prototype.collapseTreeitem=function(e){var t=!1;(t=e.isExpanded()?e:e.groupTreeitem)&&(t.domNode.setAttribute("aria-expanded",!1),this.updateVisibleTreeitems(),this.setFocusToItem(t))},d.prototype.updateVisibleTreeitems=function(){this.firstTreeitem=this.treeitems[0];for(var e=0;e<this.treeitems.length;e++){var t=this.treeitems[e],i=t.domNode.parentNode;for(t.isVisible=!0;i&&i!==this.domNode;)"false"==i.getAttribute("aria-expanded")&&(t.isVisible=!1),i=i.parentNode;t.isVisible&&(this.lastTreeitem=t)}},d.prototype.setFocusByFirstCharacter=function(e,t){t=t.toLowerCase(),(e=this.treeitems.indexOf(e)+1)===this.treeitems.length&&(e=0),-1<(e=-1===(e=this.getIndexFirstChars(e,t))?this.getIndexFirstChars(0,t):e)&&this.setFocusToItem(this.treeitems[e])},d.prototype.getIndexFirstChars=function(e,t){for(var i=e;i<this.firstChars.length;i++)if(this.treeitems[i].isVisible&&t===this.firstChars[i])return i;return-1},t=d,n}(jQuery),wp.themePluginEditor.l10n=wp.themePluginEditor.l10n||{saveAlert:"",saveError:"",lintError:{alternative:"wp.i18n",func:function(){return{singular:"",plural:""}}}},wp.themePluginEditor.l10n=window.wp.deprecateL10nObject("wp.themePluginEditor.l10n",wp.themePluginEditor.l10n,"5.5.0");
\ No newline at end of file
+window.wp||(window.wp={}),wp.themePluginEditor=function(o){"use strict";var t,i=wp.i18n.__,s=wp.i18n._n,r=wp.i18n.sprintf,n={codeEditor:{},instance:null,noticeElements:{},dirty:!1,lintErrors:[],init:function(e,t){n.form=e,t&&o.extend(n,t),n.noticeTemplate=wp.template("wp-file-editor-notice"),n.noticesContainer=n.form.find(".editor-notices"),n.submitButton=n.form.find(":input[name=submit]"),n.spinner=n.form.find(".submit .spinner"),n.form.on("submit",n.submit),n.textarea=n.form.find("#newcontent"),n.textarea.on("change",n.onChange),n.warning=o(".file-editor-warning"),n.docsLookUpButton=n.form.find("#docs-lookup"),n.docsLookUpList=n.form.find("#docs-list"),0<n.warning.length&&n.showWarning(),!1!==n.codeEditor&&_.defer(function(){n.initCodeEditor()}),o(n.initFileBrowser),o(window).on("beforeunload",function(){if(n.dirty)return i("The changes you made will be lost if you navigate away from this page.")}),n.docsLookUpList.on("change",function(){""===o(this).val()?n.docsLookUpButton.prop("disabled",!0):n.docsLookUpButton.prop("disabled",!1)}),o(window).on("keydown",function(e){!e.ctrlKey&&!e.metaKey||"s"!==e.key.toLowerCase()||n.instance&&n.instance.codemirror.hasFocus()||(e.preventDefault(),n.form.trigger("submit"))})},showWarning:function(){var e=n.warning.find(".file-editor-warning-message").text();o("#wpwrap").attr("aria-hidden","true"),o(document.body).addClass("modal-open").append(n.warning.detach()),n.warning.removeClass("hidden").find(".file-editor-warning-go-back").trigger("focus"),n.warningTabbables=n.warning.find("a, button"),n.warningTabbables.on("keydown",n.constrainTabbing),n.warning.on("click",".file-editor-warning-dismiss",n.dismissWarning),setTimeout(function(){wp.a11y.speak(wp.sanitize.stripTags(e.replace(/\s+/g," ")),"assertive")},1e3)},constrainTabbing:function(e){var t,i;9===e.which&&(t=n.warningTabbables.first()[0],(i=n.warningTabbables.last()[0])!==e.target||e.shiftKey?t===e.target&&e.shiftKey&&(i.focus(),e.preventDefault()):(t.focus(),e.preventDefault()))},dismissWarning:function(){wp.ajax.post("dismiss-wp-pointer",{pointer:n.themeOrPlugin+"_editor_notice"}),n.warning.remove(),o("#wpwrap").removeAttr("aria-hidden"),o("body").removeClass("modal-open")},onChange:function(){n.dirty=!0,n.removeNotice("file_saved")},submit:function(e){var t={};e.preventDefault(),o.each(n.form.serializeArray(),function(){t[this.name]=this.value}),n.instance&&(t.newcontent=n.instance.codemirror.getValue()),n.isSaving||(n.instance&&n.instance.updateErrorNotice&&n.instance.updateErrorNotice(),n.lintErrors.length?n.instance.codemirror.setCursor(n.lintErrors[0].from.line):(n.isSaving=!0,n.textarea.prop("readonly",!0),n.instance&&n.instance.codemirror.setOption("readOnly",!0),n.spinner.addClass("is-active"),e=wp.ajax.post("edit-theme-plugin-file",t),n.lastSaveNoticeCode&&n.removeNotice(n.lastSaveNoticeCode),e.done(function(e){n.lastSaveNoticeCode="file_saved",n.addNotice({code:n.lastSaveNoticeCode,type:"success",message:e.message,dismissible:!0}),n.dirty=!1}),e.fail(function(e){e=o.extend({code:"save_error",message:i("An error occurred while saving your changes. Please try again. If the problem persists, you may need to manually update the file via FTP.")},e,{type:"error",dismissible:!0});n.lastSaveNoticeCode=e.code,n.addNotice(e)}),e.always(function(){n.spinner.removeClass("is-active"),n.isSaving=!1,n.textarea.prop("readonly",!1),n.instance&&n.instance.codemirror.setOption("readOnly",!1)})))},addNotice:function(e){var t;if(e.code)return n.removeNotice(e.code),(t=o(n.noticeTemplate(e))).hide(),t.find(".notice-dismiss").on("click",function(){n.removeNotice(e.code),e.onDismiss&&e.onDismiss(e)}),wp.a11y.speak(e.message),n.noticesContainer.append(t),t.slideDown("fast"),n.noticeElements[e.code]=t;throw new Error("Missing code.")},removeNotice:function(e){return!!n.noticeElements[e]&&(n.noticeElements[e].slideUp("fast",function(){o(this).remove()}),delete n.noticeElements[e],!0)},initCodeEditor:function(){var t,e;function i(){n.form.trigger("submit")}(t=o.extend({},n.codeEditor)).onTabPrevious=function(){o("#templateside").find(":tabbable").last().trigger("focus")},t.onTabNext=function(){o("#template").find(":tabbable:not(.CodeMirror-code)").first().trigger("focus")},t.onChangeLintingErrors=function(e){0===(n.lintErrors=e).length&&n.submitButton.toggleClass("disabled",!1)},t.onUpdateErrorNotice=function(e){n.submitButton.toggleClass("disabled",0<e.length),0!==e.length?n.addNotice({code:"lint_errors",type:"error",message:r(s("There is %s error which must be fixed before you can update this file.","There are %s errors which must be fixed before you can update this file.",e.length),String(e.length)),dismissible:!1}).find("input[type=checkbox]").on("click",function(){t.onChangeLintingErrors([]),n.removeNotice("lint_errors")}):n.removeNotice("lint_errors")},(e=wp.codeEditor.initialize(o("#newcontent"),t)).codemirror.on("change",n.onChange),e.codemirror.setOption("extraKeys",{...e.codemirror.getOption("extraKeys")||{},"Ctrl-S":i,"Cmd-S":i}),o(e.codemirror.display.lineDiv).attr({role:"textbox","aria-multiline":"true","aria-labelledby":"theme-plugin-editor-label","aria-describedby":"editor-keyboard-trap-help-1 editor-keyboard-trap-help-2 editor-keyboard-trap-help-3 editor-keyboard-trap-help-4"}),o("#theme-plugin-editor-label").on("click",function(){e.codemirror.focus()}),n.instance=e},initFileBrowser:function(){var e=o("#templateside");e.find('[role="group"]').parent().attr("aria-expanded",!1),e.find(".notice").parents("[aria-expanded]").attr("aria-expanded",!0),e.find('[role="tree"]').each(function(){new t(this).init()}),e.find(".current-file:first").each(function(){this.scrollIntoViewIfNeeded?this.scrollIntoViewIfNeeded():this.scrollIntoView(!1)})}},a=(e.prototype.init=function(){this.domNode.tabIndex=-1,this.domNode.getAttribute("role")||this.domNode.setAttribute("role","treeitem"),this.domNode.addEventListener("keydown",this.handleKeydown.bind(this)),this.domNode.addEventListener("click",this.handleClick.bind(this)),this.domNode.addEventListener("focus",this.handleFocus.bind(this)),this.domNode.addEventListener("blur",this.handleBlur.bind(this)),(this.isExpandable?(this.domNode.firstElementChild.addEventListener("mouseover",this.handleMouseOver.bind(this)),this.domNode.firstElementChild):(this.domNode.addEventListener("mouseover",this.handleMouseOver.bind(this)),this.domNode)).addEventListener("mouseout",this.handleMouseOut.bind(this))},e.prototype.isExpanded=function(){return!!this.isExpandable&&"true"===this.domNode.getAttribute("aria-expanded")},e.prototype.handleKeydown=function(e){e.currentTarget;var t=!1,i=e.key;function o(e){return 1===e.length&&e.match(/\S/)}function s(e){"*"==i?(e.tree.expandAllSiblingItems(e),t=!0):o(i)&&(e.tree.setFocusByFirstCharacter(e,i),t=!0)}if(this.stopDefaultClick=!1,!(e.altKey||e.ctrlKey||e.metaKey)){if(e.shift)e.keyCode==this.keyCode.SPACE||e.keyCode==this.keyCode.RETURN?(e.stopPropagation(),this.stopDefaultClick=!0):o(i)&&s(this);else switch(e.keyCode){case this.keyCode.SPACE:case this.keyCode.RETURN:this.isExpandable?(this.isExpanded()?this.tree.collapseTreeitem(this):this.tree.expandTreeitem(this),t=!0):(e.stopPropagation(),this.stopDefaultClick=!0);break;case this.keyCode.UP:this.tree.setFocusToPreviousItem(this),t=!0;break;case this.keyCode.DOWN:this.tree.setFocusToNextItem(this),t=!0;break;case this.keyCode.RIGHT:this.isExpandable&&(this.isExpanded()?this.tree.setFocusToNextItem(this):this.tree.expandTreeitem(this)),t=!0;break;case this.keyCode.LEFT:this.isExpandable&&this.isExpanded()?(this.tree.collapseTreeitem(this),t=!0):this.inGroup&&(this.tree.setFocusToParentItem(this),t=!0);break;case this.keyCode.HOME:this.tree.setFocusToFirstItem(),t=!0;break;case this.keyCode.END:this.tree.setFocusToLastItem(),t=!0;break;default:o(i)&&s(this)}t&&(e.stopPropagation(),e.preventDefault())}},e.prototype.handleClick=function(e){e.target!==this.domNode&&e.target!==this.domNode.firstElementChild||this.isExpandable&&(this.isExpanded()?this.tree.collapseTreeitem(this):this.tree.expandTreeitem(this),e.stopPropagation())},e.prototype.handleFocus=function(e){var t=this.domNode;(t=this.isExpandable?t.firstElementChild:t).classList.add("focus")},e.prototype.handleBlur=function(e){var t=this.domNode;(t=this.isExpandable?t.firstElementChild:t).classList.remove("focus")},e.prototype.handleMouseOver=function(e){e.currentTarget.classList.add("hover")},e.prototype.handleMouseOut=function(e){e.currentTarget.classList.remove("hover")},e);function e(e,t,i){if("object"==typeof e){e.tabIndex=-1,this.tree=t,this.groupTreeitem=i,this.domNode=e,this.label=e.textContent.trim(),this.stopDefaultClick=!1,e.getAttribute("aria-label")&&(this.label=e.getAttribute("aria-label").trim()),this.isExpandable=!1,this.isVisible=!1,this.inGroup=!1,i&&(this.inGroup=!0);for(var o=e.firstElementChild;o;){if("ul"==o.tagName.toLowerCase()){o.setAttribute("role","group"),this.isExpandable=!0;break}o=o.nextElementSibling}this.keyCode=Object.freeze({RETURN:13,SPACE:32,PAGEUP:33,PAGEDOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40})}}function d(e){"object"==typeof e&&(this.domNode=e,this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null)}return d.prototype.init=function(){this.domNode.getAttribute("role")||this.domNode.setAttribute("role","tree"),function e(t,i,o){for(var s=t.firstElementChild,r=o;s;)("li"===s.tagName.toLowerCase()&&"span"===s.firstElementChild.tagName.toLowerCase()||"a"===s.tagName.toLowerCase())&&((r=new a(s,i,o)).init(),i.treeitems.push(r),i.firstChars.push(r.label.substring(0,1).toLowerCase())),s.firstElementChild&&e(s,i,r),s=s.nextElementSibling}(this.domNode,this,!1),this.updateVisibleTreeitems(),this.firstTreeitem.domNode.tabIndex=0},d.prototype.setFocusToItem=function(e){for(var t=0;t<this.treeitems.length;t++){var i=this.treeitems[t];i===e?(i.domNode.tabIndex=0,i.domNode.focus()):i.domNode.tabIndex=-1}},d.prototype.setFocusToNextItem=function(e){for(var t=!1,i=this.treeitems.length-1;0<=i;i--){var o=this.treeitems[i];if(o===e)break;o.isVisible&&(t=o)}t&&this.setFocusToItem(t)},d.prototype.setFocusToPreviousItem=function(e){for(var t=!1,i=0;i<this.treeitems.length;i++){var o=this.treeitems[i];if(o===e)break;o.isVisible&&(t=o)}t&&this.setFocusToItem(t)},d.prototype.setFocusToParentItem=function(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)},d.prototype.setFocusToFirstItem=function(){this.setFocusToItem(this.firstTreeitem)},d.prototype.setFocusToLastItem=function(){this.setFocusToItem(this.lastTreeitem)},d.prototype.expandTreeitem=function(e){e.isExpandable&&(e.domNode.setAttribute("aria-expanded",!0),this.updateVisibleTreeitems())},d.prototype.expandAllSiblingItems=function(e){for(var t=0;t<this.treeitems.length;t++){var i=this.treeitems[t];i.groupTreeitem===e.groupTreeitem&&i.isExpandable&&this.expandTreeitem(i)}},d.prototype.collapseTreeitem=function(e){var t=!1;(t=e.isExpanded()?e:e.groupTreeitem)&&(t.domNode.setAttribute("aria-expanded",!1),this.updateVisibleTreeitems(),this.setFocusToItem(t))},d.prototype.updateVisibleTreeitems=function(){this.firstTreeitem=this.treeitems[0];for(var e=0;e<this.treeitems.length;e++){var t=this.treeitems[e],i=t.domNode.parentNode;for(t.isVisible=!0;i&&i!==this.domNode;)"false"==i.getAttribute("aria-expanded")&&(t.isVisible=!1),i=i.parentNode;t.isVisible&&(this.lastTreeitem=t)}},d.prototype.setFocusByFirstCharacter=function(e,t){t=t.toLowerCase(),(e=this.treeitems.indexOf(e)+1)===this.treeitems.length&&(e=0),-1<(e=-1===(e=this.getIndexFirstChars(e,t))?this.getIndexFirstChars(0,t):e)&&this.setFocusToItem(this.treeitems[e])},d.prototype.getIndexFirstChars=function(e,t){for(var i=e;i<this.firstChars.length;i++)if(this.treeitems[i].isVisible&&t===this.firstChars[i])return i;return-1},t=d,n}(jQuery),wp.themePluginEditor.l10n=wp.themePluginEditor.l10n||{saveAlert:"",saveError:"",lintError:{alternative:"wp.i18n",func:function(){return{singular:"",plural:""}}}},wp.themePluginEditor.l10n=window.wp.deprecateL10nObject("wp.themePluginEditor.l10n",wp.themePluginEditor.l10n,"5.5.0");
\ No newline at end of file
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 33befb47a0..1a50374451 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.0-alpha-61587';
+$wp_version = '7.0-alpha-61588';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.