Commit 71a778ea83 for wordpress.org

commit 71a778ea8305d39fcf8ae94b994fbd5a7de42d22
Author: westonruter <westonruter@git.wordpress.org>
Date:   Fri Oct 9 04:11:53 2026 +0000

    Emoji: Fix defects in emoji scripts and add type checking.

    Several defects in `wp-emoji.js` had gone unnoticed because neither emoji script was type checked nor tested:

    * Since 4.4, the fallback for an emoji image which fails to load has never worked. The `onerror` handler given to Twemoji referred to the library object instead of the image element, leaving a broken image icon in place of the emoji character.
    * Because that handler never set the `data-error` attribute, the `MutationObserver` guard which recognizes such a replacement was unreachable, hiding the fact that it abandoned all remaining mutation records rather than only the one it recognized. It is corrected along with the handler, since fixing the handler alone would cause an element added in the same batch as a failed image to go unparsed.
    * An added `<svg>` or MathML element was handed to Twemoji, which put `<img>` elements inside it.
    * The `wp-exclude-emoji` class was matched as a substring of the `class` attribute rather than as a class, so classes such as `my-wp-exclude-emoji` also excluded an element.

    Code which could not run in any browser able to load the script is removed:

    * The IE 11 workaround.
    * The `browserSupportsSvgAsImage()` check, whose call to `document.implementation.hasFeature()` always returns `true` per the DOM standard, so the PNG fallback was unreachable.
    * The vendor-prefixed `MutationObserver` detection.

    The rest of `wp-emoji.js` is modernized to match the emoji loader, which was already updated in r60899.

    Both scripts are added to the files checked by `tsc`, with new typings for the settings exported by `_print_emoji_detection_script()`, the vendored Twemoji library, and `WorkerGlobalScope`, which the `dom` lib does not provide. Annotating the loader's support tests precisely made `browserSupportsEmoji()` exhaustively checked, and `allowUnreachableCode` is disabled so that unreachable code is reported on the command line and not just in editors. The first QUnit tests for `wp-emoji.js` are added, covering each defect fixed here. The loader remains untested because it exports nothing and runs on import, leaving no seam to test through.

    Developed in https://github.com/WordPress/wordpress-develop/pull/13592.
    Follow-up to r35637, r36817, r37471, r55186, r60899, r60902.

    Props westonruter, peterwilsoncc.
    See #65997, #66033.
    Fixes #66131.

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


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

diff --git a/wp-includes/js/wp-emoji-loader.js b/wp-includes/js/wp-emoji-loader.js
index 4397a72eaf..bbb46e80d0 100644
--- a/wp-includes/js/wp-emoji-loader.js
+++ b/wp-includes/js/wp-emoji-loader.js
@@ -4,20 +4,12 @@

 // Note: This is loaded as a script module, so there is no need for an IIFE to prevent pollution of the global scope.

-/**
- * Emoji Settings as exported in PHP via _print_emoji_detection_script().
- * @typedef WPEmojiSettings
- * @type {Object}
- * @property {?object} source             The source object containing emoji-related URLs.
- * @property {?string} source.concatemoji The URL for the concatenated emoji script.
- * @property {?string} source.twemoji     The URL for the Twemoji script.
- * @property {?string} source.wpemoji     The URL for the WP Emoji script.
- */
+// Note: The WPEmojiSettings and EmojiSupports types are declared in typings/wp-emoji, since wp-emoji.js reads them back.

 const selector = 'script#wp-emoji-settings';
 const script = document.querySelector( selector );
 if ( ! ( script instanceof HTMLScriptElement ) ) {
-	throw new Error( `Element missing: ${ selector }`);
+	throw new Error( `Element missing: ${ selector }` );
 }
 const settings = /** @type {WPEmojiSettings} */ ( JSON.parse( script.text ) );

@@ -25,14 +17,17 @@ const settings = /** @type {WPEmojiSettings} */ ( JSON.parse( script.text ) );
 window._wpemojiSettings = settings;

 /**
- * Support tests.
+ * Results of the emoji support tests.
+ *
  * @typedef SupportTests
  * @type {Object}
- * @property {?boolean} flag  Whether the browser supports flag emojis.
- * @property {?boolean} emoji Whether the browser supports general emojis.
+ * @property {boolean} flag  Whether the browser renders flag emoji.
+ * @property {boolean} emoji Whether the browser renders emoji.
  */

 const sessionStorageKey = 'wpEmojiSettingsSupports';
+
+/** @type {Array<keyof SupportTests>} */
 const tests = [ 'flag', 'emoji' ];

 /**
@@ -49,16 +44,18 @@ function supportsWorkerOffloading() {
 		typeof Worker !== 'undefined' &&
 		typeof OffscreenCanvas !== 'undefined' &&
 		typeof URL !== 'undefined' &&
-		URL.createObjectURL &&
+		typeof URL.createObjectURL === 'function' &&
 		typeof Blob !== 'undefined'
 	);
 }

 /**
+ * Support tests as they are stored in session storage.
+ *
  * @typedef SessionSupportTests
  * @type {Object}
- * @property {number}       timestamp    The timestamp when the support tests were last updated.
- * @property {SupportTests} supportTests The support tests for the browser.
+ * @property {number}       timestamp    When the tests were run, in milliseconds since the epoch.
+ * @property {SupportTests} supportTests What the tests found.
  */

 /**
@@ -72,10 +69,13 @@ function supportsWorkerOffloading() {
  */
 function getSessionSupportTests() {
 	try {
+		const itemJson = sessionStorage.getItem( sessionStorageKey );
+		if ( null === itemJson ) {
+			return null;
+		}
+
 		/** @type {SessionSupportTests} */
-		const item = JSON.parse(
-			sessionStorage.getItem( sessionStorageKey )
-		);
+		const item = JSON.parse( itemJson );
 		if (
 			typeof item === 'object' &&
 			typeof item.timestamp === 'number' &&
@@ -95,7 +95,7 @@ function getSessionSupportTests() {
  *
  * @private
  *
- * @param {SupportTests} supportTests Support tests.
+ * @param {SupportTests} supportTests What the tests found.
  */
 function setSessionSupportTests( supportTests ) {
 	try {
@@ -112,6 +112,51 @@ function setSessionSupportTests( supportTests ) {
 	} catch ( e ) {}
 }

+/**
+ * A 2D context for the support tests.
+ *
+ * Which of the two it is depends on the kind of canvas it came from, and the tests use only what
+ * both provide.
+ *
+ * @typedef {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} EmojiTestContext
+ */
+
+/**
+ * Checks if two sets of Emoji characters render the same visually.
+ *
+ * @callback EmojiSetsRenderIdentically
+ *
+ * @param {EmojiTestContext} context 2D Context.
+ * @param {string}           set1    Set of Emoji to test.
+ * @param {string}           set2    Set of Emoji to test.
+ *
+ * @return {boolean} True if the two sets render the same.
+ */
+
+/**
+ * Checks if the center point of a single emoji is empty.
+ *
+ * @callback EmojiRendersEmptyCenterPoint
+ *
+ * @param {EmojiTestContext} context 2D Context.
+ * @param {string}           emoji   Emoji to test.
+ *
+ * @return {boolean} True if the center point is empty.
+ */
+
+/**
+ * Determines if the browser properly renders Emoji that Twemoji can supplement.
+ *
+ * @callback BrowserSupportsEmoji
+ *
+ * @param {EmojiTestContext}             context                      2D Context.
+ * @param {keyof SupportTests}           type                         Which support test to run.
+ * @param {EmojiSetsRenderIdentically}   emojiSetsRenderIdentically   Reference to emojiSetsRenderIdentically function, needed due to minification.
+ * @param {EmojiRendersEmptyCenterPoint} emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
+ *
+ * @return {boolean} True if the browser can render emoji, false if it cannot.
+ */
+
 /**
  * Checks if two sets of Emoji characters render the same visually.
  *
@@ -127,9 +172,9 @@ function setSessionSupportTests( supportTests ) {
  *
  * @private
  *
- * @param {CanvasRenderingContext2D} context 2D Context.
- * @param {string}                   set1    Set of Emoji to test.
- * @param {string}                   set2    Set of Emoji to test.
+ * @param {EmojiTestContext} context 2D Context.
+ * @param {string}           set1    Set of Emoji to test.
+ * @param {string}           set2    Set of Emoji to test.
  *
  * @return {boolean} True if the two sets render the same.
  */
@@ -177,8 +222,8 @@ function emojiSetsRenderIdentically( context, set1, set2 ) {
  *
  * @private
  *
- * @param {CanvasRenderingContext2D} context 2D Context.
- * @param {string}                   emoji   Emoji to test.
+ * @param {EmojiTestContext} context 2D Context.
+ * @param {string}           emoji   Emoji to test.
  *
  * @return {boolean} True if the center point is empty.
  */
@@ -188,7 +233,7 @@ function emojiRendersEmptyCenterPoint( context, emoji ) {
 	context.fillText( emoji, 0, 0 );

 	// Test if the center point (16, 16) is empty (0,0,0,0).
-	const centerPoint = context.getImageData(16, 16, 1, 1);
+	const centerPoint = context.getImageData( 16, 16, 1, 1 );
 	for ( let i = 0; i < centerPoint.data.length; i++ ) {
 		if ( centerPoint.data[ i ] !== 0 ) {
 			// Stop checking the moment it's known not to be empty.
@@ -209,14 +254,15 @@ function emojiRendersEmptyCenterPoint( context, emoji ) {
  *
  * @private
  *
- * @param {CanvasRenderingContext2D} context                      2D Context.
- * @param {string}                   type                         Whether to test for support of "flag" or "emoji".
- * @param {Function}                 emojiSetsRenderIdentically   Reference to emojiSetsRenderIdentically function, needed due to minification.
- * @param {Function}                 emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
+ * @param {EmojiTestContext}             context                      2D Context.
+ * @param {keyof SupportTests}           type                         Which support test to run.
+ * @param {EmojiSetsRenderIdentically}   emojiSetsRenderIdentically   Reference to emojiSetsRenderIdentically function, needed due to minification.
+ * @param {EmojiRendersEmptyCenterPoint} emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
  *
  * @return {boolean} True if the browser can render emoji, false if it cannot.
  */
 function browserSupportsEmoji( context, type, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint ) {
+	/** @type {boolean} */
 	let isIdentical;

 	switch ( type ) {
@@ -256,7 +302,7 @@ function browserSupportsEmoji( context, type, emojiSetsRenderIdentically, emojiR

 			/*
 			 * Test for English flag compatibility. England is a country in the United Kingdom, it
-			 * does not have a two letter locale code but rather a five letter sub-division code.
+			 * does not have a two letter locale code but rather a five letter subdivision code.
 			 *
 			 * To test for support, we try to render it, and compare the rendering to how it would look if
 			 * the browser doesn't render it correctly (black flag emoji + [G] + [B] + [E] + [N] + [G]).
@@ -288,8 +334,6 @@ function browserSupportsEmoji( context, type, emojiSetsRenderIdentically, emojiR
 			const notSupported = emojiRendersEmptyCenterPoint( context, '\uD83E\uDEC8' );
 			return ! notSupported;
 	}
-
-	return false;
 }

 /**
@@ -302,25 +346,30 @@ function browserSupportsEmoji( context, type, emojiSetsRenderIdentically, emojiR
  *
  * @private
  *
- * @param {string[]} tests                        Tests.
- * @param {Function} browserSupportsEmoji         Reference to browserSupportsEmoji function, needed due to minification.
- * @param {Function} emojiSetsRenderIdentically   Reference to emojiSetsRenderIdentically function, needed due to minification.
- * @param {Function} emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
+ * @param {Array<keyof SupportTests>}    tests                        Which support tests to run.
+ * @param {BrowserSupportsEmoji}         browserSupportsEmoji         Reference to browserSupportsEmoji function, needed due to minification.
+ * @param {EmojiSetsRenderIdentically}   emojiSetsRenderIdentically   Reference to emojiSetsRenderIdentically function, needed due to minification.
+ * @param {EmojiRendersEmptyCenterPoint} emojiRendersEmptyCenterPoint Reference to emojiRendersEmptyCenterPoint function, needed due to minification.
  *
  * @return {SupportTests} Support tests.
  */
 function testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint ) {
-	let canvas;
+	/** @type {?EmojiTestContext} */
+	let context;
+
 	if (
 		typeof WorkerGlobalScope !== 'undefined' &&
 		self instanceof WorkerGlobalScope
 	) {
-		canvas = new OffscreenCanvas( 300, 150 ); // Dimensions are default for HTMLCanvasElement.
+		// Dimensions are default for HTMLCanvasElement.
+		context = new OffscreenCanvas( 300, 150 ).getContext( '2d', { willReadFrequently: true } );
 	} else {
-		canvas = document.createElement( 'canvas' );
+		context = document.createElement( 'canvas' ).getContext( '2d', { willReadFrequently: true } );
 	}

-	const context = canvas.getContext( '2d', { willReadFrequently: true } );
+	if ( ! context ) {
+		throw new Error( 'Unable to obtain a 2D context for the emoji support tests.' );
+	}

 	/*
 	 * Chrome on OS X added native emoji rendering in M41. Unfortunately,
@@ -330,7 +379,7 @@ function testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentica
 	context.textBaseline = 'top';
 	context.font = '600 32px Arial';

-	const supports = {};
+	const supports = /** @type {SupportTests} */ ( {} );
 	tests.forEach( ( test ) => {
 		supports[ test ] = browserSupportsEmoji( context, test, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint );
 	} );
@@ -361,10 +410,11 @@ settings.supports = {
 };

 // Obtain the emoji support from the browser, asynchronously when possible.
-new Promise( ( resolve ) => {
-	let supportTests = getSessionSupportTests();
-	if ( supportTests ) {
-		resolve( supportTests );
+/** @type {Promise<SupportTests>} */
+const supportTestsPromise = new Promise( ( resolve ) => {
+	const sessionSupportTests = getSessionSupportTests();
+	if ( sessionSupportTests ) {
+		resolve( sessionSupportTests );
 		return;
 	}

@@ -386,20 +436,21 @@ new Promise( ( resolve ) => {
 				type: 'text/javascript'
 			} );
 			const worker = new Worker( URL.createObjectURL( blob ), { name: 'wpTestEmojiSupports' } );
-			worker.onmessage = ( event ) => {
-				supportTests = event.data;
-				setSessionSupportTests( supportTests );
+			worker.onmessage = ( /** @type {MessageEvent<SupportTests>} */ event ) => {
+				setSessionSupportTests( event.data );
 				worker.terminate();
-				resolve( supportTests );
+				resolve( event.data );
 			};
 			return;
 		} catch ( e ) {}
 	}

-	supportTests = testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint );
-	setSessionSupportTests( supportTests );
-	resolve( supportTests );
-} )
+	const testedSupportTests = testEmojiSupports( tests, browserSupportsEmoji, emojiSetsRenderIdentically, emojiRendersEmptyCenterPoint );
+	setSessionSupportTests( testedSupportTests );
+	resolve( testedSupportTests );
+} );
+
+supportTestsPromise
 	// Once the browser emoji support has been obtained from the session, finalize the settings.
 	.then( ( supportTests ) => {
 		/*
@@ -407,15 +458,17 @@ new Promise( ( resolve ) => {
 		 * support settings accordingly.
 		 */
 		for ( const test in supportTests ) {
-			settings.supports[ test ] = supportTests[ test ];
+			const key = /** @type {keyof SupportTests} */ ( test );
+			const supported = supportTests[ key ];
+
+			settings.supports[ key ] = supported;

 			settings.supports.everything =
-				settings.supports.everything && settings.supports[ test ];
+				settings.supports.everything && supported;

-			if ( 'flag' !== test ) {
+			if ( 'flag' !== key ) {
 				settings.supports.everythingExceptFlag =
-					settings.supports.everythingExceptFlag &&
-					settings.supports[ test ];
+					settings.supports.everythingExceptFlag && supported;
 			}
 		}

diff --git a/wp-includes/js/wp-emoji-loader.min.js b/wp-includes/js/wp-emoji-loader.min.js
index feb314f080..cf51220b87 100644
--- a/wp-includes/js/wp-emoji-loader.min.js
+++ b/wp-includes/js/wp-emoji-loader.min.js
@@ -1,2 +1,2 @@
 /*! This file is auto-generated */
-var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\udec8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=>{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=>{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&&r.supports[n],"flag"!==n&&(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&&t.twemoji&&(a(t.twemoji),a(t.wpemoji)))});
\ No newline at end of file
+var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const o=JSON.parse(t.text),s=(window._wpemojiSettings=o,"wpEmojiSettingsSupports"),i=["flag","emoji"];function c(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function p(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function f(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\udec8")}}function l(e,t,n,r){let a;if(!(a=("undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0})))throw new Error("Unable to obtain a 2D context for the emoji support tests.");a.textBaseline="top",a.font="600 32px Arial";const o={};return e.forEach(e=>{o[e]=t(a,e,n,r)}),o}function g(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}o.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{var e=function(){try{var e=sessionStorage.getItem(s);if(null===e)return null;var t=JSON.parse(e);if("object"==typeof t&&"number"==typeof t.timestamp&&(new Date).valueOf()<t.timestamp+604800&&"object"==typeof t.supportTests)return t.supportTests}catch(e){}return null}();if(e)t(e);else{if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&"function"==typeof URL.createObjectURL&&"undefined"!=typeof Blob)try{var n="postMessage("+l.toString()+"("+[JSON.stringify(i),u.toString(),p.toString(),f.toString()].join(",")+"));",r=new Blob([n],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{c(e.data),a.terminate(),t(e.data)})}catch(e){}e=l(i,u,p,f);c(e),t(e)}}).then(e=>{for(const a in e){var t=a,n=e[t];o.supports[t]=n,o.supports.everything=o.supports.everything&&n,"flag"!==t&&(o.supports.everythingExceptFlag=o.supports.everythingExceptFlag&&n)}var r;o.supports.everythingExceptFlag=o.supports.everythingExceptFlag&&!o.supports.flag,o.supports.everything||((r=o.source||{}).concatemoji?g(r.concatemoji):r.wpemoji&&r.twemoji&&(g(r.twemoji),g(r.wpemoji)))});
\ No newline at end of file
diff --git a/wp-includes/js/wp-emoji-release.min.js b/wp-includes/js/wp-emoji-release.min.js
index 15f6433df6..2331852658 100644
--- a/wp-includes/js/wp-emoji-release.min.js
+++ b/wp-includes/js/wp-emoji-release.min.js
@@ -2,4 +2,4 @@
 // Source: wp-includes/js/twemoji.min.js
 var twemoji=function(){"use strict";var h={base:"https://cdn.jsdelivr.net/gh/jdecked/twemoji@17.0.1/assets/",ext:".png",size:"72x72",className:"emoji",convert:{fromCodePoint:function(d){d="string"==typeof d?parseInt(d,16):d;if(d<65536)return e(d);return e(55296+((d-=65536)>>10),56320+(1023&d))},toCodePoint:o},onerror:function(){this.parentNode&&this.parentNode.replaceChild(x(this.alt,!1),this)},parse:function(d,u){u&&"function"!=typeof u||(u={callback:u});return h.doNotParse=u.doNotParse,("string"==typeof d?function(d,a){return n(d,function(d){var u,f,c=d,e=N(d),b=a.callback(e,a);if(e&&b){for(f in c="<img ".concat('class="',a.className,'" ','draggable="false" ','alt="',d,'"',' src="',b,'"'),u=a.attributes(d,e))u.hasOwnProperty(f)&&0!==f.indexOf("on")&&-1===c.indexOf(" "+f+"=")&&(c=c.concat(" ",f,'="',u[f].replace(t,r),'"'));c=c.concat("/>")}return c})}:function(d,u){var f,c,e,b,a,t,r,n,o,s,i,l=function d(u,f){var c,e,b=u.childNodes,a=b.length;for(;a--;)c=b[a],3===(e=c.nodeType)?f.push(c):1!==e||"ownerSVGElement"in c||m.test(c.nodeName.toLowerCase())||h.doNotParse&&h.doNotParse(c)||d(c,f);return f}(d,[]),p=l.length;for(;p--;){for(e=!1,b=document.createDocumentFragment(),a=l[p],t=a.nodeValue,r=0;o=g.exec(t);){if((i=o.index)!==r&&b.appendChild(x(t.slice(r,i),!0)),s=N(o=o[0]),r=i+o.length,i=u.callback(s,u),s&&i){for(c in(n=new Image).onerror=u.onerror,n.setAttribute("draggable","false"),f=u.attributes(o,s))f.hasOwnProperty(c)&&0!==c.indexOf("on")&&!n.hasAttribute(c)&&n.setAttribute(c,f[c]);n.className=u.className,n.alt=o,n.src=i,e=!0,b.appendChild(n)}n||b.appendChild(x(o,!1)),n=null}e&&(r<t.length&&b.appendChild(x(t.slice(r),!0)),a.parentNode.replaceChild(b,a))}return d})(d,{callback:u.callback||b,attributes:"function"==typeof u.attributes?u.attributes:a,base:("string"==typeof u.base?u:h).base,ext:u.ext||h.ext,size:u.folder||function(d){return"number"==typeof d?d+"x"+d:d}(u.size||h.size),className:u.className||h.className,onerror:u.onerror||h.onerror})},replace:n,test:function(d){g.lastIndex=0;d=g.test(d);return g.lastIndex=0,d}},u={"&":"&amp;","<":"&lt;",">":"&gt;","'":"&#39;",'"':"&quot;"},g=/(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83d\udc30\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udeef\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83d\udc30\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udeef\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83d\udc30\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udeef\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83d\udc30\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udeef\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83d\udc30\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udeef\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83d\udc30\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udeef\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83d\udc30\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udeef\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83d\udc30\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udeef\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83d\udc30\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udeef\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83d\udc30\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udeef\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83d\udc30\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udeef\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83d\udc30\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udeef\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83d\udc30\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udeef\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83d\udc30\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udeef\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83d\udc30\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udeef\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6f\ud83c\udffb\u200d\u2640\ufe0f|\ud83d\udc6f\ud83c\udffb\u200d\u2642\ufe0f|\ud83d\udc6f\ud83c\udffc\u200d\u2640\ufe0f|\ud83d\udc6f\ud83c\udffc\u200d\u2642\ufe0f|\ud83d\udc6f\ud83c\udffd\u200d\u2640\ufe0f|\ud83d\udc6f\ud83c\udffd\u200d\u2642\ufe0f|\ud83d\udc6f\ud83c\udffe\u200d\u2640\ufe0f|\ud83d\udc6f\ud83c\udffe\u200d\u2642\ufe0f|\ud83d\udc6f\ud83c\udfff\u200d\u2640\ufe0f|\ud83d\udc6f\ud83c\udfff\u200d\u2642\ufe0f|\ud83e\udd3c\ud83c\udffb\u200d\u2640\ufe0f|\ud83e\udd3c\ud83c\udffb\u200d\u2642\ufe0f|\ud83e\udd3c\ud83c\udffc\u200d\u2640\ufe0f|\ud83e\udd3c\ud83c\udffc\u200d\u2642\ufe0f|\ud83e\udd3c\ud83c\udffd\u200d\u2640\ufe0f|\ud83e\udd3c\ud83c\udffd\u200d\u2642\ufe0f|\ud83e\udd3c\ud83c\udffe\u200d\u2640\ufe0f|\ud83e\udd3c\ud83c\udffe\u200d\u2642\ufe0f|\ud83e\udd3c\ud83c\udfff\u200d\u2640\ufe0f|\ud83e\udd3c\ud83c\udfff\u200d\u2642\ufe0f|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc6f\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83e\udd3c\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc6f\udc8f\udc91]|\ud83e[\udd1d\udd3c])|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd\ude70])(?:\u200d\u27a1\ufe0f)?|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f(?:\u200d\u27a1\ufe0f)?)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f(?:\u200d\u27a1\ufe0f)?|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83e\uddd1\u200d\ud83e\uddd1\u200d\ud83e\uddd2\u200d\ud83e\uddd2|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83e\uddd1\u200d\ud83e\uddd1\u200d\ud83e\uddd2|\ud83e\uddd1\u200d\ud83e\uddd2\u200d\ud83e\uddd2|\ud83d\udc41\ufe0f\u200d\ud83d\udde8\ufe0f|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u26d3\ufe0f\u200d\ud83d\udca5|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udf44\u200d\ud83d\udfeb|\ud83c\udf4b\u200d\ud83d\udfe9|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc26\u200d\ud83d\udd25|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83d\ude42\u200d\u2194\ufe0f|\ud83d\ude42\u200d\u2195\ufe0f|\ud83e\uddd1\u200d\ud83e\uddd2|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b|\ud83d\udc26\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:(?:\ud83c[\udd70\udd71\udd7e\udd7f\ude02\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\xa9\xae\u203c\u2049\u2122\u2139\u2194-\u2199\u21a9\u21aa\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb\u25fc\u2600-\u2604\u260e\u2611\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u265f\u2660\u2663\u2665\u2666\u2668\u267b\u267e\u2692\u2694-\u2697\u2699\u269b\u269c\u26a0\u26a7\u26b0\u26b1\u26c8\u26cf\u26d1\u26d3\u26e9\u26f0\u26f1\u26f4\u26f8\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2763\u27a1\u2934\u2935\u2b05-\u2b07\u3030\u303d\u3297\u3299])\ufe0f)|(?:\ud83c[\udc04\ude1a\ude2f]|[\u231a\u231b\u25fd\u25fe\u2614\u2615\u2648-\u2653\u267f\u2693\u26a1\u26aa\u26ab\u26bd\u26be\u26c4\u26c5\u26d4\u26ea\u26f2\u26f3\u26f5\u26fa\u26fd\u2757\u2764\u2b1b\u2b1c\u2b50\u2b55])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83e\udef0)(?:\ufe0f|(?!\ufe0e))|(?:\ud83c\udfc3|\ud83d\udeb6|\ud83e\uddce)(?:\ud83c[\udffb-\udfff])?(?:\u200d\u27a1\ufe0f)?|(?:\ud83c[\udf85\udfc2\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4\udeb5\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd\uddcf\uddd1-\udddd\udec3-\udec5\udef1-\udef8]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded8\udedc-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude7c\ude80-\ude8a\ude8e-\udec2\udec6\udec8\udecd-\udedc\udedf-\udeea\udeef]|[\u23e9-\u23ec\u23f0\u23f3\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g,f=/\uFE0F/g,c=String.fromCharCode(8205),t=/[&<>'"]/g,m=/^(?:iframe|noframes|noscript|script|select|style|textarea)$/,e=String.fromCharCode;return h;function x(d,u){return document.createTextNode(u?d.replace(f,""):d)}function b(d,u){return"".concat(u.base,u.size,"/",d,u.ext)}function N(d){return o(d.indexOf(c)<0?d.replace(f,""):d)}function r(d){return u[d]}function a(){return null}function n(d,u){return String(d).replace(g,u)}function o(d,u){for(var f=[],c=0,e=0,b=0;b<d.length;)c=d.charCodeAt(b++),e?(f.push((65536+(e-55296<<10)+(c-56320)).toString(16)),e=0):55296<=c&&c<=56319?e=c:f.push(c.toString(16));return f.join(u||"-")}}();
 // Source: wp-includes/js/wp-emoji.min.js
-!function(c,l){c.wp=c.wp||{},c.wp.emoji=new function(){var n,e,t=c.MutationObserver||c.WebKitMutationObserver||c.MozMutationObserver,r=c.document,a=!1,o=0,i=0<c.navigator.userAgent.indexOf("Trident/7.0");function s(){return!r.implementation.hasFeature||r.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")}function d(u){return!!u&&(/[\uDC00-\uDFFF]/.test(u)||/[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/.test(u))}function f(u,e){var t;return!l.supports.everything&&n&&u&&("string"==typeof u||u.childNodes&&u.childNodes.length)?(e=e||{},t={base:s()?l.svgUrl:l.baseUrl,ext:s()?l.svgExt:l.ext,className:e.className||"emoji",callback:function(u,e){switch(u){case"a9":case"ae":case"2122":case"2194":case"2660":case"2663":case"2665":case"2666":return!1}return!(l.supports.everythingExceptFlag&&!/^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test(u)&&!/^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test(u))&&"".concat(e.base,u,e.ext)},attributes:function(){return{role:"img"}},onerror:function(){n.parentNode&&(this.setAttribute("data-error","load-failed"),n.parentNode.replaceChild(r.createTextNode(n.alt),n))},doNotParse:function(u){return!(!u||!u.className||"string"!=typeof u.className||-1===u.className.indexOf("wp-exclude-emoji"))}},"object"==typeof e.imgAttr&&(t.attributes=function(){return e.imgAttr}),n.parse(u,t)):u}return function u(){if(!a){if(void 0===c.twemoji)return 600<o?void 0:(c.clearTimeout(e),e=c.setTimeout(u,50),void o++);n=c.twemoji,a=!0,t&&new t(function(u){for(var e,t,n,r,a=u.length;a--;){if(e=u[a].addedNodes,t=u[a].removedNodes,1===(n=e.length)&&1===t.length&&3===e[0].nodeType&&"IMG"===t[0].nodeName&&e[0].data===t[0].alt&&"load-failed"===t[0].getAttribute("data-error"))return;for(;n--;){if(3===(r=e[n]).nodeType){if(!r.parentNode)continue;if(i)for(;r.nextSibling&&3===r.nextSibling.nodeType;)r.nodeValue=r.nodeValue+r.nextSibling.nodeValue,r.parentNode.removeChild(r.nextSibling);r=r.parentNode}d(r.textContent)&&f(r)}}}).observe(r.body,{childList:!0,subtree:!0}),f(r.body)}}(),{parse:f,test:d}}}(window,window._wpemojiSettings);
\ No newline at end of file
+!function(n,c){n.wp=n.wp||{},n.wp.emoji=function(){const o=n.document;let s,e,t=!1,a=0;function r(u){return!!u&&(/[\uDC00-\uDFFF]/.test(u)||/[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/.test(u))}function i(u,e){if(c.supports.everything||!s||!u||"string"!=typeof u&&(!u.childNodes||!u.childNodes.length))return u;const t="object"==typeof(e=e||{}).imgAttr?e.imgAttr:{role:"img"};e={base:c.svgUrl,ext:c.svgExt,className:e.className||"emoji",callback:(u,e)=>{switch(u){case"a9":case"ae":case"2122":case"2194":case"2660":case"2663":case"2665":case"2666":return!1}return!(c.supports.everythingExceptFlag&&!/^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test(u)&&!/^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test(u))&&"".concat(e.base,u,e.ext)},attributes:()=>t,onerror:function(){this.parentNode&&(this.dataset.error="load-failed",this.parentNode.replaceChild(o.createTextNode(this.alt),this))},doNotParse:u=>u.classList.contains("wp-exclude-emoji")};return s.parse(u,e)}return function u(){if(!t){if(void 0===n.twemoji)return 600<a?void 0:(n.clearTimeout(e),e=n.setTimeout(u,50),void a++);s=n.twemoji,t=!0,new MutationObserver(u=>{for(var{addedNodes:e,removedNodes:t}of u){var o=e[0],s=t[0];if(!(1===e.length&&1===t.length&&o instanceof Text&&s instanceof HTMLImageElement&&o.data===s.alt&&"load-failed"===s.dataset.error))for(const n of e){var a=n instanceof Text?n.parentElement:n;a instanceof HTMLElement&&r(a.textContent)&&i(a)}}}).observe(o.body,{childList:!0,subtree:!0}),i(o.body)}}(),{parse:i,test:r}}()}(window,window._wpemojiSettings);
\ No newline at end of file
diff --git a/wp-includes/js/wp-emoji.js b/wp-includes/js/wp-emoji.js
index 274868f52d..a1f0f4face 100644
--- a/wp-includes/js/wp-emoji.js
+++ b/wp-includes/js/wp-emoji.js
@@ -1,58 +1,52 @@
+/**
+ * @output wp-includes/js/wp-emoji.js
+ */
+
+/**
+ * Additional options accepted by wp.emoji.parse().
+ *
+ * @typedef WPEmojiParseArgs
+ * @type {Object}
+ * @property {string}                 [className] Class name to give each generated image.
+ * @property {Record<string, string>} [imgAttr]   Attributes to set on each generated image, in
+ *                                                place of the default ones.
+ */
+
 /**
  * wp-emoji.js is used to replace emoji with images in browsers when the browser
  * doesn't support emoji natively.
  *
- * @param {Window} window   The global window object.
- * @param {Object} settings The settings object.
- * @output wp-includes/js/wp-emoji.js
+ * @param {Window}          window   The global window object.
+ * @param {WPEmojiSettings} settings The settings object.
  */
-
-( function( window, settings ) {
+( function ( window, settings ) {
 	/**
 	 * Replaces emoji with images when browsers don't support emoji.
 	 *
 	 * @since 4.2.0
 	 * @access private
 	 *
-	 * @class
+	 * @see  Twemoji
+	 * @link https://github.com/jdecked/twemoji
 	 *
-	 * @see  Twitter Emoji library
-	 * @link https://github.com/twitter/twemoji
-	 *
-	 * @return {Object} The wpEmoji parse and test functions.
+	 * @return {{
+	 *     parse: ( object: HTMLElement|string, args?: WPEmojiParseArgs ) => HTMLElement|string,
+	 *     test: ( text: ?string ) => boolean
+	 * }} The wpEmoji parse and test functions.
 	 */
 	function wpEmoji() {
-		var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
-
 		// Compression and maintain local scope.
-		document = window.document,
+		const document = window.document;

 		// Private.
-		twemoji, timer,
-		loaded = false,
-		count = 0,
-		ie11 = window.navigator.userAgent.indexOf( 'Trident/7.0' ) > 0;
+		/** @type {Twemoji|undefined} */
+		let twemoji;

-		/**
-		 * Detect if the browser supports SVG.
-		 *
-		 * @since 4.6.0
-		 * @private
-		 *
-		 * @see Modernizr
-		 * @link https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg/asimg.js
-		 *
-		 * @return {boolean} True if the browser supports svg, false if not.
-		 */
-		function browserSupportsSvgAsImage() {
-			if ( !! document.implementation.hasFeature ) {
-				return document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' );
-			}
+		/** @type {number|undefined} */
+		let timer;

-			// document.implementation.hasFeature is deprecated. It can be presumed
-			// if future browsers remove it, the browser will support SVGs as images.
-			return true;
-		}
+		let loaded = false;
+		let count = 0;

 		/**
 		 * Runs when the document load event is fired, so we can do our first parse of
@@ -89,74 +83,42 @@

 			// Initialize the mutation observer, which checks all added nodes for
 			// replaceable emoji characters.
-			if ( MutationObserver ) {
-				new MutationObserver( function( mutationRecords ) {
-					var i = mutationRecords.length,
-						addedNodes, removedNodes, ii, node;
-
-					while ( i-- ) {
-						addedNodes = mutationRecords[ i ].addedNodes;
-						removedNodes = mutationRecords[ i ].removedNodes;
-						ii = addedNodes.length;
-
-						/*
-						 * Checks if an image has been replaced by a text element
-						 * with the same text as the alternate description of the replaced image.
-						 * (presumably because the image could not be loaded).
-						 * If it is, do absolutely nothing.
-						 *
-						 * Node type 3 is a TEXT_NODE.
-						 *
-						 * @link https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
-						 */
-						if (
-							ii === 1 && removedNodes.length === 1 &&
-							addedNodes[0].nodeType === 3 &&
-							removedNodes[0].nodeName === 'IMG' &&
-							addedNodes[0].data === removedNodes[0].alt &&
-							'load-failed' === removedNodes[0].getAttribute( 'data-error' )
-						) {
-							return;
-						}
+			new MutationObserver( ( mutationRecords ) => {
+				for ( const { addedNodes, removedNodes } of mutationRecords ) {
+					const addedNode = addedNodes[ 0 ];
+					const removedNode = removedNodes[ 0 ];
+
+					/*
+					 * Checks if an image has been replaced by a text element
+					 * with the same text as the alternate description of the replaced image.
+					 * (presumably because the image could not be loaded).
+					 * If it is, leave this record alone, so that the text is not turned
+					 * straight back into the image which just failed to load.
+					 */
+					if (
+						addedNodes.length === 1 && removedNodes.length === 1 &&
+						addedNode instanceof Text &&
+						removedNode instanceof HTMLImageElement &&
+						addedNode.data === removedNode.alt &&
+						'load-failed' === removedNode.dataset.error
+					) {
+						continue;
+					}

-						// Loop through all the added nodes.
-						while ( ii-- ) {
-							node = addedNodes[ ii ];
-
-							// Node type 3 is a TEXT_NODE.
-							if ( node.nodeType === 3 ) {
-								if ( ! node.parentNode ) {
-									continue;
-								}
-
-								if ( ie11 ) {
-									/*
-									 * IE 11's implementation of MutationObserver is buggy.
-									 * It unnecessarily splits text nodes when it encounters a HTML
-									 * template interpolation symbol ( "{{", for example ). So, we
-									 * join the text nodes back together as a work-around.
-									 *
-									 * Node type 3 is a TEXT_NODE.
-									 */
-									while( node.nextSibling && 3 === node.nextSibling.nodeType ) {
-										node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
-										node.parentNode.removeChild( node.nextSibling );
-									}
-								}
-
-								node = node.parentNode;
-							}
-
-							if ( test( node.textContent ) ) {
-								parse( node );
-							}
+					// Loop through all the added nodes.
+					for ( const addedNode of addedNodes ) {
+						// Emoji in a text node are replaced by parsing the element which contains it.
+						const node = addedNode instanceof Text ? addedNode.parentElement : addedNode;
+
+						if ( node instanceof HTMLElement && test( node.textContent ) ) {
+							parse( node );
 						}
 					}
-				} ).observe( document.body, {
-					childList: true,
-					subtree: true
-				} );
-			}
+				}
+			} ).observe( document.body, {
+				childList: true,
+				subtree: true
+			} );

 			parse( document.body );
 		}
@@ -168,18 +130,19 @@
 		 *
 		 * @memberOf wp.emoji
 		 *
-		 * @param {string} text The string to test.
+		 * @param {?string} text The string to test.
 		 *
 		 * @return {boolean} Whether the string contains emoji characters.
 		 */
 		function test( text ) {
 			// Single char. U+20E3 to detect keycaps. U+00A9 "copyright sign" and U+00AE "registered sign" not included.
-			var single = /[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/,
+			const single = /[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/;
+
 			// Surrogate pair range. Only tests for the second half.
-			pair = /[\uDC00-\uDFFF]/;
+			const pair = /[\uDC00-\uDFFF]/;

 			if ( text ) {
-				return  pair.test( text ) || single.test( text );
+				return pair.test( text ) || single.test( text );
 			}

 			return false;
@@ -197,14 +160,12 @@
 		 * @memberOf wp.emoji
 		 *
 		 * @param {HTMLElement|string} object The element or string to parse.
-		 * @param {Object}             args   Additional options for Twemoji.
+		 * @param {WPEmojiParseArgs}   [args] Additional options for Twemoji.
 		 *
 		 * @return {HTMLElement|string} A string where all emoji are now image tags of
 		 *                              emoji. Or the element that was passed as the first argument.
 		 */
 		function parse( object, args ) {
-			var params;
-
 			/*
 			 * If the browser has full support, twemoji is not loaded or our
 			 * object is not what was expected, we do not parse anything.
@@ -217,11 +178,16 @@

 			// Compose the params for the twitter emoji library.
 			args = args || {};
-			params = {
-				base: browserSupportsSvgAsImage() ? settings.svgUrl : settings.baseUrl,
-				ext:  browserSupportsSvgAsImage() ? settings.svgExt : settings.ext,
+
+			// The caller may replace the attributes given to every generated image.
+			const attributes = typeof args.imgAttr === 'object' ? args.imgAttr : { role: 'img' };
+
+			/** @type {TwemojiParseOptions} */
+			const params = {
+				base: settings.svgUrl,
+				ext: settings.svgExt,
 				className: args.className || 'emoji',
-				callback: function( icon, options ) {
+				callback: ( icon, options ) => {
 					// Ignore some standard characters that TinyMCE recommends in its character map.
 					switch ( icon ) {
 						case 'a9':
@@ -244,47 +210,30 @@

 					return ''.concat( options.base, icon, options.ext );
 				},
-				attributes: function() {
-					return {
-						role: 'img'
-					};
-				},
-				onerror: function() {
-					if ( twemoji.parentNode ) {
-						this.setAttribute( 'data-error', 'load-failed' );
-						twemoji.parentNode.replaceChild( document.createTextNode( twemoji.alt ), twemoji );
+				attributes: () => attributes,
+				onerror: function () {
+					/*
+					 * Put the emoji character back in place of the image which failed to load. The
+					 * attribute is what tells the MutationObserver above that this replacement is
+					 * the one it must not turn straight back into an image.
+					 */
+					if ( this.parentNode ) {
+						this.dataset.error = 'load-failed';
+						this.parentNode.replaceChild( document.createTextNode( this.alt ), this );
 					}
 				},
-				doNotParse: function( node ) {
-					if (
-						node &&
-						node.className &&
-						typeof node.className === 'string' &&
-						node.className.indexOf( 'wp-exclude-emoji' ) !== -1
-					) {
-						// Do not parse this node. Emojis will not be replaced in this node and all sub-nodes.
-						return true;
-					}
-
-					return false;
+				doNotParse: ( element ) => {
+					// Emoji will not be replaced in this element, nor in any of its descendants.
+					return element.classList.contains( 'wp-exclude-emoji' );
 				}
 			};

-			if ( typeof args.imgAttr === 'object' ) {
-				params.attributes = function() {
-					return args.imgAttr;
-				};
-			}
-
 			return twemoji.parse( object, params );
 		}

 		load();

-		return {
-			parse: parse,
-			test: test
-		};
+		return { parse, test };
 	}

 	window.wp = window.wp || {};
@@ -292,6 +241,6 @@
 	/**
 	 * @namespace wp.emoji
 	 */
-	window.wp.emoji = new wpEmoji();
+	window.wp.emoji = wpEmoji();

 } )( window, window._wpemojiSettings );
diff --git a/wp-includes/js/wp-emoji.min.js b/wp-includes/js/wp-emoji.min.js
index 58abd962ec..6de96db420 100644
--- a/wp-includes/js/wp-emoji.min.js
+++ b/wp-includes/js/wp-emoji.min.js
@@ -1,2 +1,2 @@
 /*! This file is auto-generated */
-!function(c,l){c.wp=c.wp||{},c.wp.emoji=new function(){var n,e,t=c.MutationObserver||c.WebKitMutationObserver||c.MozMutationObserver,r=c.document,a=!1,o=0,i=0<c.navigator.userAgent.indexOf("Trident/7.0");function s(){return!r.implementation.hasFeature||r.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")}function d(u){return!!u&&(/[\uDC00-\uDFFF]/.test(u)||/[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/.test(u))}function f(u,e){var t;return!l.supports.everything&&n&&u&&("string"==typeof u||u.childNodes&&u.childNodes.length)?(e=e||{},t={base:s()?l.svgUrl:l.baseUrl,ext:s()?l.svgExt:l.ext,className:e.className||"emoji",callback:function(u,e){switch(u){case"a9":case"ae":case"2122":case"2194":case"2660":case"2663":case"2665":case"2666":return!1}return!(l.supports.everythingExceptFlag&&!/^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test(u)&&!/^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test(u))&&"".concat(e.base,u,e.ext)},attributes:function(){return{role:"img"}},onerror:function(){n.parentNode&&(this.setAttribute("data-error","load-failed"),n.parentNode.replaceChild(r.createTextNode(n.alt),n))},doNotParse:function(u){return!(!u||!u.className||"string"!=typeof u.className||-1===u.className.indexOf("wp-exclude-emoji"))}},"object"==typeof e.imgAttr&&(t.attributes=function(){return e.imgAttr}),n.parse(u,t)):u}return function u(){if(!a){if(void 0===c.twemoji)return 600<o?void 0:(c.clearTimeout(e),e=c.setTimeout(u,50),void o++);n=c.twemoji,a=!0,t&&new t(function(u){for(var e,t,n,r,a=u.length;a--;){if(e=u[a].addedNodes,t=u[a].removedNodes,1===(n=e.length)&&1===t.length&&3===e[0].nodeType&&"IMG"===t[0].nodeName&&e[0].data===t[0].alt&&"load-failed"===t[0].getAttribute("data-error"))return;for(;n--;){if(3===(r=e[n]).nodeType){if(!r.parentNode)continue;if(i)for(;r.nextSibling&&3===r.nextSibling.nodeType;)r.nodeValue=r.nodeValue+r.nextSibling.nodeValue,r.parentNode.removeChild(r.nextSibling);r=r.parentNode}d(r.textContent)&&f(r)}}}).observe(r.body,{childList:!0,subtree:!0}),f(r.body)}}(),{parse:f,test:d}}}(window,window._wpemojiSettings);
\ No newline at end of file
+!function(n,c){n.wp=n.wp||{},n.wp.emoji=function(){const o=n.document;let s,e,t=!1,a=0;function r(u){return!!u&&(/[\uDC00-\uDFFF]/.test(u)||/[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/.test(u))}function i(u,e){if(c.supports.everything||!s||!u||"string"!=typeof u&&(!u.childNodes||!u.childNodes.length))return u;const t="object"==typeof(e=e||{}).imgAttr?e.imgAttr:{role:"img"};e={base:c.svgUrl,ext:c.svgExt,className:e.className||"emoji",callback:(u,e)=>{switch(u){case"a9":case"ae":case"2122":case"2194":case"2660":case"2663":case"2665":case"2666":return!1}return!(c.supports.everythingExceptFlag&&!/^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test(u)&&!/^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test(u))&&"".concat(e.base,u,e.ext)},attributes:()=>t,onerror:function(){this.parentNode&&(this.dataset.error="load-failed",this.parentNode.replaceChild(o.createTextNode(this.alt),this))},doNotParse:u=>u.classList.contains("wp-exclude-emoji")};return s.parse(u,e)}return function u(){if(!t){if(void 0===n.twemoji)return 600<a?void 0:(n.clearTimeout(e),e=n.setTimeout(u,50),void a++);s=n.twemoji,t=!0,new MutationObserver(u=>{for(var{addedNodes:e,removedNodes:t}of u){var o=e[0],s=t[0];if(!(1===e.length&&1===t.length&&o instanceof Text&&s instanceof HTMLImageElement&&o.data===s.alt&&"load-failed"===s.dataset.error))for(const n of e){var a=n instanceof Text?n.parentElement:n;a instanceof HTMLElement&&r(a.textContent)&&i(a)}}}).observe(o.body,{childList:!0,subtree:!0}),i(o.body)}}(),{parse:i,test:r}}()}(window,window._wpemojiSettings);
\ No newline at end of file
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 3d806b4e37..65548bbf74 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-64248';
+$wp_version = '7.2-alpha-64249';

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