The full file reads as follows:
<?php class Cornerstone_Font_Manager extends Cornerstone_Plugin_Component { public $queue = array(); public $extend = array(); public $custom_css_output = ''; protected $font_items; protected $font_config; protected $loaded = array(); public function setup() { add_filter('cs_css_post_process_font-family', array( $this, 'css_post_process_font_family') ); add_filter('cs_css_post_process_font-weight', array( $this, 'css_post_process_font_weight') ); add_action( 'cornerstone_head_css', array( $this, 'output_typekit_loading_styles' ) ); add_action( 'x_head_css', array( $this, 'output_typekit_loading_styles' ) ); add_filter( 'wp_check_filetype_and_ext', array( $this, 'upload_check'), 10, 5 ); add_filter( 'upload_mimes', array( $this, 'upload_mimes' ), 999 ); add_action( 'wp_head', array( $this, 'load_initial_items'), 0 ); add_action( 'cs_head_late', array( $this, 'load_queued_fonts' ) ); add_action( 'wp_footer', array( $this, 'load_queued_fonts' ) ); } public function load_initial_items() { $items = $this->load_items(); $force = did_action('cs_before_preview_frame'); foreach ($items as $item) { if ($force || isset($item['force']) && $item['force']) { $this->queue_font( $item ); } } } public function get_extended() { return apply_filters('cs_fonts_extend', array() ); } public function default_font_items( $data = array() ) { return apply_filters('cornerstone_option_model_defaults_cornerstone_font_items', array( array( '_id' => bin2hex('Body Copy'), 'title' => csi18n( 'app.fonts.body-copy' ), 'family' => 'Helvetica', 'stack' => 'Helvetica, Arial, sans-serif', 'weights' => array( '300', '300i', '400', '400i', '700', '700i' ), 'source' => 'system' ), array( '_id' => bin2hex('Headings'), 'title' => csi18n( 'app.fonts.headings' ), 'family' => 'Helvetica', 'stack' => 'Helvetica, Arial, sans-serif', 'weights' => array( '300', '300i', '400', '400i', '700', '700i' ), 'source' => 'system' ), ) ); } public function get_fallback_font() { return array( 'family' => 'Helvetica', 'stack' => 'Helvetica, Arial, sans-serif', 'weights' => array( '400', '400i', '300', '300i', '700', '700i' ), // The first weight will be used when falling back 'source' => 'system' ); } public function get_font_items() { if ( ! $this->font_items ) { $this->font_items = $this->load_items(); } return $this->font_items; } public function get_font_config() { if ( ! $this->font_config ) { $this->font_config = $this->load_config(); } return $this->font_config; } protected function preload_config() { $preloaded = apply_filters('cs_preload_font_config', false ); if ($preloaded) { return $preloaded; } $saved = get_option( 'cornerstone_font_config' ); return ( is_null( $saved ) ) ? array() : json_decode( wp_unslash( $saved ), true ); } protected function load_config() { return wp_parse_args( $this->preload_config(), array( 'googleSubsets' => array(), 'typekitKitID' => '', 'customFontItems' => array(), 'customFontFaceCSS' => '', 'fontDisplay' => 'auto' ) ); } protected function load_items() { $preloaded = apply_filters('cs_preload_font_items', false ); if ($preloaded) { return $preloaded; } $stored = get_option( 'cornerstone_font_items' ); if ($stored === false ) { $stored = wp_slash( cs_json_encode( $this->default_font_items() ) ); update_option( 'cornerstone_font_items', $stored ); } return ( is_null( $stored ) ) ? array() : json_decode( wp_unslash( $stored ), true ); } protected function locate_font( $_id ) { $this->get_font_items(); foreach ($this->font_items as $font) { if ( isset( $font['_id'] ) && $_id === $font['_id'] ) { return $font; } } return array( 'family' => 'inherit', 'stack' => 'inherit', 'weights' => array( 'inherit' ), 'source' => 'system' ); } public function queue_font( $font ) { if ( 'system' === $font['source'] || 'extend' === $font['source'] ) { return; } if ( isset( $this->queue[$font['stack']] ) ) { $this->queue[$font['stack']]['weights'] = array_unique( array_merge( $this->queue[$font['stack']]['weights'], $font['weights'] ) ); } else { $this->queue[$font['stack']] = $font; } if ( ! isset( $this->queue[$font['stack']]['weights'] ) ) { $this->queue[$font['stack']]['weights'] = array(); } } protected function queue_font_weight( $font, $weight ) { $this->queue_font( $font ); if (isset($this->queue[$font['stack']]) && isset($this->queue[$font['stack']]['weights']) ) { if ( ! in_array($weight, $this->queue[$font['stack']]['weights'], true ) ) { $this->queue[$font['stack']]['weights'][] = $weight; $this->queue[$font['stack']]['weights'][] = $weight . 'i'; } } } public function css_post_process_font_family( $value ) { $font = $this->locate_font($value); $this->queue_font( $font ); return $font['stack']; } protected function normalize_weight( $value ) { return ( false === strpos($value, ':' ) ) ? 'inherit:' . $value : $value; } public function css_post_process_font_weight( $value ) { $value = $this->normalize_weight( $value ); $parts = explode(':', $value ); if ( 'inherit' === $parts[0] ) { return $parts[1]; } $font = $this->locate_font($parts[0]); $weight = ( in_array( $parts[1], $font['weights'], true ) ) ? $parts[1] : $font['weights'][0]; $this->queue_font_weight( $font, $weight ); return $weight; } public function load_queued_fonts() { if (count( array_keys( $this->queue ) ) <=0 ) { return; } $sources = array(); foreach ($this->queue as $font) { if ( ! isset( $font['source'] ) ) { continue; } if ( ! isset( $sources[$font['source'] ] ) ) { $sources[$font['source']] = array(); } $sources[$font['source']][] = array( 'family' => $font['family'], 'weights' => $font['weights'] ); } ksort($sources); do_action( 'cs_load_queued_fonts', $this->queue, $sources ); foreach ($sources as $source => $fonts) { $method = array( $this, "load_fonts_$source" ); if ( is_callable( $method ) ) { call_user_func_array( $method, array( $fonts ) ); } } $this->queue = array(); } public function load_fonts_google( $fonts ) { if ( ! apply_filters('cs_load_google_fonts', '__return_true' ) ) { return; } $in_footer = 'wp_footer' === current_action(); $config = apply_filters( 'cs_google_font_config', wp_parse_args($this->get_font_config(), array( 'googleSubsets' => array(), 'fontDisplay' => 'auto' ) ) ); $subsets = array_merge( array('latin', 'latin-ext'), $config['googleSubsets'] ); $subsets = array_unique($subsets); $family_strings = array(); foreach ($fonts as $font) { $weights = array_unique( $font['weights'] ); $to_load = str_replace(' ', '+', $font['family'] ) . ':' . implode(',', $weights ); if ( ! isset( $this->loaded[$to_load] ) ) { $family_strings[] = $to_load; $this->loaded[$to_load] = true; } } if ( count($family_strings) <=0 ) { return; } $request = esc_url( add_query_arg( array( 'family' => implode('%7C', $family_strings), //Was | (pipe), but %7C is required for W3C Markup validation, this is also more optimized than using urlencoder 'subset' => implode(',', $subsets ), 'display' => $config['fontDisplay'] ), apply_filters('cs_google_fonts_uri', '//fonts.googleapis.com/css' ) ) ); $atts = cs_atts( array( 'rel' => 'stylesheet', 'href' => apply_filters( 'cs_google_fonts_href', $request ), 'type' => 'text/css', 'media' => 'all', 'data-x-google-fonts' => null, ) ); $output = ""; if ( $in_footer ) { $output = $this->late_google_font_script( $output ); } echo $output; } public function late_google_font_script( $output ) { ob_start(); ?> <?php return ob_get_clean(); } public function load_fonts_typekit( $fonts ) { add_action( did_action('cs_head_late_after') ? 'wp_footer' : 'cs_head_late_after', array( $this, 'output_typekit_script') ); } public function load_fonts_custom( $fonts ) { $config = apply_filters( 'cs_custom_font_config', wp_parse_args($this->get_font_config(), array( 'customFontItems' => array(), 'fontDisplay' => 'auto' ) ) ); $load = array(); $buffer = ''; foreach ($fonts as $font) { $load[] = $font['family']; } foreach ($config['customFontItems'] as $item) { if (in_array($item['family'], $load)) { $buffer .= $this->make_custom_font_css( $item, $config ); } } if ( $buffer ) { CS()->component( 'Styling' )->add_styles( 'cs-custom-fonts', $buffer ); } } public function identify_custom_font_variants( $item ) { $variants = []; $variant_config = []; foreach ($item['files'] as $file) { $key = $file['weight'] . ':' . $file['style']; if ( ! isset( $variants[ $key ] ) ) { $variant_config[$key] = [ esc_attr($file['weight']), esc_attr($file['style']) ]; $variants[ $key ] = []; } $file_parts = explode( '.', $file['filename']); $format = array_pop( $file_parts ); if ($format) { $variants[ $key ][] = [esc_attr($file['url']), $this->normalize_format( $format)]; } } return [$variants, $variant_config]; } public function normalize_format( $format ) { switch ($format) { case 'ttf': return "format('truetype')"; case 'otf': return "format('opentype')"; case 'woff': return "format('woff')"; case 'woff2': return "format('woff2')"; } return ""; } public function make_custom_font_css( $item, $config ) { list( $variants, $variant_config ) = $this->identify_custom_font_variants( $item ); $family = isset($item['stack']) ? $item['stack'] : $item['family']; $display = esc_attr( $config['fontDisplay'] ); $buffer = ''; foreach ($variants as $key => $variant_files) { list($weight, $style) = $variant_config[$key]; $sources = []; foreach ($variant_files as $file) { list($url, $format) = $file; $sources[] = "url('$url') $format"; } $sources = implode(', ', $sources); $buffer .= "@font-face { font-family: $family; font-display: $display; src: $sources; font-weight: $weight; font-style: $style; }"; } return $buffer; } public function output_typekit_script() { $config = $this->get_font_config(); if ( ! $config['typekitKitID'] ) { return; } ?> <?php } public function output_typekit_loading_styles() { $config = $this->get_font_config(); if ( ! $config['typekitKitID'] ) { return; } echo '.wf-loading a, .wf-loading p, .wf-loading ul, .wf-loading ol, .wf-loading dl, .wf-loading h1, .wf-loading h2, .wf-loading h3, .wf-loading h4, .wf-loading h5, .wf-loading h6, .wf-loading em, .wf-loading pre, .wf-loading cite, .wf-loading span, .wf-loading table, .wf-loading strong, .wf-loading blockquote { visibility: hidden !important; }'; } public function item_permissions( $value, $operation ) { $permissions = $this->plugin->component('App_Permissions'); if ( 'update' === $operation ) { return $permissions->user_can('fonts.create') || $permissions->user_can('fonts.change') || $permissions->user_can('fonts.rename'); } if ( 'delete' === $operation ) { return $permissions->user_can('fonts.delete'); } return true; } public function config_permissions( $value, $operation ) { $permissions = $this->plugin->component('App_Permissions'); if ( 'update' === $operation ) { return $permissions->user_can('fonts.manage-google') || $permissions->user_can('fonts.manage-adobe-fonts'); } return 'delete' !== $operation; } public function upload_check( $result, $file, $filename, $mimes, $real_mime ) { $mime_types = $this->mime_types(); $parts = explode( '.', $filename); $ext = end($parts); if ( isset($mime_types[$ext]) && false !== strpos( $mime_types[$ext], $real_mime ) ) { $ext_mime_types = explode('|', $mime_types[$ext]); $result['ext'] = $ext; $result['type'] = array_shift( $ext_mime_types ); } return $result; } public function upload_mimes( $mime_types ) { $new_types = $this->mime_types(); foreach ($new_types as $ext => $type) { if (! isset($mime_types[$ext])) { $mime_types[$ext] = $type; } } return $mime_types; } public function mime_types() { return apply_filters( 'cs_font_manager_mime_types', array( 'woff2' => 'font/woff2|application/octet-stream', 'woff' => 'font/woff|application/font/woff|application/font-woff|application/octet-stream', 'ttf' => 'font/sfnt|application/x-font-ttf' ) ); } public function get_app_data() { return array( 'fontItems' => $this->get_font_items(), 'fontConfig' => $this->get_font_config(), 'customFontMimeTypes' => $this->mime_types(), 'fallbackFont' => $this->get_fallback_font(), 'extend' => $this->get_extended() ); } }