run:R W Run
8.68 KB
2026-03-11 16:18:51
R W Run
5.52 KB
2026-03-11 16:18:51
R W Run
10.01 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:51
R W Run
8.68 KB
2026-03-11 16:18:51
R W Run
55.24 KB
2026-03-11 16:18:51
R W Run
121.69 KB
2026-03-11 16:18:51
R W Run
55.07 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
25.52 KB
2026-03-11 16:18:51
R W Run
error_log
📄class-wp-font-face.php
1<?php
2/**
3 * WP_Font_Face class.
4 *
5 * @package WordPress
6 * @subpackage Fonts
7 * @since 6.4.0
8 */
9
10/**
11 * Font Face generates and prints `@font-face` styles for given fonts.
12 *
13 * @since 6.4.0
14 */
15class WP_Font_Face {
16
17 /**
18 * The font-face property defaults.
19 *
20 * @since 6.4.0
21 *
22 * @var string[]
23 */
24 private $font_face_property_defaults = array(
25 'font-family' => '',
26 'font-style' => 'normal',
27 'font-weight' => '400',
28 'font-display' => 'fallback',
29 );
30
31 /**
32 * Valid font-face property names.
33 *
34 * @since 6.4.0
35 *
36 * @var string[]
37 */
38 private $valid_font_face_properties = array(
39 'ascent-override',
40 'descent-override',
41 'font-display',
42 'font-family',
43 'font-stretch',
44 'font-style',
45 'font-weight',
46 'font-variant',
47 'font-feature-settings',
48 'font-variation-settings',
49 'line-gap-override',
50 'size-adjust',
51 'src',
52 'unicode-range',
53 );
54
55 /**
56 * Valid font-display values.
57 *
58 * @since 6.4.0
59 *
60 * @var string[]
61 */
62 private $valid_font_display = array( 'auto', 'block', 'fallback', 'swap', 'optional' );
63
64 /**
65 * Array of font-face style tag's attribute(s)
66 * where the key is the attribute name and the
67 * value is its value.
68 *
69 * @since 6.4.0
70 *
71 * @var string[]
72 */
73 private $style_tag_attrs = array();
74
75 /**
76 * Creates and initializes an instance of WP_Font_Face.
77 *
78 * @since 6.4.0
79 */
80 public function __construct() {
81 if (
82 function_exists( 'is_admin' ) && ! is_admin()
83 &&
84 function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' )
85 ) {
86 $this->style_tag_attrs = array( 'type' => 'text/css' );
87 }
88 }
89
90 /**
91 * Generates and prints the `@font-face` styles for the given fonts.
92 *
93 * @since 6.4.0
94 *
95 * @param array[][] $fonts Optional. The font-families and their font variations.
96 * See {@see wp_print_font_faces()} for the supported fields.
97 * Default empty array.
98 */
99 public function generate_and_print( array $fonts ) {
100 $fonts = $this->validate_fonts( $fonts );
101
102 // Bail out if there are no fonts are given to process.
103 if ( empty( $fonts ) ) {
104 return;
105 }
106
107 $css = $this->get_css( $fonts );
108
109 /*
110 * The font-face CSS is contained within <style> tags and can only be interpreted
111 * as CSS in the browser. Using wp_strip_all_tags() is sufficient escaping
112 * to avoid malicious attempts to close </style> and open a <script>.
113 */
114 $css = wp_strip_all_tags( $css );
115
116 // Bail out if there is no CSS to print.
117 if ( empty( $css ) ) {
118 return;
119 }
120
121 printf( $this->get_style_element(), $css );
122 }
123
124 /**
125 * Validates each of the font-face properties.
126 *
127 * @since 6.4.0
128 *
129 * @param array $fonts The fonts to valid.
130 * @return array Prepared font-faces organized by provider and font-family.
131 */
132 private function validate_fonts( array $fonts ) {
133 $validated_fonts = array();
134
135 foreach ( $fonts as $font_faces ) {
136 foreach ( $font_faces as $font_face ) {
137 $font_face = $this->validate_font_face_declarations( $font_face );
138 // Skip if failed validation.
139 if ( false === $font_face ) {
140 continue;
141 }
142
143 $validated_fonts[] = $font_face;
144 }
145 }
146
147 return $validated_fonts;
148 }
149
150 /**
151 * Validates each font-face declaration (property and value pairing).
152 *
153 * @since 6.4.0
154 *
155 * @param array $font_face Font face property and value pairings to validate.
156 * @return array|false Validated font-face on success, or false on failure.
157 */
158 private function validate_font_face_declarations( array $font_face ) {
159 $font_face = wp_parse_args( $font_face, $this->font_face_property_defaults );
160
161 // Check the font-family.
162 if ( empty( $font_face['font-family'] ) || ! is_string( $font_face['font-family'] ) ) {
163 // @todo replace with `wp_trigger_error()`.
164 _doing_it_wrong(
165 __METHOD__,
166 __( 'Font font-family must be a non-empty string.' ),
167 '6.4.0'
168 );
169 return false;
170 }
171
172 // Make sure that local fonts have 'src' defined.
173 if ( empty( $font_face['src'] ) || ( ! is_string( $font_face['src'] ) && ! is_array( $font_face['src'] ) ) ) {
174 // @todo replace with `wp_trigger_error()`.
175 _doing_it_wrong(
176 __METHOD__,
177 __( 'Font src must be a non-empty string or an array of strings.' ),
178 '6.4.0'
179 );
180 return false;
181 }
182
183 // Validate the 'src' property.
184 foreach ( (array) $font_face['src'] as $src ) {
185 if ( empty( $src ) || ! is_string( $src ) ) {
186 // @todo replace with `wp_trigger_error()`.
187 _doing_it_wrong(
188 __METHOD__,
189 __( 'Each font src must be a non-empty string.' ),
190 '6.4.0'
191 );
192 return false;
193 }
194 }
195
196 // Check the font-weight.
197 if ( ! is_string( $font_face['font-weight'] ) && ! is_int( $font_face['font-weight'] ) ) {
198 // @todo replace with `wp_trigger_error()`.
199 _doing_it_wrong(
200 __METHOD__,
201 __( 'Font font-weight must be a properly formatted string or integer.' ),
202 '6.4.0'
203 );
204 return false;
205 }
206
207 // Check the font-display.
208 if ( ! in_array( $font_face['font-display'], $this->valid_font_display, true ) ) {
209 $font_face['font-display'] = $this->font_face_property_defaults['font-display'];
210 }
211
212 // Remove invalid properties.
213 foreach ( $font_face as $property => $value ) {
214 if ( ! in_array( $property, $this->valid_font_face_properties, true ) ) {
215 unset( $font_face[ $property ] );
216 }
217 }
218
219 return $font_face;
220 }
221
222 /**
223 * Gets the style element for wrapping the `@font-face` CSS.
224 *
225 * @since 6.4.0
226 *
227 * @return string The style element.
228 */
229 private function get_style_element() {
230 $attributes = $this->generate_style_element_attributes();
231
232 return "<style class='wp-fonts-local'{$attributes}>\n%s\n</style>\n";
233 }
234
235 /**
236 * Gets the defined <style> element's attributes.
237 *
238 * @since 6.4.0
239 *
240 * @return string A string of attribute=value when defined, else, empty string.
241 */
242 private function generate_style_element_attributes() {
243 $attributes = '';
244 foreach ( $this->style_tag_attrs as $name => $value ) {
245 $attributes .= " {$name}='{$value}'";
246 }
247 return $attributes;
248 }
249
250 /**
251 * Gets the `@font-face` CSS styles for locally-hosted font files.
252 *
253 * This method does the following processing tasks:
254 * 1. Orchestrates an optimized `src` (with format) for browser support.
255 * 2. Generates the `@font-face` for all its fonts.
256 *
257 * @since 6.4.0
258 *
259 * @param array[] $font_faces The font-faces to generate @font-face CSS styles.
260 * @return string The `@font-face` CSS styles.
261 */
262 private function get_css( $font_faces ) {
263 $css = '';
264
265 foreach ( $font_faces as $font_face ) {
266 // Order the font's `src` items to optimize for browser support.
267 $font_face = $this->order_src( $font_face );
268
269 // Build the @font-face CSS for this font.
270 $css .= '@font-face{' . $this->build_font_face_css( $font_face ) . '}' . "\n";
271 }
272
273 // Don't print the last newline character.
274 return rtrim( $css, "\n" );
275 }
276
277 /**
278 * Orders `src` items to optimize for browser support.
279 *
280 * @since 6.4.0
281 *
282 * @param array $font_face Font face to process.
283 * @return array Font-face with ordered src items.
284 */
285 private function order_src( array $font_face ) {
286 if ( ! is_array( $font_face['src'] ) ) {
287 $font_face['src'] = (array) $font_face['src'];
288 }
289
290 $src = array();
291 $src_ordered = array();
292
293 foreach ( $font_face['src'] as $url ) {
294 // Add data URIs first.
295 if ( str_starts_with( trim( $url ), 'data:' ) ) {
296 $src_ordered[] = array(
297 'url' => $url,
298 'format' => 'data',
299 );
300 continue;
301 }
302 $format = pathinfo( $url, PATHINFO_EXTENSION );
303 $src[ $format ] = $url;
304 }
305
306 // Add woff2.
307 if ( ! empty( $src['woff2'] ) ) {
308 $src_ordered[] = array(
309 'url' => $src['woff2'],
310 'format' => 'woff2',
311 );
312 }
313
314 // Add woff.
315 if ( ! empty( $src['woff'] ) ) {
316 $src_ordered[] = array(
317 'url' => $src['woff'],
318 'format' => 'woff',
319 );
320 }
321
322 // Add ttf.
323 if ( ! empty( $src['ttf'] ) ) {
324 $src_ordered[] = array(
325 'url' => $src['ttf'],
326 'format' => 'truetype',
327 );
328 }
329
330 // Add eot.
331 if ( ! empty( $src['eot'] ) ) {
332 $src_ordered[] = array(
333 'url' => $src['eot'],
334 'format' => 'embedded-opentype',
335 );
336 }
337
338 // Add otf.
339 if ( ! empty( $src['otf'] ) ) {
340 $src_ordered[] = array(
341 'url' => $src['otf'],
342 'format' => 'opentype',
343 );
344 }
345 $font_face['src'] = $src_ordered;
346
347 return $font_face;
348 }
349
350 /**
351 * Builds the font-family's CSS.
352 *
353 * @since 6.4.0
354 *
355 * @param array $font_face Font face to process.
356 * @return string This font-family's CSS.
357 */
358 private function build_font_face_css( array $font_face ) {
359 $css = '';
360
361 /*
362 * Wrap font-family in quotes if it contains spaces
363 * and is not already wrapped in quotes.
364 */
365 if (
366 str_contains( $font_face['font-family'], ' ' ) &&
367 ! str_contains( $font_face['font-family'], '"' ) &&
368 ! str_contains( $font_face['font-family'], "'" )
369 ) {
370 $font_face['font-family'] = '"' . $font_face['font-family'] . '"';
371 }
372
373 foreach ( $font_face as $key => $value ) {
374 // Compile the "src" parameter.
375 if ( 'src' === $key ) {
376 $value = $this->compile_src( $value );
377 }
378
379 // If font-variation-settings is an array, convert it to a string.
380 if ( 'font-variation-settings' === $key && is_array( $value ) ) {
381 $value = $this->compile_variations( $value );
382 }
383
384 if ( ! empty( $value ) ) {
385 $css .= "$key:$value;";
386 }
387 }
388
389 return $css;
390 }
391
392 /**
393 * Compiles the `src` into valid CSS.
394 *
395 * @since 6.4.0
396 *
397 * @param array $value Value to process.
398 * @return string The CSS.
399 */
400 private function compile_src( array $value ) {
401 $src = '';
402
403 foreach ( $value as $item ) {
404 $src .= ( 'data' === $item['format'] )
405 ? ", url({$item['url']})"
406 : ", url('{$item['url']}') format('{$item['format']}')";
407 }
408
409 $src = ltrim( $src, ', ' );
410 return $src;
411 }
412
413 /**
414 * Compiles the font variation settings.
415 *
416 * @since 6.4.0
417 *
418 * @param array $font_variation_settings Array of font variation settings.
419 * @return string The CSS.
420 */
421 private function compile_variations( array $font_variation_settings ) {
422 $variations = '';
423
424 foreach ( $font_variation_settings as $key => $value ) {
425 $variations .= "$key $value";
426 }
427
428 return $variations;
429 }
430}
431
Ui Ux Design – Teachers Night Out

Get in Touch

© 2024 Teachers Night Out. All Rights Reserved.