From 5724b49a972aeadfc31a9394142cc330512c94c0 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 9 Sep 2024 14:39:22 -0400 Subject: [PATCH 01/19] WIP working to convert attributes and URLs. --- includes/create-theme/theme-locale.php | 31 +++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 783d8715..5dba1ccb 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -28,7 +28,36 @@ private static function escape_text_content( $string ) { $string = addcslashes( $string, "'" ); - return "get( 'TextDomain' ) . "');?>"; + $p = new WP_HTML_Tag_Processor( $string ); + + $text = ''; + $tokens = array(); + while ( $p->next_token() ) { + switch ( $p->get_token_type() ) { + case '#tag': + if ( $p->is_tag_closer() ) { + $text .= 'get_token_name() ) . '>'; + } else { + switch ( $p->get_token_name() ) { + case 'A': + $text .= 'get_attribute( 'href' ) . '" );?>">'; + break; + case 'IMG': + $text .= 'get_attribute( 'style' ) . '" )?>" src="' . CBT_Theme_Media::make_relative_media_url( $p->get_attribute( 'src' ) ) . '" alt="get_attribute( 'alt' ) . '" );?>">'; + break; + default: + $text .= '<' . strtolower( $p->get_token_name() ) . '>'; + break; + } + } + break; + case '#text': + $text .= 'get_modifiable_text() . '", wp_get_theme()->get( \'TextDomain\' ) ); ?>'; + break; + } + } + + return $text; } /** From 723a88feebe69a7820e1abb97c7259e0fd6855cd Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 9 Sep 2024 14:45:17 -0400 Subject: [PATCH 02/19] Ensure media is added to local. --- includes/create-theme/theme-locale.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 5dba1ccb..0f8ab56c 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -43,6 +43,7 @@ private static function escape_text_content( $string ) { $text .= 'get_attribute( 'href' ) . '" );?>">'; break; case 'IMG': + CBT_Theme_Media::add_media_to_local( array( $p->get_attribute( 'src' ) ) ); $text .= 'get_attribute( 'style' ) . '" )?>" src="' . CBT_Theme_Media::make_relative_media_url( $p->get_attribute( 'src' ) ) . '" alt="get_attribute( 'alt' ) . '" );?>">'; break; default: From a9ca35aa88728d5b1ca40dd7d5725d7c2d10840c Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Tue, 10 Sep 2024 16:57:48 -0400 Subject: [PATCH 03/19] Use a list of tokens and sprintf to generate the formatted string. --- includes/create-theme/theme-locale.php | 78 ++++++++++++++++++-------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 0f8ab56c..64ed8077 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -28,37 +28,71 @@ private static function escape_text_content( $string ) { $string = addcslashes( $string, "'" ); + // Process the string to avoid escaping inner HTML markup. $p = new WP_HTML_Tag_Processor( $string ); $text = ''; $tokens = array(); while ( $p->next_token() ) { - switch ( $p->get_token_type() ) { - case '#tag': - if ( $p->is_tag_closer() ) { - $text .= 'get_token_name() ) . '>'; - } else { - switch ( $p->get_token_name() ) { - case 'A': - $text .= 'get_attribute( 'href' ) . '" );?>">'; - break; - case 'IMG': - CBT_Theme_Media::add_media_to_local( array( $p->get_attribute( 'src' ) ) ); - $text .= 'get_attribute( 'style' ) . '" )?>" src="' . CBT_Theme_Media::make_relative_media_url( $p->get_attribute( 'src' ) ) . '" alt="get_attribute( 'alt' ) . '" );?>">'; - break; - default: - $text .= '<' . strtolower( $p->get_token_name() ) . '>'; - break; - } + $token_type = $p->get_token_type(); + $token_name = strtolower( $p->get_token_name() ); + $is_tag_closer = $p->is_tag_closer(); + + if ( '#tag' === $token_type ) { + // Add a placeholder for the token. + $text .= '%s'; + if ( $is_tag_closer ) { + $tokens[] = ""; + } else { + // Depending on the HTML tag, we may need to process attributes so they are correctly added to the placeholder. + switch ( $token_name ) { + // Handle links. + case 'a': + $href = esc_url( $p->get_attribute( 'href' ) ); + $target = empty( esc_attr( $p->get_attribute( 'target' ) ) ) ? '' : ' target="_blank"'; + $rel = empty( esc_attr( $p->get_attribute( 'rel' ) ) ) ? '' : ' rel="nofollow noopener noreferrer"'; + $tokens[] = ""; + break; + // Handle inline images. + case 'img': + $src = esc_url( $p->get_attribute( 'src' ) ); + $style = esc_attr( $p->get_attribute( 'style' ) ); + $alt = esc_attr( $p->get_attribute( 'alt' ) ); + + CBT_Theme_Media::add_media_to_local( array( $src ) ); + $relative_src = CBT_Theme_Media::get_media_folder_path_from_url( $src ) . basename( $src ); + $tokens[] = "\"{$alt}\""; + break; + // Handle highlights. + case 'mark': + $style = esc_attr( $p->get_attribute( 'style' ) ); + $class = esc_attr( $p->get_attribute( 'class' ) ); + $tokens[] = ""; + break; + // Otherwise, just add the tag opener. + default: + $tokens[] = "<{$token_name}>"; + break; } - break; - case '#text': - $text .= 'get_modifiable_text() . '", wp_get_theme()->get( \'TextDomain\' ) ); ?>'; - break; + } + } else { + // If it's not a tag, just add the text content. + $text .= esc_html( $p->get_modifiable_text() ); } } - return $text; + // Format the string, replacing the placeholders with the formatted tokens. + $mystring = "get( 'TextDomain' ) . "' ), " . implode( + ', ', + array_map( + function( $token ) { + return "'$token'"; + }, + $tokens + ) + ) . '); ?>'; + + return $mystring; } /** From 0460dc52fa709a1f263a9f535beb24fc2dfadf57 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Tue, 10 Sep 2024 17:49:43 -0400 Subject: [PATCH 04/19] Only format the string if tokens are present. --- includes/create-theme/theme-locale.php | 27 ++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 64ed8077..c50ffc43 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -80,19 +80,22 @@ private static function escape_text_content( $string ) { $text .= esc_html( $p->get_modifiable_text() ); } } + // If tokens is not empty, format the string using sprintf. + if ( ! empty( $tokens ) ) { + // Format the string, replacing the placeholders with the formatted tokens. + return "get( 'TextDomain' ) . "' ), " . implode( + ', ', + array_map( + function( $token ) { + return "'$token'"; + }, + $tokens + ) + ) . '); ?>'; + } + + return "get( 'TextDomain' ) . "');?>"; - // Format the string, replacing the placeholders with the formatted tokens. - $mystring = "get( 'TextDomain' ) . "' ), " . implode( - ', ', - array_map( - function( $token ) { - return "'$token'"; - }, - $tokens - ) - ) . '); ?>'; - - return $mystring; } /** From 194764cd45788b1739f0e1c1e2bf15ccfe23dfe6 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Tue, 10 Sep 2024 17:51:56 -0400 Subject: [PATCH 05/19] Update content with html test. Update remaining tests with inner markup. Try and fix tests. Format tests. --- includes/create-theme/theme-locale.php | 4 ++-- tests/CbtThemeLocale/escapeTextContent.php | 7 ++++--- .../CbtThemeLocale/escapeTextContentOfBlocks.php | 2 +- tests/test-theme-templates.php | 15 ++++++++++----- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index c50ffc43..ab7ed778 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -83,7 +83,7 @@ private static function escape_text_content( $string ) { // If tokens is not empty, format the string using sprintf. if ( ! empty( $tokens ) ) { // Format the string, replacing the placeholders with the formatted tokens. - return "get( 'TextDomain' ) . "' ), " . implode( + return "get( 'TextDomain' ) . "' ), " . implode( ', ', array_map( function( $token ) { @@ -91,7 +91,7 @@ function( $token ) { }, $tokens ) - ) . '); ?>'; + ) . ' ); ?>'; } return "get( 'TextDomain' ) . "');?>"; diff --git a/tests/CbtThemeLocale/escapeTextContent.php b/tests/CbtThemeLocale/escapeTextContent.php index 32609243..d3d0e4c4 100644 --- a/tests/CbtThemeLocale/escapeTextContent.php +++ b/tests/CbtThemeLocale/escapeTextContent.php @@ -37,9 +37,10 @@ public function test_escape_text_content_with_double_quote() { } public function test_escape_text_content_with_html() { - $string = '

This is a test text with HTML.

'; - $escaped_string = $this->call_private_method( 'escape_text_content', array( $string ) ); - $this->assertEquals( "This is a test text with HTML.

', 'test-locale-theme');?>", $escaped_string ); + $string = '

This is a test text with HTML.

'; + $escaped_string = $this->call_private_method( 'escape_text_content', array( $string ) ); + $expected_output = "', '

' ); ?>"; + $this->assertEquals( $expected_output, $escaped_string ); } public function test_escape_text_content_with_already_escaped_string() { diff --git a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php index 2fee4adf..34d705c6 100644 --- a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php +++ b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php @@ -108,7 +108,7 @@ public function data_test_escape_text_content_of_blocks() { ', 'expected_markup' => ' -
El polvo elemental que nos ignora
y que fue el rojo Adán y que es ahora
todos los hombres, y que no veremos.\', \'test-locale-theme\');?>
+
\', \'
\', \'
\' ); ?>
', ), diff --git a/tests/test-theme-templates.php b/tests/test-theme-templates.php index e2842800..f3aec6e6 100644 --- a/tests/test-theme-templates.php +++ b/tests/test-theme-templates.php @@ -159,12 +159,12 @@ public function test_properly_encode_lessthan_and_greaterthan() { public function test_properly_encode_html_markup() { $template = new stdClass(); - $template->content = ' -

Bold text has feelings <> TOO

- '; + $template->content = '

Bold text has feelings <> TOO

'; $escaped_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $this->assertStringContainsString( "Bold text has feelings <> TOO', '');?>", $escaped_template->content ); + $expected_output = '

\', \'\' ); ?>

'; + + $this->assertStringContainsString( $expected_output, $escaped_template->content ); } public function test_empty_alt_text_is_not_localized() { @@ -262,7 +262,12 @@ public function test_localize_verse() {
Here is some verse to localize
'; $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $this->assertStringContainsString( "verse to localize', '');?>", $new_template->content ); + + $expected_output = ' +
\', \'\' ); ?>
+ '; + + $this->assertStringContainsString( $expected_output, $new_template->content ); } public function test_localize_table() { From 45c312c5cb42d0fc694d845e4a874e8a920d317d Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Wed, 11 Sep 2024 15:10:32 -0400 Subject: [PATCH 06/19] Remove whitespace. --- includes/create-theme/theme-locale.php | 1 - 1 file changed, 1 deletion(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index ab7ed778..0ac8aa29 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -95,7 +95,6 @@ function( $token ) { } return "get( 'TextDomain' ) . "');?>"; - } /** From 678a8ef22ddecc2e0b4190dd141cfa0c4436cd1e Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Fri, 13 Sep 2024 13:01:12 -0400 Subject: [PATCH 07/19] Process all attributes Escape at the end. Provide better translation note. --- includes/create-theme/theme-locale.php | 76 +++++++++++++------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 0ac8aa29..af4becf8 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -31,59 +31,57 @@ private static function escape_text_content( $string ) { // Process the string to avoid escaping inner HTML markup. $p = new WP_HTML_Tag_Processor( $string ); - $text = ''; - $tokens = array(); + $text = ''; + $tokens = array(); + $increment = 0; + $translators_note = "\n/* Translators: "; while ( $p->next_token() ) { $token_type = $p->get_token_type(); $token_name = strtolower( $p->get_token_name() ); $is_tag_closer = $p->is_tag_closer(); if ( '#tag' === $token_type ) { - // Add a placeholder for the token. - $text .= '%s'; + $increment++; + $text .= '%' . $increment . '$s'; + if ( 1 !== $increment ) { + $translators_note .= ', '; + } if ( $is_tag_closer ) { - $tokens[] = ""; + $tokens[] = ""; + $translators_note .= '%' . $increment . "\$s is the end of a '" . $token_name . "' HTML element"; } else { - // Depending on the HTML tag, we may need to process attributes so they are correctly added to the placeholder. - switch ( $token_name ) { - // Handle links. - case 'a': - $href = esc_url( $p->get_attribute( 'href' ) ); - $target = empty( esc_attr( $p->get_attribute( 'target' ) ) ) ? '' : ' target="_blank"'; - $rel = empty( esc_attr( $p->get_attribute( 'rel' ) ) ) ? '' : ' rel="nofollow noopener noreferrer"'; - $tokens[] = "
"; - break; - // Handle inline images. - case 'img': - $src = esc_url( $p->get_attribute( 'src' ) ); - $style = esc_attr( $p->get_attribute( 'style' ) ); - $alt = esc_attr( $p->get_attribute( 'alt' ) ); - - CBT_Theme_Media::add_media_to_local( array( $src ) ); - $relative_src = CBT_Theme_Media::get_media_folder_path_from_url( $src ) . basename( $src ); - $tokens[] = "\"{$alt}\""; - break; - // Handle highlights. - case 'mark': - $style = esc_attr( $p->get_attribute( 'style' ) ); - $class = esc_attr( $p->get_attribute( 'class' ) ); - $tokens[] = ""; - break; - // Otherwise, just add the tag opener. - default: - $tokens[] = "<{$token_name}>"; - break; + $token = '<' . $token_name; + // Get all attributes of the tag. + $attributes = $p->get_attribute_names_with_prefix( '' ); + + // Add the attributes to the token, processing and escaping where necessary. + foreach ( $attributes as $attr_name ) { + $attr_value = $p->get_attribute( $attr_name ); + if ( empty( $attr_value ) ) { + $token .= ' ' . $attr_name; + continue; + } elseif ( 'src' === $attr_name ) { + CBT_Theme_Media::add_media_to_local( array( $attr_value ) ); + $relative_src = CBT_Theme_Media::get_media_folder_path_from_url( $attr_value ) . basename( $attr_value ); + $attr_value = "' . esc_url( get_stylesheet_directory_uri() ) . '{$relative_src}"; + } elseif ( 'href' === $attr_name ) { + $attr_value = "' . esc_url( '$attr_value' ) . '"; + } + $token .= ' ' . $attr_name . '="' . $attr_value . '"'; } + $token .= '>'; + $tokens[] = $token; + $translators_note .= '%' . $increment . "\$s is the start of a '" . $token_name . "' HTML element"; } } else { - // If it's not a tag, just add the text content. - $text .= esc_html( $p->get_modifiable_text() ); + $text .= $p->get_modifiable_text(); } } - // If tokens is not empty, format the string using sprintf. + if ( ! empty( $tokens ) ) { - // Format the string, replacing the placeholders with the formatted tokens. - return "get( 'TextDomain' ) . "' ), " . implode( + $translators_note .= ". */\n"; + // Return the formatted text, substituting the placeholders with the tokens. + return "get( 'TextDomain' ) . "' ), " . implode( ', ', array_map( function( $token ) { From bf8ff55e9629f9bf31317bf18e806f5d086b61ef Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Fri, 13 Sep 2024 14:46:35 -0400 Subject: [PATCH 08/19] Refactor token processing to its own class. --- includes/create-theme/theme-locale.php | 59 ++------- .../create-theme/theme-token-processor.php | 120 ++++++++++++++++++ 2 files changed, 128 insertions(+), 51 deletions(-) create mode 100644 includes/create-theme/theme-token-processor.php diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index af4becf8..31435f1f 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -2,6 +2,9 @@ /* * Locale related functionality */ + +require_once __DIR__ . '/theme-token-processor.php'; + class CBT_Theme_Locale { /** @@ -28,59 +31,13 @@ private static function escape_text_content( $string ) { $string = addcslashes( $string, "'" ); - // Process the string to avoid escaping inner HTML markup. - $p = new WP_HTML_Tag_Processor( $string ); - - $text = ''; - $tokens = array(); - $increment = 0; - $translators_note = "\n/* Translators: "; - while ( $p->next_token() ) { - $token_type = $p->get_token_type(); - $token_name = strtolower( $p->get_token_name() ); - $is_tag_closer = $p->is_tag_closer(); - - if ( '#tag' === $token_type ) { - $increment++; - $text .= '%' . $increment . '$s'; - if ( 1 !== $increment ) { - $translators_note .= ', '; - } - if ( $is_tag_closer ) { - $tokens[] = ""; - $translators_note .= '%' . $increment . "\$s is the end of a '" . $token_name . "' HTML element"; - } else { - $token = '<' . $token_name; - // Get all attributes of the tag. - $attributes = $p->get_attribute_names_with_prefix( '' ); - - // Add the attributes to the token, processing and escaping where necessary. - foreach ( $attributes as $attr_name ) { - $attr_value = $p->get_attribute( $attr_name ); - if ( empty( $attr_value ) ) { - $token .= ' ' . $attr_name; - continue; - } elseif ( 'src' === $attr_name ) { - CBT_Theme_Media::add_media_to_local( array( $attr_value ) ); - $relative_src = CBT_Theme_Media::get_media_folder_path_from_url( $attr_value ) . basename( $attr_value ); - $attr_value = "' . esc_url( get_stylesheet_directory_uri() ) . '{$relative_src}"; - } elseif ( 'href' === $attr_name ) { - $attr_value = "' . esc_url( '$attr_value' ) . '"; - } - $token .= ' ' . $attr_name . '="' . $attr_value . '"'; - } - $token .= '>'; - $tokens[] = $token; - $translators_note .= '%' . $increment . "\$s is the start of a '" . $token_name . "' HTML element"; - } - } else { - $text .= $p->get_modifiable_text(); - } - } + $p = new CBT_Token_Processor( $string ); + $p->process_tokens(); + $text = $p->get_text(); + $tokens = $p->get_tokens(); + $translators_note = $p->get_translators_note(); if ( ! empty( $tokens ) ) { - $translators_note .= ". */\n"; - // Return the formatted text, substituting the placeholders with the tokens. return "get( 'TextDomain' ) . "' ), " . implode( ', ', array_map( diff --git a/includes/create-theme/theme-token-processor.php b/includes/create-theme/theme-token-processor.php new file mode 100644 index 00000000..679239cc --- /dev/null +++ b/includes/create-theme/theme-token-processor.php @@ -0,0 +1,120 @@ +p = new WP_HTML_Tag_Processor( $string ); + } + + /** + * Processes the HTML tags in the string and updates tokens, text, and translators' note. + * + * @param $p The string to process. + * @return void + */ + public function process_tokens() { + while ( $this->p->next_token() ) { + $token_type = $this->p->get_token_type(); + $token_name = strtolower( $this->p->get_token_name() ); + $is_tag_closer = $this->p->is_tag_closer(); + + if ( '#tag' === $token_type ) { + $this->increment++; + $this->text .= '%' . $this->increment . '$s'; + + if ( 1 !== $this->increment ) { + $this->translators_note .= ', '; + } + + if ( $is_tag_closer ) { + $this->tokens[] = ""; + $this->translators_note .= '%' . $this->increment . "\$s is the end of a '" . $token_name . "' HTML element"; + } else { + $token = '<' . $token_name; + $attributes = $this->p->get_attribute_names_with_prefix( '' ); + + foreach ( $attributes as $attr_name ) { + $attr_value = $this->p->get_attribute( $attr_name ); + $token .= $this->process_attribute( $attr_name, $attr_value ); + } + + $token .= '>'; + $this->tokens[] = $token; + $this->translators_note .= '%' . $this->increment . "\$s is the start of a '" . $token_name . "' HTML element"; + } + } else { + // Escape text content + $this->text .= esc_html( $this->p->get_modifiable_text() ); + } + } + + if ( ! empty( $this->tokens ) ) { + $this->translators_note .= ' */ '; + } + } + + /** + * Processes individual tag attributes and escapes where necessary. + * + * @param string $attr_name The name of the attribute. + * @param string $attr_value The value of the attribute. + * @return string The processed attribute. + */ + private function process_attribute( $attr_name, $attr_value ) { + $token_part = ''; + if ( empty( $attr_value ) ) { + $token_part .= ' ' . $attr_name; + } elseif ( 'src' === $attr_name ) { + CBT_Theme_Media::add_media_to_local( array( $attr_value ) ); + $relative_src = CBT_Theme_Media::get_media_folder_path_from_url( $attr_value ) . basename( $attr_value ); + $attr_value = "' . esc_url( get_stylesheet_directory_uri() ) . '{$relative_src}"; + $token_part .= ' ' . $attr_name . '="' . $attr_value . '"'; + } elseif ( 'href' === $attr_name ) { + $attr_value = "' . esc_url( '$attr_value' ) . '"; + $token_part .= ' ' . $attr_name . '="' . $attr_value . '"'; + } else { + $token_part .= ' ' . $attr_name . '="' . $attr_value . '"'; + } + + return $token_part; + } + + /** + * Gets the processed text. + * + * @return string + */ + public function get_text() { + return $this->text; + } + + /** + * Gets the processed tokens. + * + * @return array + */ + public function get_tokens() { + return $this->tokens; + } + + /** + * Gets the generated translators' note. + * + * @return string + */ + public function get_translators_note() { + return $this->translators_note; + } +} From d55f3224bdd628599013b4ec0644c54813fdd03b Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Fri, 13 Sep 2024 14:57:43 -0400 Subject: [PATCH 09/19] Update tests with string replacements and translation. --- tests/CbtThemeLocale/escapeTextContent.php | 2 +- tests/CbtThemeLocale/escapeTextContentOfBlocks.php | 2 +- tests/test-theme-templates.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/CbtThemeLocale/escapeTextContent.php b/tests/CbtThemeLocale/escapeTextContent.php index d3d0e4c4..be10c7e3 100644 --- a/tests/CbtThemeLocale/escapeTextContent.php +++ b/tests/CbtThemeLocale/escapeTextContent.php @@ -39,7 +39,7 @@ public function test_escape_text_content_with_double_quote() { public function test_escape_text_content_with_html() { $string = '

This is a test text with HTML.

'; $escaped_string = $this->call_private_method( 'escape_text_content', array( $string ) ); - $expected_output = "', '

' ); ?>"; + $expected_output = '\', \'

\' ); ?>'; $this->assertEquals( $expected_output, $escaped_string ); } diff --git a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php index 34d705c6..fe897867 100644 --- a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php +++ b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php @@ -108,7 +108,7 @@ public function data_test_escape_text_content_of_blocks() { ', 'expected_markup' => ' -
\', \'
\', \'
\' ); ?>
+
\', \'
\', \'
\' ); ?>
', ), diff --git a/tests/test-theme-templates.php b/tests/test-theme-templates.php index f3aec6e6..7007f39e 100644 --- a/tests/test-theme-templates.php +++ b/tests/test-theme-templates.php @@ -162,7 +162,7 @@ public function test_properly_encode_html_markup() { $template->content = '

Bold text has feelings <> TOO

'; $escaped_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $expected_output = '

\', \'\' ); ?>

'; + $expected_output = '

\', \'\' ); ?>

'; $this->assertStringContainsString( $expected_output, $escaped_template->content ); } @@ -264,7 +264,7 @@ public function test_localize_verse() { $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); $expected_output = ' -
\', \'\' ); ?>
+
\', \'\' ); ?>
'; $this->assertStringContainsString( $expected_output, $new_template->content ); From 3f0adfac69e3a240e58257b1bbe40d1db8bef9a4 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 23 Sep 2024 13:28:19 -0400 Subject: [PATCH 10/19] Check if % exists in the text and escape it. --- includes/create-theme/theme-token-processor.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/includes/create-theme/theme-token-processor.php b/includes/create-theme/theme-token-processor.php index 679239cc..5795eb0c 100644 --- a/includes/create-theme/theme-token-processor.php +++ b/includes/create-theme/theme-token-processor.php @@ -55,8 +55,15 @@ public function process_tokens() { $this->translators_note .= '%' . $this->increment . "\$s is the start of a '" . $token_name . "' HTML element"; } } else { - // Escape text content - $this->text .= esc_html( $this->p->get_modifiable_text() ); + // Escape text content. + $temp_text = $this->p->get_modifiable_text(); + + // If the text contains a %, we need to escape it. + if ( false !== strpos( $temp_text, '%' ) ) { + $temp_text = str_replace( '%', '%%', $temp_text ); + } + + $this->text .= $temp_text; } } From 4504111b0900b9d377984ab2794a297f94a9659e Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 23 Sep 2024 13:28:46 -0400 Subject: [PATCH 11/19] Add a test case for a localizing text that includes a %. --- tests/test-theme-templates.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test-theme-templates.php b/tests/test-theme-templates.php index 7007f39e..ced18c7b 100644 --- a/tests/test-theme-templates.php +++ b/tests/test-theme-templates.php @@ -162,7 +162,7 @@ public function test_properly_encode_html_markup() { $template->content = '

Bold text has feelings <> TOO

'; $escaped_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $expected_output = '

\', \'\' ); ?>

'; + $expected_output = '

TOO\', \'\' ), \'\', \'\' ); ?>

'; $this->assertStringContainsString( $expected_output, $escaped_template->content ); } @@ -270,6 +270,15 @@ public function test_localize_verse() { $this->assertStringContainsString( $expected_output, $new_template->content ); } + public function test_localize_text_with_placeholders() { + $template = new stdClass(); + $template->content = ' +

This is bold text with a %s placeholder

+ '; + $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); + $this->assertStringContainsString( '\', \'\' ); ?>', $new_template->content ); + } + public function test_localize_table() { $template = new stdClass(); $template->content = ' From 7a75758984c2238c464afcd9bec7942f7b6ce66c Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 13:02:04 +0100 Subject: [PATCH 12/19] Add new line at the end of translators note --- includes/create-theme/theme-token-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/create-theme/theme-token-processor.php b/includes/create-theme/theme-token-processor.php index 5795eb0c..81818879 100644 --- a/includes/create-theme/theme-token-processor.php +++ b/includes/create-theme/theme-token-processor.php @@ -68,7 +68,7 @@ public function process_tokens() { } if ( ! empty( $this->tokens ) ) { - $this->translators_note .= ' */ '; + $this->translators_note .= ' */ ' . "\n"; } } From c6652860bd350295ad7c85a00033936b132308a1 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 13:02:53 +0100 Subject: [PATCH 13/19] Reformat numbers in translators note --- includes/create-theme/theme-token-processor.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/includes/create-theme/theme-token-processor.php b/includes/create-theme/theme-token-processor.php index 81818879..c840af31 100644 --- a/includes/create-theme/theme-token-processor.php +++ b/includes/create-theme/theme-token-processor.php @@ -33,6 +33,7 @@ public function process_tokens() { if ( '#tag' === $token_type ) { $this->increment++; $this->text .= '%' . $this->increment . '$s'; + $token_label = $this->increment . '.'; if ( 1 !== $this->increment ) { $this->translators_note .= ', '; @@ -40,7 +41,7 @@ public function process_tokens() { if ( $is_tag_closer ) { $this->tokens[] = ""; - $this->translators_note .= '%' . $this->increment . "\$s is the end of a '" . $token_name . "' HTML element"; + $this->translators_note .= $token_label . " is the end of a '" . $token_name . "' HTML element"; } else { $token = '<' . $token_name; $attributes = $this->p->get_attribute_names_with_prefix( '' ); @@ -52,7 +53,7 @@ public function process_tokens() { $token .= '>'; $this->tokens[] = $token; - $this->translators_note .= '%' . $this->increment . "\$s is the start of a '" . $token_name . "' HTML element"; + $this->translators_note .= $token_label . " is the start of a '" . $token_name . "' HTML element"; } } else { // Escape text content. From 730565acc1757ce812bd52de05a5232293c51b1d Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 13:03:02 +0100 Subject: [PATCH 14/19] Update test --- tests/CbtThemeLocale/escapeTextContent.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/CbtThemeLocale/escapeTextContent.php b/tests/CbtThemeLocale/escapeTextContent.php index be10c7e3..93368388 100644 --- a/tests/CbtThemeLocale/escapeTextContent.php +++ b/tests/CbtThemeLocale/escapeTextContent.php @@ -39,7 +39,8 @@ public function test_escape_text_content_with_double_quote() { public function test_escape_text_content_with_html() { $string = '

This is a test text with HTML.

'; $escaped_string = $this->call_private_method( 'escape_text_content', array( $string ) ); - $expected_output = '\', \'

\' ); ?>'; + $expected_output = '\', \'

\' ); ?>'; $this->assertEquals( $expected_output, $escaped_string ); } From bf603a97213fea85c913144a41a160db916c9927 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 13:18:45 +0100 Subject: [PATCH 15/19] Move new line to theme-locale --- includes/create-theme/theme-locale.php | 2 +- includes/create-theme/theme-token-processor.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 31435f1f..65e491fd 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -35,7 +35,7 @@ private static function escape_text_content( $string ) { $p->process_tokens(); $text = $p->get_text(); $tokens = $p->get_tokens(); - $translators_note = $p->get_translators_note(); + $translators_note = $p->get_translators_note() . "\n"; if ( ! empty( $tokens ) ) { return "get( 'TextDomain' ) . "' ), " . implode( diff --git a/includes/create-theme/theme-token-processor.php b/includes/create-theme/theme-token-processor.php index c840af31..f491ae1e 100644 --- a/includes/create-theme/theme-token-processor.php +++ b/includes/create-theme/theme-token-processor.php @@ -69,7 +69,7 @@ public function process_tokens() { } if ( ! empty( $this->tokens ) ) { - $this->translators_note .= ' */ ' . "\n"; + $this->translators_note .= ' */ '; } } From 6b5fe21f2372f6918cb0e1f6e825b7721d44cfab Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 14:49:13 +0100 Subject: [PATCH 16/19] Handle self closing tags --- .../create-theme/theme-token-processor.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/includes/create-theme/theme-token-processor.php b/includes/create-theme/theme-token-processor.php index f491ae1e..a2404e41 100644 --- a/includes/create-theme/theme-token-processor.php +++ b/includes/create-theme/theme-token-processor.php @@ -26,9 +26,10 @@ public function __construct( $string ) { */ public function process_tokens() { while ( $this->p->next_token() ) { - $token_type = $this->p->get_token_type(); - $token_name = strtolower( $this->p->get_token_name() ); - $is_tag_closer = $this->p->is_tag_closer(); + $token_type = $this->p->get_token_type(); + $token_name = strtolower( $this->p->get_token_name() ); + $is_tag_closer = $this->p->is_tag_closer(); + $has_self_closer = $this->p->has_self_closing_flag(); if ( '#tag' === $token_type ) { $this->increment++; @@ -51,9 +52,14 @@ public function process_tokens() { $token .= $this->process_attribute( $attr_name, $attr_value ); } - $token .= '>'; - $this->tokens[] = $token; - $this->translators_note .= $token_label . " is the start of a '" . $token_name . "' HTML element"; + $token .= '>'; + $this->tokens[] = $token; + + if ( $has_self_closer || 'br' === $token_name ) { + $this->translators_note .= $token_label . " is a '" . $token_name . "' HTML element"; + } else { + $this->translators_note .= $token_label . " is the start of a '" . $token_name . "' HTML element"; + } } } else { // Escape text content. From 1e317ce80b0ef55f28dccad825264b5410434f9f Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 15:14:10 +0100 Subject: [PATCH 17/19] Refactor how new line is added --- includes/create-theme/theme-locale.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/includes/create-theme/theme-locale.php b/includes/create-theme/theme-locale.php index 65e491fd..7f105022 100644 --- a/includes/create-theme/theme-locale.php +++ b/includes/create-theme/theme-locale.php @@ -35,10 +35,12 @@ private static function escape_text_content( $string ) { $p->process_tokens(); $text = $p->get_text(); $tokens = $p->get_tokens(); - $translators_note = $p->get_translators_note() . "\n"; + $translators_note = $p->get_translators_note(); if ( ! empty( $tokens ) ) { - return "get( 'TextDomain' ) . "' ), " . implode( + $php_tag = 'get( 'TextDomain' ) . "' ), " . implode( ', ', array_map( function( $token ) { @@ -47,6 +49,7 @@ function( $token ) { $tokens ) ) . ' ); ?>'; + return $php_tag; } return "get( 'TextDomain' ) . "');?>"; From 273378e8100b1f7d32fefc009b1af9e98ca54ff2 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 15:21:51 +0100 Subject: [PATCH 18/19] Attempt to fix tests --- tests/CbtThemeLocale/escapeTextContentOfBlocks.php | 3 ++- tests/test-theme-templates.php | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php index fe897867..07f4097c 100644 --- a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php +++ b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php @@ -108,7 +108,8 @@ public function data_test_escape_text_content_of_blocks() { ', 'expected_markup' => ' -
\', \'
\', \'
\' ); ?>
+
\', \'
\', \'
\' ); ?>
', ), diff --git a/tests/test-theme-templates.php b/tests/test-theme-templates.php index ced18c7b..7beb9a1c 100644 --- a/tests/test-theme-templates.php +++ b/tests/test-theme-templates.php @@ -162,7 +162,7 @@ public function test_properly_encode_html_markup() { $template->content = '

Bold text has feelings <> TOO

'; $escaped_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $expected_output = '

TOO\', \'\' ), \'\', \'\' ); ?>

'; + $expected_output = '

TOO\', \'\' ), \'\', \'\' ); ?>

'; $this->assertStringContainsString( $expected_output, $escaped_template->content ); } @@ -264,7 +264,7 @@ public function test_localize_verse() { $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); $expected_output = ' -
\', \'\' ); ?>
+
\', \'\' ); ?>
'; $this->assertStringContainsString( $expected_output, $new_template->content ); @@ -276,7 +276,7 @@ public function test_localize_text_with_placeholders() {

This is bold text with a %s placeholder

'; $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $this->assertStringContainsString( '\', \'\' ); ?>', $new_template->content ); + $this->assertStringContainsString( '\', \'\' ); ?>', $new_template->content ); } public function test_localize_table() { From e3497d3dab581f40f9b02c0bb73fa49c62cd7bd8 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Mon, 21 Oct 2024 16:28:54 +0100 Subject: [PATCH 19/19] Attempt to fix tests again --- tests/CbtThemeLocale/escapeTextContent.php | 3 +-- tests/CbtThemeLocale/escapeTextContentOfBlocks.php | 3 +-- tests/test-theme-templates.php | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/CbtThemeLocale/escapeTextContent.php b/tests/CbtThemeLocale/escapeTextContent.php index 93368388..82e6a08b 100644 --- a/tests/CbtThemeLocale/escapeTextContent.php +++ b/tests/CbtThemeLocale/escapeTextContent.php @@ -39,8 +39,7 @@ public function test_escape_text_content_with_double_quote() { public function test_escape_text_content_with_html() { $string = '

This is a test text with HTML.

'; $escaped_string = $this->call_private_method( 'escape_text_content', array( $string ) ); - $expected_output = '\', \'

\' ); ?>'; + $expected_output = '\', \'

\' ); ?>'; $this->assertEquals( $expected_output, $escaped_string ); } diff --git a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php index 07f4097c..50e85891 100644 --- a/tests/CbtThemeLocale/escapeTextContentOfBlocks.php +++ b/tests/CbtThemeLocale/escapeTextContentOfBlocks.php @@ -108,8 +108,7 @@ public function data_test_escape_text_content_of_blocks() { ', 'expected_markup' => ' -
\', \'
\', \'
\' ); ?>
+
\', \'
\', \'
\' ); ?>
', ), diff --git a/tests/test-theme-templates.php b/tests/test-theme-templates.php index 7beb9a1c..15bdc8f0 100644 --- a/tests/test-theme-templates.php +++ b/tests/test-theme-templates.php @@ -162,7 +162,7 @@ public function test_properly_encode_html_markup() { $template->content = '

Bold text has feelings <> TOO

'; $escaped_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $expected_output = '

TOO\', \'\' ), \'\', \'\' ); ?>

'; + $expected_output = '

TOO\', \'\' ), \'\', \'\' ); ?>

'; $this->assertStringContainsString( $expected_output, $escaped_template->content ); } @@ -264,7 +264,7 @@ public function test_localize_verse() { $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); $expected_output = ' -
\', \'\' ); ?>
+
\', \'\' ); ?>
'; $this->assertStringContainsString( $expected_output, $new_template->content ); @@ -276,7 +276,7 @@ public function test_localize_text_with_placeholders() {

This is bold text with a %s placeholder

'; $new_template = CBT_Theme_Templates::escape_text_in_template( $template ); - $this->assertStringContainsString( '\', \'\' ); ?>', $new_template->content ); + $this->assertStringContainsString( '\', \'\' ); ?>', $new_template->content ); } public function test_localize_table() {