-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
register-webfonts-from-theme-json.php
182 lines (155 loc) · 6.42 KB
/
register-webfonts-from-theme-json.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<?php
/**
* Bootstraps Global Styles.
*
* @package gutenberg
*/
/**
* Register webfonts defined in theme.json.
*/
function gutenberg_register_webfonts_from_theme_json() {
// Get settings.
$settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings();
// If in the editor, add webfonts defined in variations.
if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
$variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
foreach ( $variations as $variation ) {
// Sanity check: Skip if fontFamilies are not defined in the variation.
if (
empty( $variation['settings'] ) ||
empty( $variation['settings']['typography'] ) ||
empty( $variation['settings']['typography']['fontFamilies'] )
) {
continue;
}
// Merge the variation settings with the global settings.
$settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography'];
$settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies'];
$settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme'];
$settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
// Make sure there are no duplicates.
$settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );
}
}
// Bail out early if there are no settings for webfonts.
if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) {
return;
}
$webfonts = array();
// Look for fontFamilies.
foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
foreach ( $font_families as $font_family ) {
// Skip if fontFace is not defined.
if ( empty( $font_family['fontFace'] ) ) {
continue;
}
$font_family['fontFace'] = (array) $font_family['fontFace'];
foreach ( $font_family['fontFace'] as $font_face ) {
// Skip if the webfont was registered through the Webfonts API.
if ( isset( $font_face['origin'] ) && 'gutenberg_wp_webfonts_api' === $font_face['origin'] ) {
continue;
}
// Check if webfonts have a "src" param, and if they do account for the use of "file:./".
if ( ! empty( $font_face['src'] ) ) {
$font_face['src'] = (array) $font_face['src'];
foreach ( $font_face['src'] as $src_key => $url ) {
// Tweak the URL to be relative to the theme root.
if ( ! str_starts_with( $url, 'file:./' ) ) {
continue;
}
$font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
}
}
// Convert keys to kebab-case.
foreach ( $font_face as $property => $value ) {
$kebab_case = _wp_to_kebab_case( $property );
$font_face[ $kebab_case ] = $value;
if ( $kebab_case !== $property ) {
unset( $font_face[ $property ] );
}
}
$webfonts[] = $font_face;
}
}
}
foreach ( $webfonts as $webfont ) {
wp_webfonts()->register_webfont( $webfont );
}
foreach ( $webfonts as $webfont ) {
wp_webfonts()->enqueue_webfont( $webfont['font-family'] );
}
}
/**
* Add missing fonts data to the global styles.
*
* @param array $data The global styles.
* @return array The global styles with missing fonts data.
*/
function gutenberg_add_registered_webfonts_to_theme_json( $data ) {
$font_families_registered = wp_webfonts()->get_all_webfonts();
$font_families_from_theme = array();
if ( ! empty( $data['settings'] ) && ! empty( $data['settings']['typography'] ) && ! empty( $data['settings']['typography']['fontFamilies'] ) ) {
$font_families_from_theme = $data['settings']['typography']['fontFamilies'];
}
/**
* Helper to get an array of the font-families.
*
* @param array $families_data The font-families data.
* @return array The font-families array.
*/
$get_families = static function( $families_data ) {
$families = array();
foreach ( $families_data as $family ) {
$families[] = WP_Webfonts::get_font_slug( $family );
}
// Micro-optimization: Use array_flip( array_flip( $array ) )
// instead of array_unique( $array ) because it's faster.
// The result is the same.
return array_flip( array_flip( $families ) );
};
// Diff the arrays to find the missing fonts.
$to_add = array_diff(
array_keys( $font_families_registered ),
$get_families( $font_families_from_theme )
);
// Bail out early if there are no missing fonts.
if ( empty( $to_add ) ) {
return $data;
}
// Make sure the path to settings.typography.fontFamilies.theme exists
// before adding missing fonts.
if ( empty( $data['settings'] ) ) {
$data['settings'] = array();
}
if ( empty( $data['settings']['typography'] ) ) {
$data['settings']['typography'] = array();
}
if ( empty( $data['settings']['typography']['fontFamilies'] ) ) {
$data['settings']['typography']['fontFamilies'] = array();
}
foreach ( $to_add as $slug ) {
$font_faces_for_family = $font_families_registered[ $slug ];
$family_name = $font_faces_for_family[0]['font-family'];
$font_faces = array();
foreach ( $font_faces_for_family as $font_face ) {
$camel_cased = array( 'origin' => 'gutenberg_wp_webfonts_api' );
foreach ( $font_face as $key => $value ) {
$camel_cased[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value;
}
$font_faces[] = $camel_cased;
}
$data['settings']['typography']['fontFamilies'][] = array(
'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name,
'name' => $family_name,
'slug' => $slug,
'fontFace' => $font_faces,
);
}
return $data;
}
// `gutenberg_register_webfonts_from_theme_json()` calls `WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()`, which instantiates `WP_Theme_JSON_Gutenberg()`;
// Gutenberg server-side blocks are registered via the init hook with a priority value of `20`. E.g., `add_action( 'init', 'register_block_core_image', 20 )`;
// This priority value is added dynamically during the build. See: tools/webpack/blocks.js.
// We want to make sure Gutenberg blocks are re-registered before any Theme_JSON operations take place
// so that we have access to updated merged data.
add_action( 'init', 'gutenberg_register_webfonts_from_theme_json', 21 );