Make WordPress Core

Changeset 57657


Ignore:
Timestamp:
02/20/2024 07:09:43 AM (9 months ago)
Author:
youknowriad
Message:

Editor: Format and sanitize font family names according the CSS spec.

This fixes two bugs in the font library.

  • Fonts using special characters were not being rendered properly in the frontend.
  • Allows the ability to use generic() in font family names.

Props mmaattiiaass, nithins53, kafleg, vivekawsm, swissspidy, audrasjb.
Fixes #60537.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/fonts/class-wp-font-collection.php

    r57539 r57657  
    220220                    'font_family_settings' => array(
    221221                        'name'       => 'sanitize_text_field',
    222                         'slug'       => 'sanitize_title',
    223                         'fontFamily' => 'sanitize_text_field',
     222                        'slug'       => static function ( $value ) {
     223                            return _wp_to_kebab_case( sanitize_title( $value ) );
     224                        },
     225                        'fontFamily' => 'WP_Font_Utils::sanitize_font_family',
    224226                        'preview'    => 'sanitize_url',
    225227                        'fontFace'   => array(
  • trunk/src/wp-includes/fonts/class-wp-font-utils.php

    r57632 r57657  
    2020class WP_Font_Utils {
    2121    /**
     22     * Adds surrounding quotes to font family names that contain special characters.
     23     *
     24     * It follows the recommendations from the CSS Fonts Module Level 4.
     25     * @link https://www.w3.org/TR/css-fonts-4/#font-family-prop
     26     *
     27     * @since 6.5.0
     28     *
     29     * @param string $item A font family name.
     30     * @return string The font family name with surrounding quotes, if necessary.
     31     */
     32    private static function maybe_add_quotes( $item ) {
     33        // Matches strings that are not exclusively alphabetic characters or hyphens, and do not exactly follow the pattern generic(alphabetic characters or hyphens).
     34        $regex = '/^(?!generic\([a-zA-Z\-]+\)$)(?!^[a-zA-Z\-]+$).+/';
     35        $item  = trim( $item );
     36        if ( preg_match( $regex, $item ) ) {
     37            $item = trim( $item, "\"'" );
     38            return '"' . $item . '"';
     39        }
     40        return $item;
     41    }
     42
     43    /**
    2244     * Sanitizes and formats font family names.
    2345     *
    24      * - Applies `sanitize_text_field`
    25      * - Adds surrounding quotes to names that contain spaces and are not already quoted
     46     * - Applies `sanitize_text_field`.
     47     * - Adds surrounding quotes to names containing any characters that are not alphabetic or dashes.
     48     *
     49     * It follows the recommendations from the CSS Fonts Module Level 4.
     50     * @link https://www.w3.org/TR/css-fonts-4/#font-family-prop
    2651     *
    2752     * @since 6.5.0
     
    3863        }
    3964
    40         $font_family           = sanitize_text_field( $font_family );
    41         $font_families         = explode( ',', $font_family );
    42         $wrapped_font_families = array_map(
    43             function ( $family ) {
    44                 $trimmed = trim( $family );
    45                 if ( ! empty( $trimmed ) && str_contains( $trimmed, ' ' ) && ! str_contains( $trimmed, "'" ) && ! str_contains( $trimmed, '"' ) ) {
    46                         return '"' . $trimmed . '"';
     65        $output          = sanitize_text_field( $font_family );
     66        $formatted_items = array();
     67        if ( str_contains( $output, ',' ) ) {
     68            $items = explode( ',', $output );
     69            foreach ( $items as $item ) {
     70                $formatted_item = self::maybe_add_quotes( $item );
     71                if ( ! empty( $formatted_item ) ) {
     72                    $formatted_items[] = $formatted_item;
    4773                }
    48                 return $trimmed;
    49             },
    50             $font_families
    51         );
    52 
    53         if ( count( $wrapped_font_families ) === 1 ) {
    54             $font_family = $wrapped_font_families[0];
    55         } else {
    56             $font_family = implode( ', ', $wrapped_font_families );
    57         }
    58 
    59         return $font_family;
     74            }
     75            return implode( ', ', $formatted_items );
     76        }
     77        return self::maybe_add_quotes( $output );
    6078    }
    6179
  • trunk/tests/phpunit/tests/fonts/font-library/wpFontCollection/getData.php

    r57539 r57657  
    160160                        array(
    161161                            'font_family_settings' => array(
    162                                 'fontFamily' => 'Open Sans, sans-serif',
     162                                'fontFamily' => '"Open Sans", sans-serif',
    163163                                'slug'       => 'open-sans',
    164164                                'name'       => 'Open Sans',
  • trunk/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFontFamily.php

    r57539 r57657  
    3636        return array(
    3737            'data_families_with_spaces_and_numbers' => array(
    38                 'font_family' => 'Rock 3D , Open Sans,serif',
    39                 'expected'    => '"Rock 3D", "Open Sans", serif',
     38                'font_family' => 'Arial, Rock 3D , Open Sans,serif',
     39                'expected'    => 'Arial, "Rock 3D", "Open Sans", serif',
    4040            ),
    4141            'data_single_font_family'               => array(
    4242                'font_family' => 'Rock 3D',
    4343                'expected'    => '"Rock 3D"',
    44             ),
    45             'data_no_spaces'                        => array(
    46                 'font_family' => 'Rock3D',
    47                 'expected'    => 'Rock3D',
    4844            ),
    4945            'data_many_spaces_and_existing_quotes'  => array(
     
    5955                'expected'    => '"Rock 3D"',
    6056            ),
     57            'data_font_family_with_generic_names'   => array(
     58                'font_family' => 'generic(kai), generic(font[name]), generic(fangsong), Rock 3D',
     59                'expected'    => 'generic(kai), "generic(font[name])", generic(fangsong), "Rock 3D"',
     60            ),
    6161        );
    6262    }
  • trunk/tests/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php

    r57548 r57657  
    682682        $settings = array(
    683683            'name'       => 'Open Sans',
    684             'fontFamily' => '"Open Sans, "Noto Sans", sans-serif',
     684            'fontFamily' => 'Open Sans, "Noto Sans", sans-serif',
    685685            'preview'    => 'https://s.w.org/images/fonts/16.9/previews/open-sans/open-sans-400-normal.svg',
    686686        );
     
    701701            'name'       => $settings['name'],
    702702            'slug'       => 'open-sans-2',
    703             'fontFamily' => $settings['fontFamily'],
     703            'fontFamily' => '"Open Sans", "Noto Sans", sans-serif',
    704704            'preview'    => $settings['preview'],
    705705        );
Note: See TracChangeset for help on using the changeset viewer.