Make WordPress Core

Ticket #39941: 39941.diff

File 39941.diff, 13.5 KB (added by adamsilverstein, 5 years ago)
  • src/wp-includes/functions.php

    diff --git src/wp-includes/functions.php src/wp-includes/functions.php
    index 7b5aeb8948..8ccbba3c39 100644
    function is_php_version_compatible( $required ) { 
    77677767function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
    77687768        return abs( (float) $expected - (float) $actual ) <= $precision;
    77697769}
     7770
     7771/**
     7772 * Sanitizes an attributes array into an attributes string to be placed inside a `<script>` tag.
     7773 *
     7774 * Automatically injects type attribute if needed.
     7775 * Used by {@see wp_get_script_tag()} and {@see wp_get_inline_script_tag()}.
     7776 *
     7777 * @since 5.6.0
     7778 *
     7779 * @param array $attributes Optional. Key-value pairs representing `<script>` tag attributes.
     7780 * @return string String made of sanitized `<script>` tag attributes.
     7781 */
     7782function wp_sanitize_script_attributes( $attributes = array() ) {
     7783        if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
     7784                $attributes['type'] = 'text/javascript';
     7785        }
     7786        /**
     7787         * Filters attributes to be added to a script tag.
     7788         *
     7789         * @since 5.6.0
     7790         *
     7791         * @param array $attributes Key-value pairs representing `<script>` tag attributes.
     7792         *                          Only the attribute name is added to the `<script>` tag for
     7793         *                          entries with a boolean value, and that are true.
     7794         */
     7795        $attributes = apply_filters( 'wp_script_attributes', $attributes );
     7796
     7797        $attributes_string = '';
     7798        // Only the attribute name is added to $attributes_string for entries with a boolean value, and that are true.
     7799        foreach ( $attributes as $attribute_name => $attribute_value ) {
     7800                if ( is_bool( $attribute_value ) ) {
     7801                        if ( $attribute_value ) {
     7802                                if ( ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
     7803                                        $attributes_string .= sprintf( ' %1$s="%1$s"', $attribute_name );
     7804                                } else {
     7805                                        $attributes_string .= ' ' . $attribute_name;
     7806                                }
     7807                        }
     7808                } else {
     7809                        $attributes_string .= sprintf( ' %s="%s"', $attribute_name, esc_attr( $attribute_value ) );
     7810                }
     7811        }
     7812
     7813        return $attributes_string;
     7814}
     7815
     7816/**
     7817 * Formats `<script>` loader tags.
     7818 *
     7819 * It is possible to inject attributes in the `<script>` tag via the `wp_script_attributes` filter.
     7820 * Automatically injects type attribute if needed.
     7821 *
     7822 * @since 5.6.0
     7823 *
     7824 * @param array $attributes Key-value pairs representing `<script>` tag attributes.
     7825 * @return string String containing `<script>` opening and closing tags.
     7826 */
     7827function wp_get_script_tag( $attributes ) {
     7828        return sprintf( "<script%s></script>\n", wp_sanitize_script_attributes( $attributes ) );
     7829}
     7830
     7831/**
     7832 * Prints formatted `<script>` loader tags.
     7833 *
     7834 * It is possible to inject attributes in the `<script>` tag via the `wp_script_attributes` filter.
     7835 * Automatically injects type attribute if needed.
     7836 *
     7837 * @since 5.6.0
     7838 *
     7839 * @param array $attributes Key-value pairs representing `<script>` tag attributes.
     7840 * @return null Null value.
     7841 */
     7842function wp_print_script_tag( $attributes ) {
     7843        echo wp_get_script_tag( $attributes );
     7844}
     7845
     7846/**
     7847 * Wraps inline JavaScript in `<script>` tags.
     7848 *
     7849 * It is possible to inject attributes in the `<script>` tag via the `wp_script_attributes` filter.
     7850 * Automatically injects type attribute if needed.
     7851 *
     7852 * @since 5.6.0
     7853 *
     7854 * @param string $javascript Inline JavaScript code.
     7855 * @param array  $attributes Optional. Key-value pairs representing `<script>` tag attributes.
     7856 * @return string String containing inline JavaScript code wrapped around `<script>` tags.
     7857 */
     7858function wp_get_inline_script_tag( $javascript, $attributes = array() ) {
     7859        $javascript = "\n" . trim( $javascript, "\n\r " ) . "\n";
     7860
     7861        return sprintf( "<script%s>%s</script>\n", wp_sanitize_script_attributes( $attributes ), $javascript );
     7862}
     7863
     7864/**
     7865 * Prints inline JavaScript wrapped in `<script>` tags.
     7866 *
     7867 * It is possible to inject attributes in the `<script>` tag via the `wp_script_attributes` filter.
     7868 * Automatically injects type attribute if needed.
     7869 *
     7870 * @since 5.6.0
     7871 *
     7872 * @param string $javascript Inline JavaScript code.
     7873 * @param array  $attributes Optional. Key-value pairs representing `<script>` tag attributes.
     7874 * @return null Null value.
     7875 */
     7876function wp_print_inline_script_tag( $javascript, $attributes = array() ) {
     7877        echo wp_get_inline_script_tag( $javascript, $attributes );
     7878}
  • new file tests/phpunit/tests/functions/wpInlineScriptTag.php

    diff --git tests/phpunit/tests/functions/wpInlineScriptTag.php tests/phpunit/tests/functions/wpInlineScriptTag.php
    new file mode 100644
    index 0000000000..3cfd9d1af0
    - +  
     1<?php
     2
     3/**
     4 * Test wp_get_inline_script_tag() and wp_print_inline_script_tag().
     5 *
     6 * @group functions.php
     7 */
     8class Tests_Functions_wpInlineScriptTag extends WP_UnitTestCase {
     9
     10        private $event_handler = <<<'JS'
     11document.addEventListener( 'DOMContentLoaded', function () {
     12        document.getElementById( 'elementID' )
     13                        .addEventListener( 'click', function( event ) {
     14                                event.preventDefault();
     15                        });
     16});
     17JS;
     18
     19        function get_inline_script_tag_type_set() {
     20                add_theme_support( 'html5', array( 'script' ) );
     21
     22                $this->assertSame(
     23                        '<script type="application/javascript" nomodule>' . "\n{$this->event_handler}\n</script>\n",
     24                        wp_get_inline_script_tag(
     25                                $this->event_handler,
     26                                array(
     27                                        'type'     => 'application/javascript',
     28                                        'async'    => false,
     29                                        'nomodule' => true,
     30                                )
     31                        )
     32                );
     33
     34                remove_theme_support( 'html5' );
     35
     36                $this->assertSame(
     37                        '<script type="application/javascript" nomodule>' . "\n{$this->event_handler}\n</script>\n",
     38                        wp_get_inline_script_tag(
     39                                $this->event_handler,
     40                                array(
     41                                        'type'     => 'application/javascript',
     42                                        'async'    => false,
     43                                        'nomodule' => true,
     44                                )
     45                        )
     46                );
     47        }
     48
     49        function test_get_inline_script_tag_type_not_set() {
     50                add_theme_support( 'html5', array( 'script' ) );
     51
     52                $this->assertSame(
     53                        "<script nomodule>\n{$this->event_handler}\n</script>\n",
     54                        wp_get_inline_script_tag(
     55                                $this->event_handler,
     56                                array(
     57                                        'async'    => false,
     58                                        'nomodule' => true,
     59                                )
     60                        )
     61                );
     62
     63                remove_theme_support( 'html5' );
     64        }
     65
     66        function test_get_inline_script_tag_unescaped_src() {
     67                add_theme_support( 'html5', array( 'script' ) );
     68
     69                $this->assertSame(
     70                        "<script>\n{$this->event_handler}\n</script>\n",
     71                        wp_get_inline_script_tag( $this->event_handler )
     72                );
     73
     74                remove_theme_support( 'html5' );
     75        }
     76
     77        function test_print_script_tag_prints_get_inline_script_tag() {
     78                add_filter(
     79                        'wp_script_attributes',
     80                        function ( $attributes ) {
     81                                if ( isset( $attributes['id'] ) && 'utils-js-extra' === $attributes['id'] ) {
     82                                        $attributes['async'] = true;
     83                                }
     84                                return $attributes;
     85                        }
     86                );
     87
     88                add_theme_support( 'html5', array( 'script' ) );
     89
     90                $attributes = array(
     91                        'id'       => 'utils-js-before',
     92                        'nomodule' => true,
     93                );
     94
     95                $this->assertSame(
     96                        wp_get_inline_script_tag( $this->event_handler, $attributes ),
     97                        get_echo(
     98                                'wp_print_inline_script_tag',
     99                                array(
     100                                        $this->event_handler,
     101                                        $attributes,
     102                                )
     103                        )
     104                );
     105
     106                remove_theme_support( 'html5' );
     107
     108                $this->assertSame(
     109                        wp_get_inline_script_tag( $this->event_handler, $attributes ),
     110                        get_echo(
     111                                'wp_print_inline_script_tag',
     112                                array(
     113                                        $this->event_handler,
     114                                        $attributes,
     115                                )
     116                        )
     117                );
     118        }
     119}
  • new file tests/phpunit/tests/functions/wpSanitizeScriptAttributes.php

    diff --git tests/phpunit/tests/functions/wpSanitizeScriptAttributes.php tests/phpunit/tests/functions/wpSanitizeScriptAttributes.php
    new file mode 100644
    index 0000000000..d6048f15b9
    - +  
     1<?php
     2
     3/**
     4 * Test wp_sanitize_script_attributes().
     5 *
     6 * @group functions.php
     7 */
     8class Tests_Functions_wpSanitizeScriptAttributes extends WP_UnitTestCase {
     9
     10        function test_sanitize_script_attributes_type_set() {
     11                add_theme_support( 'html5', array( 'script' ) );
     12
     13                $this->assertSame(
     14                        ' type="application/javascript" src="https://DOMAIN.TLD/PATH/FILE.js" nomodule',
     15                        wp_sanitize_script_attributes(
     16                                array(
     17                                        'type'     => 'application/javascript',
     18                                        'src'      => 'https://DOMAIN.TLD/PATH/FILE.js',
     19                                        'async'    => false,
     20                                        'nomodule' => true,
     21                                )
     22                        )
     23                );
     24
     25                remove_theme_support( 'html5' );
     26
     27                $this->assertSame(
     28                        ' src="https://DOMAIN.TLD/PATH/FILE.js" type="application/javascript" nomodule="nomodule"',
     29                        wp_sanitize_script_attributes(
     30                                array(
     31                                        'src'      => 'https://DOMAIN.TLD/PATH/FILE.js',
     32                                        'type'     => 'application/javascript',
     33                                        'async'    => false,
     34                                        'nomodule' => true,
     35                                )
     36                        )
     37                );
     38        }
     39
     40        function test_sanitize_script_attributes_type_not_set() {
     41                add_theme_support( 'html5', array( 'script' ) );
     42
     43                $this->assertSame(
     44                        ' src="https://DOMAIN.TLD/PATH/FILE.js" nomodule',
     45                        wp_sanitize_script_attributes(
     46                                array(
     47                                        'src'      => 'https://DOMAIN.TLD/PATH/FILE.js',
     48                                        'async'    => false,
     49                                        'nomodule' => true,
     50                                )
     51                        )
     52                );
     53
     54                remove_theme_support( 'html5' );
     55
     56                $this->assertSame(
     57                        ' src="https://DOMAIN.TLD/PATH/FILE.js" nomodule="nomodule" type="text/javascript"',
     58                        wp_sanitize_script_attributes(
     59                                array(
     60                                        'src'      => 'https://DOMAIN.TLD/PATH/FILE.js',
     61                                        'async'    => false,
     62                                        'nomodule' => true,
     63                                )
     64                        )
     65                );
     66        }
     67
     68
     69        function test_sanitize_script_attributes_no_attributes() {
     70                add_theme_support( 'html5', array( 'script' ) );
     71
     72                $this->assertSame(
     73                        '',
     74                        wp_sanitize_script_attributes()
     75                );
     76
     77                remove_theme_support( 'html5' );
     78        }
     79
     80        function test_sanitize_script_attributes_relative_src() {
     81                add_theme_support( 'html5', array( 'script' ) );
     82
     83                $this->assertSame(
     84                        ' src="PATH/FILE.js" nomodule',
     85                        wp_sanitize_script_attributes(
     86                                array(
     87                                        'src'      => 'PATH/FILE.js',
     88                                        'async'    => false,
     89                                        'nomodule' => true,
     90                                )
     91                        )
     92                );
     93
     94                remove_theme_support( 'html5' );
     95        }
     96
     97
     98        function test_sanitize_script_attributes_only_false_boolean_attributes() {
     99                add_theme_support( 'html5', array( 'script' ) );
     100
     101                $this->assertSame(
     102                        '',
     103                        wp_sanitize_script_attributes(
     104                                array(
     105                                        'async'    => false,
     106                                        'nomodule' => false,
     107                                )
     108                        )
     109                );
     110
     111                remove_theme_support( 'html5' );
     112        }
     113
     114        function test_sanitize_script_attributes_only_true_boolean_attributes() {
     115                add_theme_support( 'html5', array( 'script' ) );
     116
     117                $this->assertSame(
     118                        ' async nomodule',
     119                        wp_sanitize_script_attributes(
     120                                array(
     121                                        'async'    => true,
     122                                        'nomodule' => true,
     123                                )
     124                        )
     125                );
     126
     127                remove_theme_support( 'html5' );
     128        }
     129
     130        function test_sanitize_script_attributes_wp_script_attributes_filter() {
     131                add_theme_support( 'html5', array( 'script' ) );
     132
     133                add_filter(
     134                        'wp_script_attributes',
     135                        function( $attributes ) {
     136                                if ( isset( $attributes['id'] ) && 'utils-js-extra' === $attributes['id'] ) {
     137                                        $attributes['async'] = true;
     138                                }
     139                                return $attributes;
     140                        }
     141                );
     142
     143                $this->assertSame(
     144                        ' src="https://DOMAIN.TLD/PATH/FILE.js" id="utils-js-extra" async nomodule',
     145                        wp_sanitize_script_attributes(
     146                                array(
     147                                        'src'      => 'https://DOMAIN.TLD/PATH/FILE.js',
     148                                        'id'       => 'utils-js-extra',
     149                                        'async'    => false,
     150                                        'nomodule' => true,
     151                                )
     152                        )
     153                );
     154
     155                remove_theme_support( 'html5' );
     156        }
     157}
  • new file tests/phpunit/tests/functions/wpScriptTag.php

    diff --git tests/phpunit/tests/functions/wpScriptTag.php tests/phpunit/tests/functions/wpScriptTag.php
    new file mode 100644
    index 0000000000..3c451f5359
    - +  
     1<?php
     2
     3/**
     4 * Test wp_get_script_tag() and wp_print_script_tag().
     5 *
     6 * @group functions.php
     7 */
     8class Tests_Functions_wpScriptTag extends WP_UnitTestCase {
     9
     10        function get_script_tag_type_set() {
     11                add_theme_support( 'html5', array( 'script' ) );
     12
     13                $this->assertSame(
     14                        '<script src="https://localhost/PATH/FILE.js" type="application/javascript" nomodule></script>' . "\n",
     15                        wp_get_script_tag(
     16                                array(
     17                                        'type'     => 'application/javascript',
     18                                        'src'      => 'https://localhost/PATH/FILE.js',
     19                                        'async'    => false,
     20                                        'nomodule' => true,
     21                                )
     22                        )
     23                );
     24
     25                remove_theme_support( 'html5' );
     26
     27                $this->assertSame(
     28                        '<script src="https://localhost/PATH/FILE.js" type="application/javascript" nomodule></script>' . "\n",
     29                        wp_get_script_tag(
     30                                array(
     31                                        'src'      => 'https://localhost/PATH/FILE.js',
     32                                        'type'     => 'application/javascript',
     33                                        'async'    => false,
     34                                        'nomodule' => true,
     35                                )
     36                        )
     37                );
     38        }
     39
     40        function test_get_script_tag_type_not_set() {
     41                add_theme_support( 'html5', array( 'script' ) );
     42
     43                $this->assertSame(
     44                        '<script src="https://localhost/PATH/FILE.js" nomodule></script>' . "\n",
     45                        wp_get_script_tag(
     46                                array(
     47                                        'src'      => 'https://localhost/PATH/FILE.js',
     48                                        'async'    => false,
     49                                        'nomodule' => true,
     50                                )
     51                        )
     52                );
     53
     54                remove_theme_support( 'html5' );
     55        }
     56
     57        function test_print_script_tag_prints_get_script_tag() {
     58                add_filter(
     59                        'wp_script_attributes',
     60                        function ( $attributes ) {
     61                                if ( isset( $attributes['id'] ) && 'utils-js-extra' === $attributes['id'] ) {
     62                                        $attributes['async'] = true;
     63                                }
     64                                return $attributes;
     65                        }
     66                );
     67
     68                add_theme_support( 'html5', array( 'script' ) );
     69
     70                $attributes = array(
     71                        'src'      => 'https://localhost/PATH/FILE.js',
     72                        'id'       => 'utils-js-extra',
     73                        'nomodule' => true,
     74                );
     75
     76                $this->assertSame(
     77                        wp_get_script_tag( $attributes ),
     78                        get_echo(
     79                                'wp_print_script_tag',
     80                                array( $attributes )
     81                        )
     82                );
     83
     84                remove_theme_support( 'html5' );
     85
     86                $this->assertSame(
     87                        wp_get_script_tag( $attributes ),
     88                        get_echo(
     89                                'wp_print_script_tag',
     90                                array( $attributes )
     91                        )
     92                );
     93        }
     94}