Skip to content

Commit 272a747

Browse files
committed
Font: add and use normalize_css_font_face_font_family method
1 parent 2e8767e commit 272a747

3 files changed

Lines changed: 81 additions & 2 deletions

File tree

src/wp-includes/fonts/class-wp-font-collection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ private static function get_sanitization_schema() {
259259
'preview' => 'sanitize_url',
260260
'fontFace' => array(
261261
array(
262-
'fontFamily' => 'sanitize_text_field',
262+
'fontFamily' => 'WP_Font_Utils::normalize_css_font_face_font_family',
263263
'fontStyle' => 'sanitize_text_field',
264264
'fontWeight' => 'sanitize_text_field',
265265
'src' => static function ( $value ) {

src/wp-includes/fonts/class-wp-font-utils.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,85 @@ private static function maybe_add_quotes( $item ) {
4040
return $item;
4141
}
4242

43+
/**
44+
* Normalize @font-face font-family CSS text.
45+
*
46+
* This function attempts to be generous in the allowed values:
47+
* - Valid @font-face font-family values must return a semantically equivalent result.
48+
* - Normalization must be idempotent.
49+
* - Common mistakes such as providing multiple comma-separated font-family values return a
50+
* normalization of the first item: `a, b` becomes `"a"`.
51+
* - Invalid trailing content is ignored: `"string" garbage` becomes `"string"`.
52+
*
53+
* > Syntax of <family-name>
54+
* > <family-name> = <string> | <custom-ident>+
55+
*
56+
* > To avoid mistakes in escaping, it is recommended to quote font family names that contain
57+
* > white space, digits, or punctuation characters other than hyphens
58+
*
59+
* @see https://drafts.csswg.org/css-fonts/#family-name-syntax
60+
*
61+
* @param string $font_family CSS text @font-face font-family value.
62+
* @return string Normalized value.
63+
*/
64+
public static function normalize_css_font_face_font_family( string $font_family ): ?string {
65+
$processor = WP_CSS_Token_Processor::create( $font_family );
66+
if ( null === $processor ) {
67+
return null;
68+
}
69+
70+
// Ignore leading whitespace tokens.
71+
while ( $processor->next_token() && WP_CSS_Token_Processor::TOKEN_WHITESPACE === $processor->get_token_type() ) {
72+
continue;
73+
}
74+
75+
$token_type = $processor->get_token_type();
76+
if ( WP_CSS_Token_Processor::TOKEN_STRING === $token_type ) {
77+
$plaintext_font_family = $processor->get_token_value();
78+
return WP_CSS_Builder::string( $plaintext_font_family );
79+
}
80+
81+
/**
82+
* Idents can be composed to form a <family-name>, otherwise consider the
83+
* font-family invalid.
84+
*/
85+
if ( WP_CSS_Token_Processor::TOKEN_IDENT !== $token_type ) {
86+
return null;
87+
}
88+
89+
/**
90+
* > If a sequence of identifiers is given as a <family-name>, the computed value is
91+
* > the name converted to a string by joining all the identifiers in the sequence
92+
* > by single spaces.
93+
*
94+
* @see https://drafts.csswg.org/css-fonts/#family-name-syntax
95+
*/
96+
$plaintext_font_ident_parts = array( $processor->get_token_value() );
97+
while ( $processor->next_token() ) {
98+
switch ( $processor->get_token_type() ) {
99+
case WP_CSS_Token_Processor::TOKEN_IDENT:
100+
$plaintext_font_family[] = $processor->get_token_value();
101+
break;
102+
103+
case WP_CSS_Token_Processor::TOKEN_WHITESPACE:
104+
continue;
105+
106+
/**
107+
* Comma tokens suggest this was a multi-value font-family (for qualified rules, not
108+
* @font-face rules). Stop processing to handle only the first value.
109+
*/
110+
case WP_CSS_Token_Processor::TOKEN_COMMA:
111+
break 2;
112+
113+
// Anything else is an error.
114+
default:
115+
return null;
116+
}
117+
}
118+
119+
return WP_CSS_Builder::string( implode( ' ', $plaintext_font_ident_parts ) );
120+
}
121+
43122
/**
44123
* Sanitizes and formats font family names.
45124
*

src/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ public function get_item_schema() {
540540
'type' => 'string',
541541
'default' => '',
542542
'arg_options' => array(
543-
'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ),
543+
'sanitize_callback' => array( 'WP_Font_Utils', 'normalize_css_font_face_font_family' ),
544544
),
545545
),
546546
'fontStyle' => array(

0 commit comments

Comments
 (0)