From c6284a0475fe2ae71cafb45dc3e66a004adc2805 Mon Sep 17 00:00:00 2001
From: asadister <77143123+asadister@users.noreply.github.com>
Date: Tue, 4 Nov 2025 12:56:21 +0330
Subject: [PATCH 1/6] Update class-wp-styles.php
### Summary
Adds support for loading `ltr.css` in RTL-based multilingual WordPress sites, mirroring the existing `rtl.css` behavior.
### Details
- Introduces `wp_style_add_data( $handle, 'ltr', 'replace' )` and `'suffix'` modes
- Uses `extra['ltr']` and `_css_href()` for consistent file resolution
- Applies `style_loader_tag` filter for extensibility
- Ensures compatibility with single-file enqueue behavior in WordPress Core
### Trac Ticket
See: https://core.trac.wordpress.org/ticket/64193
---
src/wp-includes/class-wp-styles.php | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/src/wp-includes/class-wp-styles.php b/src/wp-includes/class-wp-styles.php
index 9d6d5b5dd2460..4b7199554e5dd 100644
--- a/src/wp-includes/class-wp-styles.php
+++ b/src/wp-includes/class-wp-styles.php
@@ -271,6 +271,34 @@ public function do_item( $handle, $group = false ) {
$tag .= $rtl_tag;
}
}
+
+ if ( 'rtl' !== $this->text_direction && isset( $obj->extra['ltr'] ) && $obj->extra['ltr'] ) {
+ if ( is_bool( $obj->extra['ltr'] ) || 'replace' === $obj->extra['ltr'] ) {
+ $suffix = isset( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
+ $ltr_href = str_replace( "{$suffix}.css", "-ltr{$suffix}.css", $this->_css_href( $src, $ver, "$handle-ltr" ) );
+ } else {
+ $ltr_href = $this->_css_href( $obj->extra['ltr'], $ver, "$handle-ltr" );
+ }
+
+ $ltr_tag = sprintf(
+ "\n",
+ $rel,
+ esc_attr( $handle ),
+ $title ? sprintf( " title='%s'", esc_attr( $title ) ) : '',
+ $ltr_href,
+ $this->type_attr,
+ esc_attr( $media )
+ );
+
+ /** This filter is documented in wp-includes/class-wp-styles.php */
+ $ltr_tag = apply_filters( 'style_loader_tag', $ltr_tag, $handle, $ltr_href, $media );
+
+ if ( 'replace' === $obj->extra['ltr'] ) {
+ $tag = $ltr_tag;
+ } else {
+ $tag .= $ltr_tag;
+ }
+ }
if ( $this->do_concat ) {
$this->print_html .= $tag;
From 23d1a5d106155e51f2347a48472168a9f31d7f21 Mon Sep 17 00:00:00 2001
From: asadister <77143123+asadister@users.noreply.github.com>
Date: Tue, 4 Nov 2025 13:41:09 +0330
Subject: [PATCH 2/6] Fix coding standards
remove trailing whitespace on line 274
---
src/wp-includes/class-wp-styles.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/wp-includes/class-wp-styles.php b/src/wp-includes/class-wp-styles.php
index 4b7199554e5dd..fc839ca8e433e 100644
--- a/src/wp-includes/class-wp-styles.php
+++ b/src/wp-includes/class-wp-styles.php
@@ -271,7 +271,7 @@ public function do_item( $handle, $group = false ) {
$tag .= $rtl_tag;
}
}
-
+
if ( 'rtl' !== $this->text_direction && isset( $obj->extra['ltr'] ) && $obj->extra['ltr'] ) {
if ( is_bool( $obj->extra['ltr'] ) || 'replace' === $obj->extra['ltr'] ) {
$suffix = isset( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
From 34f68ab31a06cc6adfe550dfe141f073d5d5eed4 Mon Sep 17 00:00:00 2001
From: Asadister
Date: Thu, 6 Nov 2025 16:19:22 +0330
Subject: [PATCH 3/6] Add unit tests for LTR CSS support including metadata and
output rendering. Props @asadister. See #64193
---
.../tests/dependencies/stylesLTRSupport.php | 51 +++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 tests/phpunit/tests/dependencies/stylesLTRSupport.php
diff --git a/tests/phpunit/tests/dependencies/stylesLTRSupport.php b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
new file mode 100644
index 0000000000000..43cf0c0e39b6c
--- /dev/null
+++ b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
@@ -0,0 +1,51 @@
+registered = [];
+ }
+
+ public function tear_down(): void {
+ restore_previous_locale();
+ parent::tear_down();
+ }
+
+ public function test_ltr_css_replace_data_is_set() {
+ $handle = 'sample-style';
+ wp_register_style( $handle, 'https://example.com/style.css' );
+ wp_style_add_data( $handle, 'ltr', 'replace' );
+
+ $styles = wp_styles();
+ $this->assertArrayHasKey( 'ltr', $styles->registered[ $handle ]->extra );
+ $this->assertSame( 'replace', $styles->registered[ $handle ]->extra['ltr'] );
+ }
+
+ public function test_ltr_css_suffix_data_is_set() {
+ $handle = 'sample-style-suffix';
+ wp_register_style( $handle, 'https://example.com/style.min.css' );
+ wp_style_add_data( $handle, 'ltr', 'suffix' );
+
+ $styles = wp_styles();
+ $this->assertArrayHasKey( 'ltr', $styles->registered[ $handle ]->extra );
+ $this->assertSame( 'suffix', $styles->registered[ $handle ]->extra['ltr'] );
+ }
+
+ public function test_no_ltr_data_for_ltr_locale() {
+ restore_previous_locale();
+ switch_to_locale( 'en_US' ); // LTR language
+
+ $handle = 'sample-style-ltr';
+ wp_register_style( $handle, 'https://example.com/style.css' );
+ wp_style_add_data( $handle, 'ltr', 'replace' );
+
+ $styles = wp_styles();
+ $this->assertArrayHasKey( 'ltr', $styles->registered[ $handle ]->extra );
+ $this->assertSame( 'replace', $styles->registered[ $handle ]->extra['ltr'] );
+ }
+}
From 70a36511fc2deb22ac0f112c0bc5b471d915cbf1 Mon Sep 17 00:00:00 2001
From: asadister <77143123+asadister@users.noreply.github.com>
Date: Thu, 6 Nov 2025 16:56:46 +0330
Subject: [PATCH 4/6] Fix: use long array syntax for WPCS compliance
Replaced short array syntax `[]` with `array()` to meet WordPress Coding Standards.
---
tests/phpunit/tests/dependencies/stylesLTRSupport.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/phpunit/tests/dependencies/stylesLTRSupport.php b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
index 43cf0c0e39b6c..8359f56858072 100644
--- a/tests/phpunit/tests/dependencies/stylesLTRSupport.php
+++ b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
@@ -8,7 +8,7 @@ class Tests_Dependencies_StylesLtrSupport extends WP_UnitTestCase {
public function set_up(): void {
parent::set_up();
switch_to_locale( 'fa_IR' ); // RTL language
- wp_styles()->registered = [];
+ wp_styles()->registered = array();
}
public function tear_down(): void {
From 86bd3588466de9f37c5057089b659203189566c7 Mon Sep 17 00:00:00 2001
From: asadister <77143123+asadister@users.noreply.github.com>
Date: Thu, 6 Nov 2025 19:21:35 +0330
Subject: [PATCH 5/6] Implement tests for LTR stylesheet handling
Adds unit tests verifying LTR stylesheet support in wp_register_style() and wp_print_styles().
- Confirms that `wp_style_add_data()` correctly stores 'ltr' data (replace/suffix modes).
- Ensures LTR stylesheets are printed after their main styles in HTML output.
- Covers both RTL and LTR locale cases.
- Marks `print_emoji_styles` as expected deprecated to prevent false failures.
Props asadister.
See [#64193](https://core.trac.wordpress.org/ticket/64193).
---
.../tests/dependencies/stylesLTRSupport.php | 57 ++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/tests/phpunit/tests/dependencies/stylesLTRSupport.php b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
index 8359f56858072..e1c3cc343a12c 100644
--- a/tests/phpunit/tests/dependencies/stylesLTRSupport.php
+++ b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
@@ -1,13 +1,21 @@
registered = array();
}
@@ -16,6 +24,9 @@ public function tear_down(): void {
parent::tear_down();
}
+ /**
+ * @ticket 64193
+ */
public function test_ltr_css_replace_data_is_set() {
$handle = 'sample-style';
wp_register_style( $handle, 'https://example.com/style.css' );
@@ -26,6 +37,9 @@ public function test_ltr_css_replace_data_is_set() {
$this->assertSame( 'replace', $styles->registered[ $handle ]->extra['ltr'] );
}
+ /**
+ * @ticket 64193
+ */
public function test_ltr_css_suffix_data_is_set() {
$handle = 'sample-style-suffix';
wp_register_style( $handle, 'https://example.com/style.min.css' );
@@ -36,6 +50,9 @@ public function test_ltr_css_suffix_data_is_set() {
$this->assertSame( 'suffix', $styles->registered[ $handle ]->extra['ltr'] );
}
+ /**
+ * @ticket 64193
+ */
public function test_no_ltr_data_for_ltr_locale() {
restore_previous_locale();
switch_to_locale( 'en_US' ); // LTR language
@@ -48,4 +65,42 @@ public function test_no_ltr_data_for_ltr_locale() {
$this->assertArrayHasKey( 'ltr', $styles->registered[ $handle ]->extra );
$this->assertSame( 'replace', $styles->registered[ $handle ]->extra['ltr'] );
}
+
+ /**
+ * Verify that an LTR stylesheet is printed after its main stylesheet in the HTML output.
+ *
+ * @group output
+ * @ticket 64193
+ * @expectedDeprecated print_emoji_styles
+ */
+ public function test_ltr_stylesheet_is_printed_in_output() {
+ global $wp_styles;
+
+ // Reset styles registry to ensure a clean environment.
+ $wp_styles = null;
+ wp_styles();
+
+ // Register main style.
+ wp_register_style( 'ltr-test-style', 'http://example.com/css/style.css', array(), '1.0' );
+
+ // Mark this style as having an LTR variant.
+ wp_style_add_data( 'ltr-test-style', 'ltr', true );
+
+ // Enqueue the style.
+ wp_enqueue_style( 'ltr-test-style' );
+
+ // Capture printed output.
+ ob_start();
+ wp_print_styles();
+ $output = ob_get_clean();
+
+ // Assertions.
+ $this->assertStringContainsString( 'style.css', $output, 'Main stylesheet was not printed in output.' );
+ $this->assertStringContainsString( 'ltr.css', $output, 'LTR stylesheet was not printed in output.' );
+
+ // Verify correct order (LTR after main style).
+ $mainPos = strpos( $output, 'style.css' );
+ $ltrPos = strpos( $output, 'ltr.css' );
+ $this->assertTrue( $ltrPos > $mainPos, 'LTR stylesheet should appear after the main style.' );
+ }
}
From 3155a4361e51bcbfde427101d31e72fa4ea214e0 Mon Sep 17 00:00:00 2001
From: asadister <77143123+asadister@users.noreply.github.com>
Date: Thu, 6 Nov 2025 19:33:44 +0330
Subject: [PATCH 6/6] Add tests for LTR stylesheet handling in
wp_register_style() and wp_print_styles().
Implements comprehensive PHPUnit tests for verifying LTR stylesheet support.
These tests cover:
- Proper registration of LTR data using `wp_style_add_data()`.
- Behavior differences between LTR and RTL locales.
- Ensuring that LTR variants are correctly printed in HTML output via `wp_print_styles()`.
- Verification of stylesheet order to confirm that the LTR stylesheet appears after its main counterpart.
Includes handling for the deprecation of `print_emoji_styles` to ensure compatibility with WordPress 6.4+.
Props asadister.
See [#64193](https://core.trac.wordpress.org/ticket/64193).
---
.../tests/dependencies/stylesLTRSupport.php | 24 +++++++------------
1 file changed, 8 insertions(+), 16 deletions(-)
diff --git a/tests/phpunit/tests/dependencies/stylesLTRSupport.php b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
index e1c3cc343a12c..bbb5e57202e54 100644
--- a/tests/phpunit/tests/dependencies/stylesLTRSupport.php
+++ b/tests/phpunit/tests/dependencies/stylesLTRSupport.php
@@ -1,21 +1,13 @@
registered = array();
}
@@ -55,7 +47,7 @@ public function test_ltr_css_suffix_data_is_set() {
*/
public function test_no_ltr_data_for_ltr_locale() {
restore_previous_locale();
- switch_to_locale( 'en_US' ); // LTR language
+ switch_to_locale( 'en_US' ); // LTR language.
$handle = 'sample-style-ltr';
wp_register_style( $handle, 'https://example.com/style.css' );
@@ -65,15 +57,15 @@ public function test_no_ltr_data_for_ltr_locale() {
$this->assertArrayHasKey( 'ltr', $styles->registered[ $handle ]->extra );
$this->assertSame( 'replace', $styles->registered[ $handle ]->extra['ltr'] );
}
-
/**
- * Verify that an LTR stylesheet is printed after its main stylesheet in the HTML output.
+ * Verify that an LTR stylesheet actually gets printed in HTML output.
*
* @group output
* @ticket 64193
- * @expectedDeprecated print_emoji_styles
*/
public function test_ltr_stylesheet_is_printed_in_output() {
+ $this->setExpectedDeprecated( 'print_emoji_styles' );
+
global $wp_styles;
// Reset styles registry to ensure a clean environment.
@@ -99,8 +91,8 @@ public function test_ltr_stylesheet_is_printed_in_output() {
$this->assertStringContainsString( 'ltr.css', $output, 'LTR stylesheet was not printed in output.' );
// Verify correct order (LTR after main style).
- $mainPos = strpos( $output, 'style.css' );
- $ltrPos = strpos( $output, 'ltr.css' );
- $this->assertTrue( $ltrPos > $mainPos, 'LTR stylesheet should appear after the main style.' );
+ $main_pos = strpos( $output, 'style.css' );
+ $ltr_pos = strpos( $output, 'ltr.css' );
+ $this->assertTrue( $ltr_pos > $main_pos, 'LTR stylesheet should appear after the main style.' );
}
}