PluginProbe
Customify / 2.3.0
Customify v2.3.0
2.10.9 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.7.1 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.0.1 1.6.5 1.7.0 1.7.1 All 77 releases
customify / features / class-Font_Selector.php

class-Font_Selector.php in Customify 2.3.0, at features/class-Font_Selector.php

656 lines 19.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Customify_Font_Selector {
4
5 /**
6 * Instance of this class.
7 * @since 1.0.0
8 * @var object
9 */
10 protected static $_instance = null;
11
12 protected static $typo_settings = null;
13 protected static $options_list = null;
14 protected $theme_fonts = null;
15 protected $customify_CSS_output = array();
16
17
18 function __construct() {
19 $this->theme_fonts = apply_filters( 'customify_theme_fonts', array() );
20
21 $load_location = PixCustomifyPlugin()->get_plugin_setting( 'style_resources_location', 'wp_head' );
22 add_action( $load_location, array( $this, 'output_webfont_script' ), 99 );
23 add_action( $load_location, array( $this, 'output_fonts_dynamic_style' ), 100 );
24 add_action( 'customify_font_family_before_options', array( $this, 'add_customify_theme_fonts' ), 11, 2 );
25
26 if ( PixCustomifyPlugin()->get_plugin_setting( 'enable_editor_style', true ) ) {
27 add_action( 'admin_head', array( $this, 'script_to_add_customizer_settings_into_wp_editor' ) );
28 }
29
30 }
31
32 function script_to_add_customizer_settings_into_wp_editor() {
33
34 ob_start();
35 $this->output_fonts_dynamic_style();
36
37 $custom_css = ob_get_clean();
38
39 ob_start(); ?>
40 (function ($) {
41 $(window).load(function () {
42 /**
43 * @param iframe_id the id of the frame you want to append the style
44 * @param style_element the style element you want to append
45 */
46 var append_script_to_iframe = function (ifrm_id, scriptEl) {
47 var myIframe = document.getElementById(ifrm_id);
48
49 var script = myIframe.contentWindow.document.createElement("script");
50 script.type = "text/javascript";
51 script.innerHTML = scriptEl.innerHTML;
52
53 myIframe.contentWindow.document.head.appendChild(script);
54 };
55
56 var append_style_to_iframe = function (ifrm_id, styleElment) {
57 var ifrm = window.frames[ifrm_id];
58 if ( typeof ifrm === "undefined" ) {
59 return;
60 }
61 ifrm = ( ifrm.contentDocument || ifrm.document );
62 var head = ifrm.getElementsByTagName('head')[0];
63
64 if (typeof styleElment !== "undefined") {
65 head.appendChild(styleElment);
66 }
67 };
68
69 var xmlString = <?php echo json_encode( str_replace( "\n", "", $custom_css ) ); ?>,
70 parser = new DOMParser(),
71 doc = parser.parseFromString(xmlString, "text/html");
72
73 if (typeof window.frames['content_ifr'] !== 'undefined') {
74
75 $.each(doc.head.childNodes, function (key, el) {
76 if (typeof el !== "undefined" && typeof el.tagName !== "undefined") {
77
78 switch (el.tagName) {
79 case 'STYLE' :
80 append_style_to_iframe('content_ifr', el);
81 break;
82 case 'SCRIPT' :
83 append_script_to_iframe('content_ifr', el);
84 break;
85 default:
86 break;
87 }
88 }
89 });
90 }
91 });
92 })(jQuery);
93 <?php
94 $script = ob_get_clean();
95 wp_add_inline_script( 'editor', $script );
96 }
97
98 public function get_theme_fonts() {
99 return $this->theme_fonts;
100 }
101
102 function add_customify_theme_fonts( $active_font_family, $val ) {
103 //first get all the published custom fonts
104 if ( empty( $this->theme_fonts ) ) {
105 return;
106 }
107
108 echo '<optgroup label="' . esc_html__( 'Theme Fonts', 'customify' ) . '">';
109 foreach ( $this->theme_fonts as $font ) {
110 if ( ! empty( $font ) ) {
111 //display the select option's HTML
112 Pix_Customize_Font_Control::output_font_option( $font['family'], $active_font_family, $font, 'theme_font' );
113 }
114 }
115 echo "</optgroup>";
116 }
117
118 function maybe_decode_value( $value ) {
119
120 $to_return = PixCustomifyPlugin::decodeURIComponent( $value );
121 if ( is_string( $value ) ) {
122 $to_return = json_decode( wp_unslash( $to_return ), true );
123 }
124
125 return $to_return;
126 }
127
128 protected function get_fonts_args() {
129
130 $args = array(
131 'google_families' => array(),
132 'local_families' => array(),
133 'local_srcs' => array(),
134 );
135
136 /** @var PixCustomifyPlugin $local_plugin */
137 $local_plugin = PixCustomifyPlugin();
138
139 self::$options_list = $local_plugin->get_options();
140
141 $local_plugin->get_typography_fields( self::$options_list, 'type', 'font', self::$typo_settings );
142
143 if ( empty( self::$typo_settings ) ) {
144 return $args;
145 }
146
147 foreach ( self::$typo_settings as $id => $font ) {
148 if ( isset ( $font['value'] ) ) {
149
150 $load_all_weights = false;
151 if ( isset( $font['load_all_weights'] ) && $font['load_all_weights'] == 'true' ) {
152 $load_all_weights = true;
153 }
154
155 $value = $this->maybe_decode_value( $font['value'] );
156
157 $value = $this->validate_font_values( $value );
158
159 // in case the value is still null, try default value (mostly for google fonts)
160 if ( ! is_array( $value ) || $value === null ) {
161 $value = $local_plugin->get_font_defaults_value( str_replace( '"', '', $font['value'] ) );
162 }
163
164 //bail if by this time we don't have a value of some sort
165 if ( empty( $value ) ) {
166 continue;
167 }
168
169 // Handle special logic for when the $value array is not an associative array
170 if ( ! $local_plugin->is_assoc( $value ) ) {
171 $value = $local_plugin->standardize_non_associative_font_default( $value );
172 }
173
174 // If we have reached this far and we don't have a type, we will assume it's a google font.
175 if ( ! isset( $value['type'] ) ) {
176 $value['type'] = 'google';
177 }
178
179 if ( isset( $value['font_family'] ) && isset( $value['type'] ) && $value['type'] === 'google' ) {
180 $family = "'" . $value['font_family'];
181
182 if ( $load_all_weights && ! empty( $value['variants'] ) && is_array( $value['variants'] ) ) {
183 $family .= ":" . implode( ',', $value['variants'] );
184 } elseif ( ! empty( $value['selected_variants'] ) ) {
185 if ( is_array( $value['selected_variants'] ) ) {
186 $family .= ":" . implode( ',', $value['selected_variants'] );
187 } elseif ( is_string( $value['selected_variants'] ) || is_numeric( $value['selected_variants'] ) ) {
188 $family .= ":" . $value['selected_variants'];
189 }
190 } elseif ( ! empty( $value['variants'] ) ) {
191 if ( is_array( $value['variants'] ) ) {
192 $family .= ":" . implode( ',', $value['variants'] );
193 } else {
194 $family .= ":" . $value['variants'];
195 }
196 }
197
198 if ( ! empty( $value['selected_subsets'] ) ) {
199 if ( is_array( $value['selected_subsets'] ) ) {
200 $family .= ":" . implode( ',', $value['selected_subsets'] );
201 } else {
202 $family .= ":" . $value['selected_subsets'];
203 }
204 } elseif ( ! empty( $value['subsets'] ) ) {
205 if ( is_array( $value['subsets'] ) ) {
206 $family .= ":" . implode( ',', $value['subsets'] );
207 } else {
208 $family .= ":" . $value['subsets'];
209 }
210 }
211
212 $family .= "'";
213
214 $args['google_families'][] = $family;
215 } elseif ( isset( $this->theme_fonts[ $value['font_family'] ] ) ) {
216
217 // $value['type'] = 'theme_font';
218 // $args['local_srcs'] .= $this->theme_fonts[ $value['font_family'] ]['src'] . ',';
219 // $value['variants'] = $this->theme_fonts[ $value['font_family'] ]['variants'];
220
221 if ( false === strpos( $args['local_families'], $value['font_family'] ) ) {
222 $args['local_families'][] = "'" . $value['font_family'] . "'";
223 }
224
225 if ( false === strpos( $args['local_srcs'], $this->theme_fonts[ $value['font_family'] ]['src'] ) ) {
226 $args['local_srcs'][] = "'" . $this->theme_fonts[ $value['font_family'] ]['src'] . "'";
227 }
228 }
229 }
230 }
231
232 $args = array(
233 'google_families' => array_unique( $args['google_families'] ),
234 'local_families' => array_unique( $args['local_families'] ),
235 'local_srcs' => array_unique( $args['local_srcs'] ),
236 );
237
238 return $args;
239 }
240
241 function output_fonts_dynamic_style() {
242
243 /** @var PixCustomifyPlugin $local_plugin */
244 $local_plugin = PixCustomifyPlugin();
245
246 self::$options_list = $local_plugin->get_options();
247 $local_plugin->get_typography_fields( self::$options_list, 'type', 'font', self::$typo_settings );
248
249 if ( empty( self::$typo_settings ) ) {
250 return;
251 }
252
253 $output = '';
254
255 foreach ( self::$typo_settings as $key => $font ) {
256 $font_output = $this->get_font_style( $font );
257 if ( empty( $font_output ) ) {
258 continue;
259 }
260
261 $output .= $font_output . PHP_EOL;
262
263 // If we are in a Customizer context we will output CSS rules grouped so we can target them.
264 // In the frontend we want a whole bulk.
265 if ( isset( $GLOBALS['wp_customize'] ) ) { ?>
266 <style id="customify_font_output_for_<?php echo sanitize_html_class( $key ); ?>">
267 <?php echo $font_output; ?>
268 </style><?php
269 }
270 }
271
272 // in customizer the CSS is printed per option, in front-end we need to print them in bulk
273 if ( ! isset( $GLOBALS['wp_customize'] ) ) { ?>
274 <style id="customify_fonts_output">
275 <?php echo $output; ?>
276 </style><?php
277 }
278 }
279
280 function get_fonts_dynamic_style() {
281
282 $output = '';
283
284 /** @var PixCustomifyPlugin $local_plugin */
285 $local_plugin = PixCustomifyPlugin();
286
287 self::$options_list = $local_plugin->get_options();
288 $local_plugin->get_typography_fields( self::$options_list, 'type', 'font', self::$typo_settings );
289
290 if ( empty( self::$typo_settings ) ) {
291 return $output;
292 }
293
294 foreach ( self::$typo_settings as $key => $font ) {
295
296 $font_output = $this->get_font_style( $font );
297 if ( empty( $font_output ) ) {
298 continue;
299 }
300
301 $output .= $font_output . PHP_EOL;
302 }
303
304 return $output;
305 }
306
307 function get_font_style( $font ) {
308
309 if ( ! isset( $font['selector'] ) ) {
310 return '';
311 }
312
313 $font['selector'] = apply_filters( 'customify_font_css_selector', $font['selector'], $font );
314
315 if ( empty( $font['selector'] ) || empty( $font['value'] ) ) {
316 return '';
317 }
318
319 /** @var PixCustomifyPlugin $local_plugin */
320 $local_plugin = PixCustomifyPlugin();
321
322 $value = $this->maybe_decode_value( $font['value'] );
323
324 if ( $value === null ) {
325 $value = $local_plugin->get_font_defaults_value( $font['value'] );
326 }
327
328 // shim the old case when the default was only the font name
329 if ( is_string( $value ) && ! empty( $value ) ) {
330 $value = array( 'font_family' => $value );
331 }
332
333 // Handle special logic for when the $value array is not an associative array
334 if ( ! $local_plugin->is_assoc( $value ) ) {
335 $value = $local_plugin->standardize_non_associative_font_default( $value );
336 }
337
338 $value = $this->validate_font_values( $value );
339 // some sanitizing
340 $load_all_weights = false;
341 if ( isset( $font['load_all_weights'] ) && $font['load_all_weights'] == 'true' ) {
342 $load_all_weights = true;
343 }
344 $selected_variant = '';
345 if ( ! empty( $value['selected_variants'] ) ) {
346 if ( is_array( $value['selected_variants'] ) ) {
347 $selected_variant = $value['selected_variants'][0];
348 } else {
349 $selected_variant = $value['selected_variants'];
350 }
351 }
352
353 ob_start();
354
355 if ( isset( $font['callback'] ) && function_exists( $font['callback'] ) ) {
356 $output = call_user_func( $font['callback'], $value, $font );
357 echo $output;
358 } elseif ( isset( $font['selector'] ) ) {
359 echo $font['selector'] . " {" . PHP_EOL;
360
361 // First handle the case where we have the font-family in the selected variant (usually this means a custom font from our Fonto plugin)
362 if ( ! empty( $selected_variant ) && is_array( $selected_variant ) && ! empty( $selected_variant['font-family'] ) ) {
363 //the variant's font-family
364 $this->display_property( 'font-family', $selected_variant['font-family'] );
365
366 if ( ! $load_all_weights ) {
367 // if this is a custom font (like from our plugin Fonto) with individual styles & weights - i.e. the font-family says it all
368 // we need to "force" the font-weight and font-style
369 if ( ! empty( $value['type'] ) && 'custom_individual' == $value['type'] ) {
370 $selected_variant['font-weight'] = '400 !important';
371 $selected_variant['font-style'] = 'normal !important';
372 }
373
374 $italic_font = false;
375
376 // output the font weight, if available
377 if ( ! empty( $selected_variant['font-weight'] ) ) {
378 echo ": " . $selected_variant['font-weight'] . ";\n";
379 $italic_font = $this->display_weight_property( $selected_variant['font-weight'] );
380 }
381
382 // output the font style, if available and if it wasn't displayed already
383 if ( ! $italic_font && ! empty( $selected_variant['font-style'] ) ) {
384 $this->display_property( 'font-style', $selected_variant['font-style'] );
385 }
386 }
387
388 } elseif ( isset( $value['font_family'] ) ) {
389 // the selected font family
390 $this->display_property( 'font-family', $value['font_family'] );
391
392 if ( ! empty( $selected_variant ) && ! $load_all_weights ) {
393 $weight_and_style = strtolower( $selected_variant );
394 $italic_font = false;
395
396 //determine if this is an italic font (the $weight_and_style is usually like '400' or '400italic' )
397 if ( ! empty( $weight_and_style ) ) {
398 //a little bit of sanity check - in case it's not a number
399 if( $weight_and_style === 'regular' ) {
400 $weight_and_style = 'normal';
401 }
402 $italic_font = $this->display_weight_property( $weight_and_style );
403 }
404
405 // output the font style, if available
406 if ( ! $italic_font && ! empty( $selected_variant['font-style'] ) ) {
407 $this->display_property( 'font-style', $selected_variant['font-style'] );
408 }
409 }
410 } else if ( isset( $value['font-family'] ) ) {
411 $this->display_property( 'font-family', $value['font-family'] );
412 }
413
414 if ( ! empty( $value['font_weight'] ) ) {
415 $italic_font = $this->display_weight_property( $value['font_weight'] );
416 }
417
418 if ( ! empty( $value['font_size'] ) ) {
419 // If the value already contains a unit, go with that.
420 // We also handle receiving the value in a standardized format ( array with 'value' and 'unit').
421 $font_size = $value['font_size'];
422 $unit = '';
423 if ( is_numeric( $value['font_size'] ) ) {
424 $unit = $this->get_field_unit( $font, 'font-size' );
425 } elseif ( is_array( $value['font_size'] ) ) {
426 if ( isset( $value['font_size']['unit'] ) ) {
427 $unit = $value['font_size']['unit'];
428 }
429
430 if ( isset( $value['font_size']['value'] ) ) {
431 $font_size = $value['font_size']['value'];
432 }
433 }
434
435 if ( isset( $value['font_size']['unit'] ) && $value['font_size']['unit'] == 'em' && $value['font_size']['value'] >= 9 ) {
436 $value['font_size']['unit'] = 'px';
437 }
438
439 $this->display_property( 'font-size', $font_size, $unit );
440 }
441
442 if ( isset( $value['line_height'] ) ) {
443 // If the value already contains a unit, go with that.
444 // We also handle receiving the value in a standardized format ( array with 'value' and 'unit').
445 $line_height = $value['line_height'];
446 $unit = '';
447 if ( is_numeric( $value['line_height'] ) ) {
448 $unit = $this->get_field_unit( $font, 'line-height' );
449 } elseif ( is_array( $value['line_height'] ) ) {
450 if ( isset( $value['line_height']['unit'] ) ) {
451 $unit = $value['line_height']['unit'];
452 }
453
454 if ( isset( $value['line_height']['value'] ) ) {
455 $line_height = $value['line_height']['value'];
456 }
457 }
458
459 $this->display_property( 'line-height', $line_height, $unit );
460 }
461
462 if ( isset( $value['letter_spacing'] ) ) {
463 // If the value already contains a unit, go with that.
464 // We also handle receiving the value in a standardized format ( array with 'value' and 'unit').
465 $letter_spacing = $value['letter_spacing'];
466 $unit = '';
467 if ( is_numeric( $value['letter_spacing'] ) ) {
468 $unit = $this->get_field_unit( $font, 'letter-spacing' );
469 } elseif ( is_array( $value['letter_spacing'] ) ) {
470 if ( isset( $value['letter_spacing']['unit'] ) ) {
471 $unit = $value['letter_spacing']['unit'];
472 }
473
474 if ( isset( $value['letter_spacing']['value'] ) ) {
475 $letter_spacing = $value['letter_spacing']['value'];
476 }
477 }
478
479 $this->display_property( 'letter-spacing', $letter_spacing, $unit );
480 }
481
482 if ( ! empty( $value['text_align'] ) ) {
483 $this->display_property( 'text-align', $value['text_align'] );
484 }
485
486 if ( ! empty( $value['text_transform'] ) ) {
487 $this->display_property( 'text-transform', $value['text_transform'] );
488 }
489
490 if ( ! empty( $value['text_decoration'] ) ) {
491 $this->display_property( 'text-decoration', $value['text_decoration'] );
492 }
493 echo "}\n";
494 }
495
496 $CSS = ob_get_clean();
497
498 return $CSS;
499 }
500
501 function output_webfont_script() {
502 $script = $this->get_fonts_dynamic_script();
503 if ( ! empty( $script ) ) { ?>
504 <script type="text/javascript">
505 <?php echo $script; ?>
506 </script>
507 <?php }
508 }
509
510 function get_fonts_dynamic_script() {
511 $args = $this->get_fonts_args();
512
513 if ( ( empty ( $args['local_families'] ) && empty ( $args['google_families'] ) ) || ! PixCustomifyPlugin()->get_plugin_setting( 'typography', '1' ) || ! PixCustomifyPlugin()->get_plugin_setting( 'typography_google_fonts', 1 ) ) {
514 return '';
515 }
516
517 ob_start();
518 ?>
519 var customify_font_loader = function () {
520 var webfontargs = {
521 classes: false,
522 events: false
523 };
524 <?php if ( ! empty( $args['google_families'] ) ) { ?>
525 webfontargs.google = {families: [<?php echo join( ',', $args['google_families'] ); ?>]};
526 <?php }
527 if ( ! empty( $args['local_families'] ) && ! empty( $args['local_srcs'] ) ) { ?>
528 webfontargs.custom = {
529 families: [<?php echo join( ',', $args['local_families'] ); ?>],
530 urls: [<?php echo join( ',', $args['local_srcs'] ) ?>]
531 };
532 <?php } ?>
533 WebFont.load(webfontargs);
534 };
535
536 if (typeof WebFont !== 'undefined') { <?php // if there is a WebFont object, use it ?>
537 customify_font_loader();
538 } else { <?php // basically when we don't have the WebFont object we create the google script dynamically ?>
539 var tk = document.createElement('script');
540 tk.src = '//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
541 tk.type = 'text/javascript';
542
543 tk.onload = tk.onreadystatechange = function () {
544 customify_font_loader();
545 };
546 var s = document.getElementsByTagName('script')[0];
547 s.parentNode.insertBefore(tk, s);
548 }
549 <?php
550 $output = ob_get_clean();
551
552 return apply_filters( 'customify_fonts_webfont_script', $output );
553 }
554
555 function get_field_unit( $font, $field ) {
556
557 if ( empty( $font ) || empty( $font['fields'] ) || empty( $font['fields'][ $field ] ) ) {
558 return 'px';
559 }
560
561 if ( isset( $font['fields'][ $field ]['unit'] ) ) {
562 return $font['fields'][ $field ]['unit'];
563 }
564
565 if ( isset( $font['fields'][ $field ][3] ) ) {
566 return $font['fields'][ $field ][3];
567 }
568
569 return 'px';
570 }
571
572 function validate_font_values( $values ) {
573
574 if ( empty( $values ) ) {
575 return array();
576 }
577
578 foreach ( $values as $key => $value ) {
579
580 if ( strpos( $key, '-' ) !== false ) {
581 $new_key = str_replace( '-', '_', $key );
582
583 $values[ $new_key ] = $value;
584
585 unset( $values[ $key ] );
586 }
587 }
588
589 return $values;
590 }
591
592 function display_selector( $selector ) {
593
594 }
595
596 function display_property( $property, $value, $unit = '' ) {
597 echo $property . ": " . $value . $unit . ";\n";
598 }
599
600 // well weight sometimes comes from google as 600italic which in CSS syntax should come in two separate properties
601 function display_weight_property( $value ) {
602 $has_style = false;
603
604 if ( strpos( $value, 'italic' ) !== false ) {
605
606 $value = str_replace( 'italic', '', $value );
607 echo 'font-weight' . ": " . $value . ";\n";
608 echo 'font-style' . ": italic;\n";
609 $has_style = true;
610 } else {
611 echo 'font-weight' . ": " . $value . ";\n";
612 }
613
614
615 return $has_style;
616 }
617
618 /**
619 * Main Customify_Font_Selector Instance
620 *
621 * Ensures only one instance of Customify_Font_Selector is loaded or can be loaded.
622 *
623 * @since 1.0.0
624 * @static
625 *
626 * @return Customify_Font_Selector Main Customify_Font_Selector instance
627 */
628 public static function instance() {
629
630 if ( is_null( self::$_instance ) ) {
631 self::$_instance = new self();
632 }
633 return self::$_instance;
634 } // End instance ()
635
636 /**
637 * Cloning is forbidden.
638 *
639 * @since 1.0.0
640 */
641 public function __clone() {
642
643 _doing_it_wrong( __FUNCTION__,esc_html( __( 'Cheatin&#8217; huh?' ) ), '' );
644 } // End __clone ()
645
646 /**
647 * Unserializing instances of this class is forbidden.
648 *
649 * @since 1.0.0
650 */
651 public function __wakeup() {
652
653 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cheatin&#8217; huh?' ) ), '' );
654 } // End __wakeup ()
655 }
656