[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Font Utils class. 4 * 5 * Provides utility functions for working with font families. 6 * 7 * @package WordPress 8 * @subpackage Fonts 9 * @since 6.5.0 10 */ 11 12 /** 13 * A class of utilities for working with the Font Library. 14 * 15 * These utilities may change or be removed in the future and are intended for internal use only. 16 * 17 * @since 6.5.0 18 * @access private 19 */ 20 class WP_Font_Utils { 21 /** 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 /** 44 * Sanitizes and formats font family names. 45 * 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 51 * 52 * @since 6.5.0 53 * @access private 54 * 55 * @see sanitize_text_field() 56 * 57 * @param string $font_family Font family name(s), comma-separated. 58 * @return string Sanitized and formatted font family name(s). 59 */ 60 public static function sanitize_font_family( $font_family ) { 61 if ( ! $font_family ) { 62 return ''; 63 } 64 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; 73 } 74 } 75 return implode( ', ', $formatted_items ); 76 } 77 return self::maybe_add_quotes( $output ); 78 } 79 80 /** 81 * Generates a slug from font face properties, e.g. `open sans;normal;400;100%;U+0-10FFFF` 82 * 83 * Used for comparison with other font faces in the same family, to prevent duplicates 84 * that would both match according the CSS font matching spec. Uses only simple case-insensitive 85 * matching for fontFamily and unicodeRange, so does not handle overlapping font-family lists or 86 * unicode ranges. 87 * 88 * @since 6.5.0 89 * @access private 90 * 91 * @link https://drafts.csswg.org/css-fonts/#font-style-matching 92 * 93 * @param array $settings { 94 * Font face settings. 95 * 96 * @type string $fontFamily Font family name. 97 * @type string $fontStyle Optional font style, defaults to 'normal'. 98 * @type string $fontWeight Optional font weight, defaults to 400. 99 * @type string $fontStretch Optional font stretch, defaults to '100%'. 100 * @type string $unicodeRange Optional unicode range, defaults to 'U+0-10FFFF'. 101 * } 102 * @return string Font face slug. 103 */ 104 public static function get_font_face_slug( $settings ) { 105 $defaults = array( 106 'fontFamily' => '', 107 'fontStyle' => 'normal', 108 'fontWeight' => '400', 109 'fontStretch' => '100%', 110 'unicodeRange' => 'U+0-10FFFF', 111 ); 112 $settings = wp_parse_args( $settings, $defaults ); 113 if ( function_exists( 'mb_strtolower' ) ) { 114 $font_family = mb_strtolower( $settings['fontFamily'] ); 115 } else { 116 $font_family = strtolower( $settings['fontFamily'] ); 117 } 118 $font_style = strtolower( $settings['fontStyle'] ); 119 $font_weight = strtolower( $settings['fontWeight'] ); 120 $font_stretch = strtolower( $settings['fontStretch'] ); 121 $unicode_range = strtoupper( $settings['unicodeRange'] ); 122 123 // Convert weight keywords to numeric strings. 124 $font_weight = str_replace( array( 'normal', 'bold' ), array( '400', '700' ), $font_weight ); 125 126 // Convert stretch keywords to numeric strings. 127 $font_stretch_map = array( 128 'ultra-condensed' => '50%', 129 'extra-condensed' => '62.5%', 130 'condensed' => '75%', 131 'semi-condensed' => '87.5%', 132 'normal' => '100%', 133 'semi-expanded' => '112.5%', 134 'expanded' => '125%', 135 'extra-expanded' => '150%', 136 'ultra-expanded' => '200%', 137 ); 138 $font_stretch = str_replace( array_keys( $font_stretch_map ), array_values( $font_stretch_map ), $font_stretch ); 139 140 $slug_elements = array( $font_family, $font_style, $font_weight, $font_stretch, $unicode_range ); 141 142 $slug_elements = array_map( 143 function ( $elem ) { 144 // Remove quotes to normalize font-family names, and ';' to use as a separator. 145 $elem = trim( str_replace( array( '"', "'", ';' ), '', $elem ) ); 146 147 // Normalize comma separated lists by removing whitespace in between items, 148 // but keep whitespace within items (e.g. "Open Sans" and "OpenSans" are different fonts). 149 // CSS spec for whitespace includes: U+000A LINE FEED, U+0009 CHARACTER TABULATION, or U+0020 SPACE, 150 // which by default are all matched by \s in PHP. 151 return preg_replace( '/,\s+/', ',', $elem ); 152 }, 153 $slug_elements 154 ); 155 156 return sanitize_text_field( implode( ';', $slug_elements ) ); 157 } 158 159 /** 160 * Sanitizes a tree of data using a schema. 161 * 162 * The schema structure should mirror the data tree. Each value provided in the 163 * schema should be a callable that will be applied to sanitize the corresponding 164 * value in the data tree. Keys that are in the data tree, but not present in the 165 * schema, will be removed in the sanitized data. Nested arrays are traversed recursively. 166 * 167 * @since 6.5.0 168 * 169 * @access private 170 * 171 * @param array $tree The data to sanitize. 172 * @param array $schema The schema used for sanitization. 173 * @return array The sanitized data. 174 */ 175 public static function sanitize_from_schema( $tree, $schema ) { 176 if ( ! is_array( $tree ) || ! is_array( $schema ) ) { 177 return array(); 178 } 179 180 foreach ( $tree as $key => $value ) { 181 // Remove keys not in the schema or with null/empty values. 182 if ( ! array_key_exists( $key, $schema ) ) { 183 unset( $tree[ $key ] ); 184 continue; 185 } 186 187 $is_value_array = is_array( $value ); 188 $is_schema_array = is_array( $schema[ $key ] ) && ! is_callable( $schema[ $key ] ); 189 190 if ( $is_value_array && $is_schema_array ) { 191 if ( wp_is_numeric_array( $value ) ) { 192 // If indexed, process each item in the array. 193 foreach ( $value as $item_key => $item_value ) { 194 $tree[ $key ][ $item_key ] = isset( $schema[ $key ][0] ) && is_array( $schema[ $key ][0] ) 195 ? self::sanitize_from_schema( $item_value, $schema[ $key ][0] ) 196 : self::apply_sanitizer( $item_value, $schema[ $key ][0] ); 197 } 198 } else { 199 // If it is an associative or indexed array, process as a single object. 200 $tree[ $key ] = self::sanitize_from_schema( $value, $schema[ $key ] ); 201 } 202 } elseif ( ! $is_value_array && $is_schema_array ) { 203 // If the value is not an array but the schema is, remove the key. 204 unset( $tree[ $key ] ); 205 } elseif ( ! $is_schema_array ) { 206 // If the schema is not an array, apply the sanitizer to the value. 207 $tree[ $key ] = self::apply_sanitizer( $value, $schema[ $key ] ); 208 } 209 210 // Remove keys with null/empty values. 211 if ( empty( $tree[ $key ] ) ) { 212 unset( $tree[ $key ] ); 213 } 214 } 215 216 return $tree; 217 } 218 219 /** 220 * Applies a sanitizer function to a value. 221 * 222 * @since 6.5.0 223 * 224 * @param mixed $value The value to sanitize. 225 * @param callable $sanitizer The sanitizer function to apply. 226 * @return mixed The sanitized value. 227 */ 228 private static function apply_sanitizer( $value, $sanitizer ) { 229 if ( null === $sanitizer ) { 230 return $value; 231 232 } 233 return call_user_func( $sanitizer, $value ); 234 } 235 236 /** 237 * Returns the expected mime-type values for font files, depending on PHP version. 238 * 239 * This is needed because font mime types vary by PHP version, so checking the PHP version 240 * is necessary until a list of valid mime-types for each file extension can be provided to 241 * the 'upload_mimes' filter. 242 * 243 * @since 6.5.0 244 * 245 * @access private 246 * 247 * @return string[] A collection of mime types keyed by file extension. 248 */ 249 public static function get_allowed_font_mime_types() { 250 $php_7_ttf_mime_type = PHP_VERSION_ID >= 70300 ? 'application/font-sfnt' : 'application/x-font-ttf'; 251 252 return array( 253 'otf' => 'application/vnd.ms-opentype', 254 'ttf' => PHP_VERSION_ID >= 70400 ? 'font/sfnt' : $php_7_ttf_mime_type, 255 'woff' => PHP_VERSION_ID >= 80112 ? 'font/woff' : 'application/font-woff', 256 'woff2' => PHP_VERSION_ID >= 80112 ? 'font/woff2' : 'application/font-woff2', 257 ); 258 } 259 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |