PluginProbe
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts / 2.7.7
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts v2.7.7
2.8.14 2.8.13 2.8.12 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.10 2.8.11 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 trunk 1.0.1 1.0.2 1.1.0 1.1.1 All 147 releases
content-blocks-builder / includes / typography.php

typography.php in Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts 2.7.7, at includes/typography.php

504 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The typography settings
4 *
5 * @package BoldBlocks
6 * @author Phi Phan <mrphipv@gmail.com>
7 * @copyright Copyright (c) 2022, Phi Phan
8 */
9
10 namespace BoldBlocks;
11
12 // Exit if accessed directly.
13 defined( 'ABSPATH' ) || exit;
14
15 if ( ! class_exists( Typography::class ) ) :
16 /**
17 * The controller class for typography settings.
18 */
19 class Typography extends CoreComponent {
20 /**
21 * Run main hooks
22 *
23 * @return void
24 */
25 public function run() {
26 // Register setting fields.
27 add_action( 'init', [ $this, 'register_setting_fields' ] );
28
29 // Add rest api endpoint to query google fonts.
30 add_action( 'rest_api_init', [ $this, 'register_google_fonts_endpoint' ] );
31
32 // Load typography style.
33 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_frontend_typography_scripts' ], PHP_INT_MAX );
34 add_action( 'enqueue_block_assets', [ $this, 'enqueue_block_editor_typography_scripts' ] );
35
36 add_filter( 'wp_resource_hints', [ $this, 'preconnect_fonts' ], 10, 2 );
37 add_action( 'wp_head', [ $this, 'preload_fonts' ], 5 );
38
39 // Add body class.
40 add_filter( 'body_class', [ $this, 'add_typography_to_body_class' ] );
41 }
42
43 /**
44 * Register custom setting fields
45 *
46 * @return void
47 */
48 public function register_setting_fields() {
49 // Setting fields.
50 register_setting(
51 'boldblocks',
52 'boldblocks_enable_typography',
53 [
54 'type' => 'boolean',
55 'show_in_rest' => [
56 'name' => 'EnableTypography',
57 ],
58 'default' => false,
59 ]
60 );
61
62 register_setting(
63 'boldblocks',
64 'boldblocks_use_bunny_fonts',
65 [
66 'type' => 'boolean',
67 'show_in_rest' => [
68 'name' => 'UseBunnyFonts',
69 ],
70 'default' => false,
71 ]
72 );
73
74 register_setting(
75 'boldblocks',
76 'boldblocks_typography',
77 [
78 'type' => 'object',
79 'show_in_rest' => array(
80 'name' => 'BoldBlocksTypography',
81 'schema' => array(
82 'type' => 'object',
83 'properties' => array(
84 'fonts' => array(
85 'type' => 'string',
86 ),
87 ),
88 'additionalProperties' => array(
89 'type' => 'string',
90 ),
91 ),
92 ),
93 ]
94 );
95
96 register_meta(
97 'post',
98 'boldblocks_typography',
99 [
100 'single' => true,
101 'type' => 'object',
102 'show_in_rest' => array(
103 'name' => 'BoldBlocksTypography',
104 'schema' => array(
105 'type' => 'object',
106 'additionalProperties' => array(
107 'type' => 'string',
108 ),
109 ),
110 ),
111 'auth_callback' => function () {
112 return current_user_can( 'edit_posts' );
113 },
114 ]
115 );
116 }
117
118 /**
119 * Build a custom endpoint to query google fonts.
120 *
121 * @return void
122 */
123 public function register_google_fonts_endpoint() {
124 register_rest_route(
125 'boldblocks/v1',
126 '/getGoogleFonts/',
127 array(
128 'methods' => 'GET',
129 'callback' => [ $this, 'get_google_fonts' ],
130 'permission_callback' => function () {
131 return current_user_can( 'publish_posts' );
132 },
133 )
134 );
135 }
136
137 /**
138 * Get google fonts.
139 *
140 * @param WP_REST_Request $request The request object.
141 * @return void
142 */
143 public function get_google_fonts( $request ) {
144 // fonts file path.
145 $fonts_file = $this->the_plugin_instance->get_file_path( 'data/fonts/google-fonts.json' );
146
147 // Send the error if the fonts file is not exists.
148 if ( ! \file_exists( $fonts_file ) ) {
149 wp_send_json_error( __( 'The google-fonts.json file is not exists.', 'content-blocks-builder' ), 500 );
150 }
151
152 // Parse json.
153 $fonts = wp_json_file_decode( $fonts_file, [ 'associative' => true ] );
154
155 wp_send_json(
156 [
157 'data' => $fonts,
158 'success' => true,
159 ]
160 );
161 }
162
163 /**
164 * Enqueue scripts for typography
165 *
166 * @return void
167 */
168 public function enqueue_frontend_typography_scripts() {
169 $post_id = 0;
170
171 if ( is_singular() ) {
172 $post_id = get_queried_object_id();
173 }
174
175 // Enqueue custom fonts.
176 $this->enqueue_custom_fonts( $post_id );
177 }
178
179 /**
180 * Enqueue typography for editor
181 *
182 * @return void
183 */
184 public function enqueue_block_editor_typography_scripts() {
185 if ( ! is_admin() ) {
186 return;
187 }
188
189 global $post;
190
191 $screen = get_current_screen();
192 $is_editor = $screen->is_block_editor;
193
194 // Bail if it's not a page that has block editor.
195 if ( ! $is_editor ) {
196 return;
197 }
198
199 $post_id = $screen->base === 'post' && $post ? $post->ID : 0;
200
201 // Enqueue custom fonts.
202 $this->enqueue_custom_fonts( $post_id, $is_editor );
203 }
204
205 /**
206 * Enqueue custom fonts
207 *
208 * @param int $post_id
209 * @param boolean $is_editor
210 * @return void
211 */
212 private function enqueue_custom_fonts( $post_id, $is_editor = false ) {
213 $use_bunny_fonts = get_option( 'boldblocks_use_bunny_fonts' );
214
215 $fonts_url = $this->get_fonts_url( $post_id, $use_bunny_fonts );
216 if ( $fonts_url ) {
217 $prefix = $is_editor ? 'https:' : '';
218 $service_url = $use_bunny_fonts ? '//fonts.bunny.net/css?family=' : '//fonts.googleapis.com/css2?';
219 wp_enqueue_style( 'boldblocks-custom-fonts', $prefix . $service_url . $fonts_url, [], null );
220
221 $typography_style = $this->get_typography_style( $post_id, $is_editor );
222 wp_add_inline_style( 'boldblocks-custom-fonts', $typography_style );
223
224 if ( $is_editor ) {
225 $wp_styles = wp_styles();
226 $custom_blocks = $wp_styles->query( $this->the_plugin_instance->get_component( CustomBlocks::class )->custom_blocks_handle, 'registered' );
227
228 if ( $custom_blocks ) {
229 $custom_blocks->deps[] = 'boldblocks-custom-fonts';
230 }
231 }
232 }
233 }
234
235 /**
236 * Add preconnect for font service.
237 *
238 * @param array $urls URLs to print for resource hints.
239 * @param string $relation_type The relation type the URLs are printed.
240 * @return array $urls URLs to print for resource hints.
241 */
242 public function preconnect_fonts( $urls, $relation_type ) {
243 if ( wp_style_is( 'boldblocks-custom-fonts', 'queue' ) && 'preconnect' === $relation_type ) {
244 $use_bunny_fonts = get_option( 'boldblocks_use_bunny_fonts' );
245
246 $urls[] = array(
247 'href' => $use_bunny_fonts ? '//fonts.bunny.net' : '//fonts.gstatic.com',
248 'crossorigin',
249 );
250 }
251
252 return $urls;
253 }
254
255 /**
256 * Add preload for fonts.
257 *
258 * @return void
259 */
260 public function preload_fonts() {
261 $wp_styles = wp_styles();
262 $style = $wp_styles->query( 'boldblocks-custom-fonts', 'registered' );
263
264 if ( $style ) {
265 echo "<link rel='preload' as='style' href='{$style->src}'/>";
266 }
267 }
268
269 /**
270 * Load google fonts
271 *
272 * @param int $post_id
273 * @param boolean $use_bunny_fonts
274 * @return void
275 */
276 private function get_fonts_url( $post_id, $use_bunny_fonts ) {
277 $typography = $this->get_custom_typography( $post_id );
278
279 if ( ! $typography ) {
280 return;
281 }
282
283 $family_urls = [];
284
285 $body = $typography['body'] ?? [];
286 $body_font_family = $body['fontFamily'] ?? '';
287 $body_font_variants = $body['fontVariants'] ?? [];
288
289 $body_font_url = $this->get_font_url( $body_font_family, $body_font_variants, $use_bunny_fonts );
290 if ( $body_font_url ) {
291 $family_urls[] = $body_font_url;
292 }
293
294 $headings = $typography['headings'] ?? [];
295 $headings_font_family = $headings['fontFamily'] ?? '';
296 $headings_font_variants = $headings['fontVariants'] ?? [];
297
298 $headings_font_url = $this->get_font_url( $headings_font_family, $headings_font_variants, $use_bunny_fonts );
299 if ( $headings_font_url ) {
300 $family_urls[] = $headings_font_url;
301 }
302
303 if ( count( $family_urls ) > 0 ) {
304 $glue = $use_bunny_fonts ? '|' : '&';
305 return implode( $glue, $family_urls ) . '&display=swap';
306 }
307
308 return;
309 }
310
311 /**
312 * Get font url
313 *
314 * @param string $font_family
315 * @param array $font_variants
316 * @param boolean $use_bunny_fonts
317 * @return string
318 */
319 private function get_font_url( $font_family, $font_variants, $use_bunny_fonts ) {
320 $family_url = '';
321
322 if ( $font_family ) {
323 $family_url = $use_bunny_fonts ? \str_replace( ' ', '+', $font_family ) : 'family=' . \str_replace( ' ', '+', $font_family );
324 if ( $font_variants ) {
325 if ( ! $use_bunny_fonts ) {
326 usort(
327 $font_variants,
328 function( $val1, $val2 ) {
329 $val1_has_italic = strpos( $val1, 'italic' ) !== false;
330 $val2_has_italic = strpos( $val2, 'italic' ) !== false;
331
332 if ( $val1_has_italic && ! $val2_has_italic ) {
333 return 1;
334 } elseif ( ! $val1_has_italic && $val2_has_italic ) {
335 return -1;
336 }
337
338 return strcmp( $val1, $val2 );
339 }
340 );
341 $family_url .= ':ital,wght@';
342 foreach ( $font_variants as $variant ) {
343 if ( strpos( $variant, 'italic' ) === false ) {
344 $family_url .= '0,' . $variant . ';';
345 } else {
346 $family_url .= '1,' . str_replace( 'italic', '', $variant ) . ';';
347 }
348 }
349 } else {
350 $family_url .= array_reduce(
351 $font_variants,
352 function ( $accumulator, $item ) {
353 $variant = \str_replace( 'italic', 'i', $item );
354 if ( empty( $accumulator ) ) {
355 $accumulator = ':' . $variant;
356 } else {
357 $accumulator .= ',' . $variant;
358 }
359
360 return $accumulator;
361 },
362 ''
363 );
364 }
365 }
366 }
367
368 return trim( $family_url, ';' );
369 }
370
371 /**
372 * Build typography style
373 *
374 * @param int $post_id
375 * @param boolean $is_editor
376 * @return string
377 */
378 private function get_typography_style( $post_id = 0, $is_editor = false ) {
379 $typography = $this->get_custom_typography( $post_id );
380
381 if ( ! $typography ) {
382 return;
383 }
384
385 $body = $this->get_typography_style_by_type( 'body', $typography['body'] ?? [], $is_editor );
386 $headings = $this->get_typography_style_by_type( 'headings', $typography['headings'] ?? [], $is_editor );
387
388 if ( $is_editor ) {
389 $style = '.editor-styles-wrapper {' . $body['vars'] . $headings['vars'] . '}';
390 } else {
391 $style = ':root {' . $body['vars'] . $headings['vars'] . '}';
392 }
393 $style .= $body['style'] . $headings['style'];
394
395 return $style;
396 }
397
398 /**
399 * Build CSS variables and style by type
400 *
401 * @param string $type
402 * @param array $type_values
403 * @param boolean $is_editor
404 * @return array
405 */
406 private function get_typography_style_by_type( $type, $type_values, $is_editor = false ) {
407 $type_styles = [];
408 $type_vars = [];
409
410 if ( empty( $type_values ) ) {
411 return [
412 'vars' => '',
413 'style' => '',
414 ];
415 }
416
417 $editor_selector = '.editor-styles-wrapper .is-root-container';
418 $frontend_selector = '.has-boldblocks-typography';
419
420 $font_family = '--cbb--' . $type . '--font-family';
421 $type_styles[] = '.' . $type . '-font-family { font-family: var(' . $font_family . ') !important; }';
422
423 if ( 'headings' !== $type ) {
424 $selector = $type === 'body' ? 'body' : '.' . $type;
425 if ( $is_editor ) {
426 $selector = 'body' === $type ? "{$editor_selector}, {$editor_selector} p" : "{$editor_selector} ." . $type;
427 } else {
428 $selector = 'body' === $type ? "{$selector}, {$frontend_selector} p" : "{$frontend_selector} {$selector}";
429 }
430 $type_styles[] = $selector . ' {';
431 if ( $type_values['fontFamily'] ?? '' ) {
432 $type_vars[] = $font_family . ': "' . $type_values['fontFamily'] . '", ' . ( $type_values['genericFamily'] ?? 'sans-serif' ) . ';';
433 $type_styles[] = 'font-family: var(' . $font_family . ');';
434 }
435
436 $type_styles[] = '}';
437 } else {
438 if ( $type_values['fontFamily'] ?? '' ) {
439 if ( $is_editor ) {
440 $type_styles[] = ".editor-styles-wrapper .wp-block.wp-block-post-title, {$editor_selector} h1, {$editor_selector} .h1, {$editor_selector} h2, {$editor_selector} .h2, {$editor_selector} h3, {$editor_selector} .h3, {$editor_selector} h4, {$editor_selector} .h4, {$editor_selector} h5, {$editor_selector} .h5, {$editor_selector} h6, {$editor_selector} .h6 {";
441 } else {
442 $type_styles[] = "{$frontend_selector} h1,{$frontend_selector} .h1,{$frontend_selector} h2,{$frontend_selector} .h2,{$frontend_selector} h3,{$frontend_selector} .h3,{$frontend_selector} h4,{$frontend_selector} .h4,{$frontend_selector} h5,{$frontend_selector} .h5,{$frontend_selector} h6,{$frontend_selector} .h6 {";
443 }
444 $type_vars[] = $font_family . ':"' . $type_values['fontFamily'] . '", ' . ( $type_values['genericFamily'] ?? 'sans-serif' ) . ';';
445 $type_styles[] = 'font-family: var(' . $font_family . ');';
446 $type_styles[] = '} ';
447 }
448 }
449
450 return [
451 'vars' => \implode( '', $type_vars ),
452 'style' => \implode( '', $type_styles ),
453 ];
454 }
455
456 /**
457 * Check whether current site support custom typography
458 *
459 * @param int $post_id
460 * @return mixed
461 */
462 private function get_custom_typography( $post_id = 0 ) {
463 $enable_typography = get_option( 'boldblocks_enable_typography' );
464
465 if ( ! $enable_typography ) {
466 return false;
467 }
468
469 $typography_raw = $post_id > 0 ? get_post_meta( $post_id, 'boldblocks_typography', true ) : false;
470 if ( empty( $typography_raw ) || ! is_array( $typography_raw ) || empty( $typography_raw['fonts'] ) ) {
471 $typography_raw = \get_option( 'boldblocks_typography' );
472 }
473
474 if ( ! is_array( $typography_raw ) || empty( $typography_raw['fonts'] ) ) {
475 return;
476 }
477
478 $fonts = $typography_raw ? \json_decode( $typography_raw['fonts'], true ) : '';
479
480 if ( empty( $fonts ) ) {
481 return;
482 }
483
484 return $fonts;
485 }
486
487 /**
488 * Add a custom css class to body for typography
489 *
490 * @param array $classes
491 * @return string
492 */
493 public function add_typography_to_body_class( $classes ) {
494 $enable_typography = get_option( 'boldblocks_enable_typography' );
495
496 if ( $enable_typography ) {
497 $classes[] = 'has-boldblocks-typography';
498 }
499
500 return $classes;
501 }
502 }
503 endif;
504