PluginProbe
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts / 2.7.8
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts v2.7.8
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.8, at includes/typography.php

506 lines 14.3 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 // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
220 wp_enqueue_style( 'boldblocks-custom-fonts', $prefix . $service_url . $fonts_url, [], null );
221
222 $typography_style = $this->get_typography_style( $post_id, $is_editor );
223 wp_add_inline_style( 'boldblocks-custom-fonts', $typography_style );
224
225 if ( $is_editor ) {
226 $wp_styles = wp_styles();
227 $custom_blocks = $wp_styles->query( $this->the_plugin_instance->get_component( CustomBlocks::class )->custom_blocks_handle, 'registered' );
228
229 if ( $custom_blocks ) {
230 $custom_blocks->deps[] = 'boldblocks-custom-fonts';
231 }
232 }
233 }
234 }
235
236 /**
237 * Add preconnect for font service.
238 *
239 * @param array $urls URLs to print for resource hints.
240 * @param string $relation_type The relation type the URLs are printed.
241 * @return array $urls URLs to print for resource hints.
242 */
243 public function preconnect_fonts( $urls, $relation_type ) {
244 if ( wp_style_is( 'boldblocks-custom-fonts', 'queue' ) && 'preconnect' === $relation_type ) {
245 $use_bunny_fonts = get_option( 'boldblocks_use_bunny_fonts' );
246
247 $urls[] = array(
248 'href' => $use_bunny_fonts ? '//fonts.bunny.net' : '//fonts.gstatic.com',
249 'crossorigin',
250 );
251 }
252
253 return $urls;
254 }
255
256 /**
257 * Add preload for fonts.
258 *
259 * @return void
260 */
261 public function preload_fonts() {
262 $wp_styles = wp_styles();
263 $style = $wp_styles->query( 'boldblocks-custom-fonts', 'registered' );
264
265 if ( $style ) {
266 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
267 echo "<link rel='preload' as='style' href='{$style->src}'/>";
268 }
269 }
270
271 /**
272 * Load google fonts
273 *
274 * @param int $post_id
275 * @param boolean $use_bunny_fonts
276 * @return void
277 */
278 private function get_fonts_url( $post_id, $use_bunny_fonts ) {
279 $typography = $this->get_custom_typography( $post_id );
280
281 if ( ! $typography ) {
282 return;
283 }
284
285 $family_urls = [];
286
287 $body = $typography['body'] ?? [];
288 $body_font_family = $body['fontFamily'] ?? '';
289 $body_font_variants = $body['fontVariants'] ?? [];
290
291 $body_font_url = $this->get_font_url( $body_font_family, $body_font_variants, $use_bunny_fonts );
292 if ( $body_font_url ) {
293 $family_urls[] = $body_font_url;
294 }
295
296 $headings = $typography['headings'] ?? [];
297 $headings_font_family = $headings['fontFamily'] ?? '';
298 $headings_font_variants = $headings['fontVariants'] ?? [];
299
300 $headings_font_url = $this->get_font_url( $headings_font_family, $headings_font_variants, $use_bunny_fonts );
301 if ( $headings_font_url ) {
302 $family_urls[] = $headings_font_url;
303 }
304
305 if ( count( $family_urls ) > 0 ) {
306 $glue = $use_bunny_fonts ? '|' : '&';
307 return implode( $glue, $family_urls ) . '&display=swap';
308 }
309
310 return;
311 }
312
313 /**
314 * Get font url
315 *
316 * @param string $font_family
317 * @param array $font_variants
318 * @param boolean $use_bunny_fonts
319 * @return string
320 */
321 private function get_font_url( $font_family, $font_variants, $use_bunny_fonts ) {
322 $family_url = '';
323
324 if ( $font_family ) {
325 $family_url = $use_bunny_fonts ? \str_replace( ' ', '+', $font_family ) : 'family=' . \str_replace( ' ', '+', $font_family );
326 if ( $font_variants ) {
327 if ( ! $use_bunny_fonts ) {
328 usort(
329 $font_variants,
330 function( $val1, $val2 ) {
331 $val1_has_italic = strpos( $val1, 'italic' ) !== false;
332 $val2_has_italic = strpos( $val2, 'italic' ) !== false;
333
334 if ( $val1_has_italic && ! $val2_has_italic ) {
335 return 1;
336 } elseif ( ! $val1_has_italic && $val2_has_italic ) {
337 return -1;
338 }
339
340 return strcmp( $val1, $val2 );
341 }
342 );
343 $family_url .= ':ital,wght@';
344 foreach ( $font_variants as $variant ) {
345 if ( strpos( $variant, 'italic' ) === false ) {
346 $family_url .= '0,' . $variant . ';';
347 } else {
348 $family_url .= '1,' . str_replace( 'italic', '', $variant ) . ';';
349 }
350 }
351 } else {
352 $family_url .= array_reduce(
353 $font_variants,
354 function ( $accumulator, $item ) {
355 $variant = \str_replace( 'italic', 'i', $item );
356 if ( empty( $accumulator ) ) {
357 $accumulator = ':' . $variant;
358 } else {
359 $accumulator .= ',' . $variant;
360 }
361
362 return $accumulator;
363 },
364 ''
365 );
366 }
367 }
368 }
369
370 return trim( $family_url, ';' );
371 }
372
373 /**
374 * Build typography style
375 *
376 * @param int $post_id
377 * @param boolean $is_editor
378 * @return string
379 */
380 private function get_typography_style( $post_id = 0, $is_editor = false ) {
381 $typography = $this->get_custom_typography( $post_id );
382
383 if ( ! $typography ) {
384 return;
385 }
386
387 $body = $this->get_typography_style_by_type( 'body', $typography['body'] ?? [], $is_editor );
388 $headings = $this->get_typography_style_by_type( 'headings', $typography['headings'] ?? [], $is_editor );
389
390 if ( $is_editor ) {
391 $style = '.editor-styles-wrapper {' . $body['vars'] . $headings['vars'] . '}';
392 } else {
393 $style = ':root {' . $body['vars'] . $headings['vars'] . '}';
394 }
395 $style .= $body['style'] . $headings['style'];
396
397 return $style;
398 }
399
400 /**
401 * Build CSS variables and style by type
402 *
403 * @param string $type
404 * @param array $type_values
405 * @param boolean $is_editor
406 * @return array
407 */
408 private function get_typography_style_by_type( $type, $type_values, $is_editor = false ) {
409 $type_styles = [];
410 $type_vars = [];
411
412 if ( empty( $type_values ) ) {
413 return [
414 'vars' => '',
415 'style' => '',
416 ];
417 }
418
419 $editor_selector = '.editor-styles-wrapper .is-root-container';
420 $frontend_selector = '.has-boldblocks-typography';
421
422 $font_family = '--cbb--' . $type . '--font-family';
423 $type_styles[] = '.' . $type . '-font-family { font-family: var(' . $font_family . ') !important; }';
424
425 if ( 'headings' !== $type ) {
426 $selector = $type === 'body' ? 'body' : '.' . $type;
427 if ( $is_editor ) {
428 $selector = 'body' === $type ? "{$editor_selector}, {$editor_selector} p" : "{$editor_selector} ." . $type;
429 } else {
430 $selector = 'body' === $type ? "{$selector}, {$frontend_selector} p" : "{$frontend_selector} {$selector}";
431 }
432 $type_styles[] = $selector . ' {';
433 if ( $type_values['fontFamily'] ?? '' ) {
434 $type_vars[] = $font_family . ': "' . $type_values['fontFamily'] . '", ' . ( $type_values['genericFamily'] ?? 'sans-serif' ) . ';';
435 $type_styles[] = 'font-family: var(' . $font_family . ');';
436 }
437
438 $type_styles[] = '}';
439 } else {
440 if ( $type_values['fontFamily'] ?? '' ) {
441 if ( $is_editor ) {
442 $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 {";
443 } else {
444 $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 {";
445 }
446 $type_vars[] = $font_family . ':"' . $type_values['fontFamily'] . '", ' . ( $type_values['genericFamily'] ?? 'sans-serif' ) . ';';
447 $type_styles[] = 'font-family: var(' . $font_family . ');';
448 $type_styles[] = '} ';
449 }
450 }
451
452 return [
453 'vars' => \implode( '', $type_vars ),
454 'style' => \implode( '', $type_styles ),
455 ];
456 }
457
458 /**
459 * Check whether current site support custom typography
460 *
461 * @param int $post_id
462 * @return mixed
463 */
464 private function get_custom_typography( $post_id = 0 ) {
465 $enable_typography = get_option( 'boldblocks_enable_typography' );
466
467 if ( ! $enable_typography ) {
468 return false;
469 }
470
471 $typography_raw = $post_id > 0 ? get_post_meta( $post_id, 'boldblocks_typography', true ) : false;
472 if ( empty( $typography_raw ) || ! is_array( $typography_raw ) || empty( $typography_raw['fonts'] ) ) {
473 $typography_raw = \get_option( 'boldblocks_typography' );
474 }
475
476 if ( ! is_array( $typography_raw ) || empty( $typography_raw['fonts'] ) ) {
477 return;
478 }
479
480 $fonts = $typography_raw ? \json_decode( $typography_raw['fonts'], true ) : '';
481
482 if ( empty( $fonts ) ) {
483 return;
484 }
485
486 return $fonts;
487 }
488
489 /**
490 * Add a custom css class to body for typography
491 *
492 * @param array $classes
493 * @return string
494 */
495 public function add_typography_to_body_class( $classes ) {
496 $enable_typography = get_option( 'boldblocks_enable_typography' );
497
498 if ( $enable_typography ) {
499 $classes[] = 'has-boldblocks-typography';
500 }
501
502 return $classes;
503 }
504 }
505 endif;
506