Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions src/js/_enqueues/lib/emoji-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// 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().
* Emoji Settings as exported in PHP via the script module data API.
* @typedef WPEmojiSettings
* @type {object}
* @property {?object} source
Expand All @@ -16,9 +16,31 @@
* @property {?string} source.wpemoji
*/

const settings = /** @type {WPEmojiSettings} */ (
JSON.parse( document.getElementById( 'wp-emoji-settings' ).textContent )
);
/**
* Parses the Emoji settings from the script module data element.
*
* @since 7.1.0
*
* @return {WPEmojiSettings} Emoji settings.
*/
function getEmojiSettings() {
const moduleDataContainer = document.getElementById(
'wp-script-module-data-wp-emoji-loader'
);
if ( moduleDataContainer ) {
return JSON.parse( moduleDataContainer.textContent );
}

// Back-compat for extensions that may still be printing the legacy element.
const legacySettingsContainer = document.getElementById( 'wp-emoji-settings' );
if ( legacySettingsContainer ) {
return JSON.parse( legacySettingsContainer.textContent );
}

return {};
}

const settings = /** @type {WPEmojiSettings} */ ( getEmojiSettings() );

// For compatibility with other scripts that read from this global, in particular wp-includes/js/wp-emoji.js (source file: js/_enqueues/wp/emoji.js).
window._wpemojiSettings = settings;
Expand Down
92 changes: 66 additions & 26 deletions src/wp-includes/formatting.php
Original file line number Diff line number Diff line change
Expand Up @@ -5894,34 +5894,63 @@ function wp_enqueue_emoji_styles() {
}

/**
* Prints the inline Emoji detection script if it is not already printed.
* Enqueues the Emoji detection script module if it is not already enqueued.
*
* @since 4.2.0
*/
function print_emoji_detection_script() {
static $printed = false;
static $enqueued = false;

if ( $printed ) {
if ( $enqueued ) {
return;
}

$printed = true;
$enqueued = true;

if ( did_action( 'wp_print_footer_scripts' ) ) {
_print_emoji_detection_script();
} else {
add_action( 'wp_print_footer_scripts', '_print_emoji_detection_script' );
}
_wp_enqueue_emoji_detection_script();
}

/**
* Prints inline Emoji detection script.
* Enqueues the Emoji detection script module.
*
* @ignore
* @since 4.6.0
* @since 7.1.0 The emoji loader is enqueued as an external script module.
* @access private
*/
function _print_emoji_detection_script() {
function _wp_enqueue_emoji_detection_script() {
if ( ! has_filter( 'script_module_data_wp-emoji-loader', '_wp_emoji_settings_script_module_data' ) ) {
add_filter( 'script_module_data_wp-emoji-loader', '_wp_emoji_settings_script_module_data' );
}

$emoji_loader_script_path = '/js/wp-emoji-loader' . wp_scripts_get_suffix() . '.js';
$src = includes_url( $emoji_loader_script_path );

/** This filter is documented in wp-includes/class-wp-scripts.php */
$src = apply_filters( 'script_loader_src', $src, 'wp-emoji-loader' );

wp_enqueue_script_module(
'wp-emoji-loader',
$src,
array(),
false,
array(
'fetchpriority' => 'low',
'in_footer' => true,
)
);
}

/**
* Returns the Emoji settings for the script module.
*
* @ignore
* @since 7.1.0
* @access private
*
* @return array<string, mixed> Emoji settings.
*/
function _wp_get_emoji_settings(): array {
$settings = array(
/**
* Filters the URL where emoji png images are hosted.
Expand Down Expand Up @@ -5976,22 +6005,33 @@ function _print_emoji_detection_script() {
);
}

wp_print_inline_script_tag(
wp_json_encode( $settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
array(
'id' => 'wp-emoji-settings',
'type' => 'application/json',
)
);
return $settings;
}

$emoji_loader_script_path = '/js/wp-emoji-loader' . wp_scripts_get_suffix() . '.js';
wp_print_inline_script_tag(
rtrim( file_get_contents( ABSPATH . WPINC . $emoji_loader_script_path ) ) . "\n" .
'//# sourceURL=' . esc_url_raw( includes_url( $emoji_loader_script_path ) ),
array(
'type' => 'module',
)
);
/**
* Filters the Emoji settings passed to the script module.
*
* @ignore
* @since 7.1.0
* @access private
*
* @param array<string, mixed> $data Script module data.
* @return array<string, mixed> Emoji settings.
*/
function _wp_emoji_settings_script_module_data( array $data ): array {
return _wp_get_emoji_settings();
}

/**
* Enqueues the Emoji detection script module.
*
* @ignore
* @since 4.6.0
* @deprecated 7.1.0 Use {@see _wp_enqueue_emoji_detection_script()} instead.
* @access private
*/
function _print_emoji_detection_script() {
_wp_enqueue_emoji_detection_script();
}

/**
Expand Down
78 changes: 60 additions & 18 deletions tests/phpunit/tests/formatting/emoji.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,64 @@ class Tests_Formatting_Emoji extends WP_UnitTestCase {
private $png_cdn = 'https://s.w.org/images/core/emoji/17.0.2/72x72/';
private $svg_cdn = 'https://s.w.org/images/core/emoji/17.0.2/svg/';

/**
* @var WP_Script_Modules|null
*/
private $original_script_modules;

/**
* @inheritDoc
*/
public function set_up() {
global $wp_script_modules;

parent::set_up();

$this->original_script_modules = $wp_script_modules;
$wp_script_modules = null;
wp_script_modules();
}

/**
* @inheritDoc
*/
public function tear_down() {
global $wp_script_modules;

$wp_script_modules = $this->original_script_modules;
parent::tear_down();
}

/**
* Returns the markup printed for the emoji detection script module.
*
* @return string Emoji detection script module markup.
*/
private function get_emoji_detection_script_output() {
// `_wp_enqueue_emoji_detection_script()` assumes `wp-includes/js/wp-emoji-loader.js` is present:
self::touch( ABSPATH . WPINC . '/js/wp-emoji-loader.js' );

_wp_enqueue_emoji_detection_script();

return get_echo( array( wp_script_modules(), 'print_script_module_data' ) ) .
get_echo( array( wp_script_modules(), 'print_enqueued_script_modules' ) );
}

/**
* @ticket 63842
* @ticket 64259
*
* @covers ::_print_emoji_detection_script
* @covers ::_wp_enqueue_emoji_detection_script
* @covers ::_wp_get_emoji_settings
* @covers ::_wp_emoji_settings_script_module_data
*/
public function test_script_tag_printing() {
// `_print_emoji_detection_script()` assumes `wp-includes/js/wp-emoji-loader.js` is present:
self::touch( ABSPATH . WPINC . '/js/wp-emoji-loader.js' );
$output = get_echo( '_print_emoji_detection_script' );
$output = $this->get_emoji_detection_script_output();

$processor = new WP_HTML_Tag_Processor( $output );
$this->assertTrue( $processor->next_tag() );
$this->assertSame( 'SCRIPT', $processor->get_tag() );
$this->assertSame( 'wp-emoji-settings', $processor->get_attribute( 'id' ) );
$this->assertSame( 'wp-script-module-data-wp-emoji-loader', $processor->get_attribute( 'id' ) );
$this->assertSame( 'application/json', $processor->get_attribute( 'type' ) );
$text = $processor->get_modifiable_text();
$settings = json_decode( $text, true );
Expand All @@ -42,19 +86,19 @@ public function test_script_tag_printing() {
$this->assertTrue( $processor->next_tag() );
$this->assertSame( 'SCRIPT', $processor->get_tag() );
$this->assertSame( 'module', $processor->get_attribute( 'type' ) );
$this->assertNull( $processor->get_attribute( 'src' ) );
$this->assertSame( 'low', $processor->get_attribute( 'fetchpriority' ) );
$this->assertStringContainsString( 'wp-emoji-loader.js', (string) $processor->get_attribute( 'src' ) );
$this->assertFalse( $processor->next_tag() );
}

/**
* @ticket 36525
* @ticket 64259
*
* @covers ::_print_emoji_detection_script
* @covers ::_wp_enqueue_emoji_detection_script
*/
public function test_unfiltered_emoji_cdns() {
// `_print_emoji_detection_script()` assumes `wp-includes/js/wp-emoji-loader.js` is present:
self::touch( ABSPATH . WPINC . '/js/wp-emoji-loader.js' );
$output = get_echo( '_print_emoji_detection_script' );
$output = $this->get_emoji_detection_script_output();

$this->assertStringContainsString( wp_json_encode( $this->png_cdn, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $output );
$this->assertStringContainsString( wp_json_encode( $this->svg_cdn, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $output );
Expand All @@ -66,17 +110,16 @@ public function _filtered_emoji_svg_cdn( $cdn = '' ) {

/**
* @ticket 36525
* @ticket 64259
*
* @covers ::_print_emoji_detection_script
* @covers ::_wp_enqueue_emoji_detection_script
*/
public function test_filtered_emoji_svn_cdn() {
$filtered_svn_cdn = $this->_filtered_emoji_svg_cdn();

add_filter( 'emoji_svg_url', array( $this, '_filtered_emoji_svg_cdn' ) );

// `_print_emoji_detection_script()` assumes `wp-includes/js/wp-emoji-loader.js` is present:
self::touch( ABSPATH . WPINC . '/js/wp-emoji-loader.js' );
$output = get_echo( '_print_emoji_detection_script' );
$output = $this->get_emoji_detection_script_output();

$this->assertStringContainsString( wp_json_encode( $this->png_cdn, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $output );
$this->assertStringNotContainsString( wp_json_encode( $this->svg_cdn, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $output );
Expand All @@ -91,17 +134,16 @@ public function _filtered_emoji_png_cdn( $cdn = '' ) {

/**
* @ticket 36525
* @ticket 64259
*
* @covers ::_print_emoji_detection_script
* @covers ::_wp_enqueue_emoji_detection_script
*/
public function test_filtered_emoji_png_cdn() {
$filtered_png_cdn = $this->_filtered_emoji_png_cdn();

add_filter( 'emoji_url', array( $this, '_filtered_emoji_png_cdn' ) );

// `_print_emoji_detection_script()` assumes `wp-includes/js/wp-emoji-loader.js` is present:
self::touch( ABSPATH . WPINC . '/js/wp-emoji-loader.js' );
$output = get_echo( '_print_emoji_detection_script' );
$output = $this->get_emoji_detection_script_output();

$this->assertStringContainsString( wp_json_encode( $filtered_png_cdn, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $output );
$this->assertStringNotContainsString( wp_json_encode( $this->png_cdn, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $output );
Expand Down
Loading