PluginProbe
Customify / 2.3.3
Customify v2.3.3
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.3, at features/class-Font_Selector.php

658 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, $active_font_family, '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( $this->theme_fonts[ $value['font_family'] ] ) ) {
180
181 // $value['type'] = 'theme_font';
182 // $args['local_srcs'] .= $this->theme_fonts[ $value['font_family'] ]['src'] . ',';
183 // $value['variants'] = $this->theme_fonts[ $value['font_family'] ]['variants'];
184
185 if ( false === array_search( $value['font_family'], $args['local_families'] ) ) {
186 $args['local_families'][] = "'" . $value['font_family'] . "'";
187 }
188
189 if ( false === array_search( $this->theme_fonts[ $value['font_family'] ]['src'], $args['local_srcs'] ) ) {
190 $args['local_srcs'][] = "'" . $this->theme_fonts[ $value['font_family'] ]['src'] . "'";
191 }
192 } elseif ( isset( $value['font_family'] ) && isset( $value['type'] ) && $value['type'] === 'google' ) {
193 $family = "'" . $value['font_family'];
194
195 if ( $load_all_weights && ! empty( $value['variants'] ) && is_array( $value['variants'] ) ) {
196 $family .= ":" . implode( ',', $value['variants'] );
197 } elseif ( ! empty( $value['selected_variants'] ) ) {
198 if ( is_array( $value['selected_variants'] ) ) {
199 $family .= ":" . implode( ',', $value['selected_variants'] );
200 } elseif ( is_string( $value['selected_variants'] ) || is_numeric( $value['selected_variants'] ) ) {
201 $family .= ":" . $value['selected_variants'];
202 }
203 } elseif ( ! empty( $value['variants'] ) ) {
204 if ( is_array( $value['variants'] ) ) {
205 $family .= ":" . implode( ',', $value['variants'] );
206 } else {
207 $family .= ":" . $value['variants'];
208 }
209 }
210
211 if ( ! empty( $value['selected_subsets'] ) ) {
212 if ( is_array( $value['selected_subsets'] ) ) {
213 $family .= ":" . implode( ',', $value['selected_subsets'] );
214 } else {
215 $family .= ":" . $value['selected_subsets'];
216 }
217 } elseif ( ! empty( $value['subsets'] ) ) {
218 if ( is_array( $value['subsets'] ) ) {
219 $family .= ":" . implode( ',', $value['subsets'] );
220 } else {
221 $family .= ":" . $value['subsets'];
222 }
223 }
224
225 $family .= "'";
226
227 $args['google_families'][] = $family;
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 function customify_font_loader() {
519 var webfontargs = {
520 classes: false,
521 events: false
522 };
523 <?php if ( ! empty( $args['google_families'] ) ) { ?>
524 webfontargs.google = {
525 families: [<?php echo join( ',', $args['google_families'] ); ?>]
526 };
527 <?php }
528 if ( ! empty( $args['local_families'] ) && ! empty( $args['local_srcs'] ) ) { ?>
529 webfontargs.custom = {
530 families: [<?php echo join( ',', $args['local_families'] ); ?>],
531 urls: [<?php echo join( ',', $args['local_srcs'] ) ?>]
532 };
533 <?php } ?>
534 WebFont.load(webfontargs);
535 };
536
537 if (typeof WebFont !== 'undefined') {
538 customify_font_loader();
539 } else {
540 var tk = document.createElement('script');
541 tk.src = '//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
542 tk.type = 'text/javascript';
543
544 tk.onload = tk.onreadystatechange = function () {
545 customify_font_loader();
546 };
547
548 var s = document.getElementsByTagName('script')[0];
549 s.parentNode.insertBefore(tk, s);
550 }
551 <?php
552 $output = ob_get_clean();
553
554 return apply_filters( 'customify_fonts_webfont_script', $output );
555 }
556
557 function get_field_unit( $font, $field ) {
558
559 if ( empty( $font ) || empty( $font['fields'] ) || empty( $font['fields'][ $field ] ) ) {
560 return 'px';
561 }
562
563 if ( isset( $font['fields'][ $field ]['unit'] ) ) {
564 return $font['fields'][ $field ]['unit'];
565 }
566
567 if ( isset( $font['fields'][ $field ][3] ) ) {
568 return $font['fields'][ $field ][3];
569 }
570
571 return 'px';
572 }
573
574 function validate_font_values( $values ) {
575
576 if ( empty( $values ) ) {
577 return array();
578 }
579
580 foreach ( $values as $key => $value ) {
581
582 if ( strpos( $key, '-' ) !== false ) {
583 $new_key = str_replace( '-', '_', $key );
584
585 $values[ $new_key ] = $value;
586
587 unset( $values[ $key ] );
588 }
589 }
590
591 return $values;
592 }
593
594 function display_selector( $selector ) {
595
596 }
597
598 function display_property( $property, $value, $unit = '' ) {
599 echo $property . ": " . $value . $unit . ";\n";
600 }
601
602 // well weight sometimes comes from google as 600italic which in CSS syntax should come in two separate properties
603 function display_weight_property( $value ) {
604 $has_style = false;
605
606 if ( strpos( $value, 'italic' ) !== false ) {
607
608 $value = str_replace( 'italic', '', $value );
609 echo 'font-weight' . ": " . $value . ";\n";
610 echo 'font-style' . ": italic;\n";
611 $has_style = true;
612 } else {
613 echo 'font-weight' . ": " . $value . ";\n";
614 }
615
616
617 return $has_style;
618 }
619
620 /**
621 * Main Customify_Font_Selector Instance
622 *
623 * Ensures only one instance of Customify_Font_Selector is loaded or can be loaded.
624 *
625 * @since 1.0.0
626 * @static
627 *
628 * @return Customify_Font_Selector Main Customify_Font_Selector instance
629 */
630 public static function instance() {
631
632 if ( is_null( self::$_instance ) ) {
633 self::$_instance = new self();
634 }
635 return self::$_instance;
636 } // End instance ()
637
638 /**
639 * Cloning is forbidden.
640 *
641 * @since 1.0.0
642 */
643 public function __clone() {
644
645 _doing_it_wrong( __FUNCTION__,esc_html( __( 'Cheatin&#8217; huh?' ) ), '' );
646 } // End __clone ()
647
648 /**
649 * Unserializing instances of this class is forbidden.
650 *
651 * @since 1.0.0
652 */
653 public function __wakeup() {
654
655 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cheatin&#8217; huh?' ) ), '' );
656 } // End __wakeup ()
657 }
658