class-kirki-fonts-google.php (9528B)
1 <?php 2 /** 3 * Processes typography-related fields 4 * and generates the google-font link. 5 * 6 * @package Kirki 7 * @category Core 8 * @author Aristeides Stathopoulos 9 * @copyright Copyright (c) 2016, Aristeides Stathopoulos 10 * @license http://opensource.org/licenses/https://opensource.org/licenses/MIT 11 * @since 1.0 12 */ 13 14 if ( ! class_exists( 'Kirki_Fonts_Google' ) ) { 15 16 /** 17 * Manages the way Google Fonts are enqueued. 18 */ 19 final class Kirki_Fonts_Google { 20 21 /** 22 * The Kirki_Fonts_Google instance. 23 * We use the singleton pattern here to avoid loading the google-font array multiple times. 24 * This is mostly a performance tweak. 25 * 26 * @access private 27 * @var null|object 28 */ 29 private static $instance = null; 30 31 /** 32 * If set to true, forces loading ALL variants. 33 * 34 * @static 35 * @access public 36 * @var bool 37 */ 38 public static $force_load_all_variants = false; 39 40 /** 41 * If set to true, forces loading ALL subsets. 42 * 43 * @static 44 * @access public 45 * @var bool 46 */ 47 public static $force_load_all_subsets = false; 48 49 /** 50 * The array of fonts 51 * 52 * @access private 53 * @var array 54 */ 55 private $fonts = array(); 56 57 /** 58 * An array of all google fonts. 59 * 60 * @access private 61 * @var array 62 */ 63 private $google_fonts = array(); 64 65 /** 66 * The array of subsets 67 * 68 * @access private 69 * @var array 70 */ 71 private $subsets = array(); 72 73 /** 74 * The google link 75 * 76 * @access private 77 * @var string 78 */ 79 private $link = ''; 80 81 /** 82 * The class constructor. 83 */ 84 private function __construct() { 85 86 $config = apply_filters( 'kirki/config', array() ); 87 88 // If we have set $config['disable_google_fonts'] to true then do not proceed any further. 89 if ( isset( $config['disable_google_fonts'] ) && true === $config['disable_google_fonts'] ) { 90 return; 91 } 92 93 // Populate the array of google fonts. 94 $this->google_fonts = Kirki_Fonts::get_google_fonts(); 95 96 // Enqueue link. 97 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ), 105 ); 98 99 } 100 101 /** 102 * Get the one, true instance of this class. 103 * Prevents performance issues since this is only loaded once. 104 * 105 * @return object Kirki_Fonts_Google 106 */ 107 public static function get_instance() { 108 if ( null === self::$instance ) { 109 self::$instance = new Kirki_Fonts_Google(); 110 } 111 return self::$instance; 112 } 113 114 /** 115 * Calls all the other necessary methods to populate and create the link. 116 */ 117 public function enqueue() { 118 if (apply_filters('kirki_skip_fonts_enqueue', false)) { 119 return; 120 } 121 122 // Go through our fields and populate $this->fonts. 123 $this->loop_fields(); 124 125 $this->fonts = apply_filters( 'kirki/enqueue_google_fonts', $this->fonts ); 126 127 // Goes through $this->fonts and adds or removes things as needed. 128 $this->process_fonts(); 129 130 // Go through $this->fonts and populate $this->link. 131 $this->create_link(); 132 133 // If $this->link is not empty then enqueue it. 134 if ( '' !== $this->link ) { 135 wp_enqueue_style( 'kirki_google_fonts', $this->link, array(), null ); 136 } 137 } 138 139 /** 140 * Goes through all our fields and then populates the $this->fonts property. 141 */ 142 private function loop_fields() { 143 foreach ( Kirki::$fields as $field_id => $args ) { 144 $this->generate_google_font( $args ); 145 } 146 } 147 148 /** 149 * Processes the arguments of a field 150 * determines if it's a typography field 151 * and if it is, then takes appropriate actions. 152 * 153 * @param array $args The field arguments. 154 */ 155 private function generate_google_font( $args ) { 156 157 // Process typography fields. 158 if ( isset( $args['type'] ) && 'kirki-typography' === $args['type'] ) { 159 160 // Get the value. 161 $value = Kirki_Values::get_sanitized_field_value( $args ); 162 163 // If we don't have a font-family then we can skip this. 164 if ( ! isset( $value['font-family'] ) ) { 165 return; 166 } 167 168 // Add support for older formats of the typography control. 169 // We used to have font-weight instead of variant. 170 if ( isset( $value['font-weight'] ) && ( ! isset( $value['variant'] ) || empty( $value['variant'] ) ) ) { 171 $value['variant'] = $value['font-weight']; 172 } 173 174 // Set a default value for variants. 175 if ( ! isset( $value['variant'] ) ) { 176 $value['variant'] = 'regular'; 177 } 178 if ( isset( $value['subsets'] ) ) { 179 180 // Add the subset directly to the array of subsets in the Kirki_GoogleFonts_Manager object. 181 // Subsets must be applied to ALL fonts if possible. 182 if ( ! is_array( $value['subsets'] ) ) { 183 $this->subsets[] = $value['subsets']; 184 } else { 185 foreach ( $value['subsets'] as $subset ) { 186 $this->subsets[] = $subset; 187 } 188 } 189 } 190 191 // Add the requested google-font. 192 if ( ! isset( $this->fonts[ $value['font-family'] ] ) ) { 193 $this->fonts[ $value['font-family'] ] = array(); 194 } 195 if ( ! in_array( $value['variant'], $this->fonts[ $value['font-family'] ], true ) ) { 196 $this->fonts[ $value['font-family'] ][] = $value['variant']; 197 } 198 } else { 199 200 // Process non-typography fields. 201 if ( isset( $args['output'] ) && is_array( $args['output'] ) ) { 202 foreach ( $args['output'] as $output ) { 203 204 // If we don't have a typography-related output argument we can skip this. 205 if ( ! isset( $output['property'] ) || ! in_array( $output['property'], array( 'font-family', 'font-weight', 'font-subset', 'subset', 'subsets' ), true ) ) { 206 continue; 207 } 208 209 // Get the value. 210 $value = Kirki_Values::get_sanitized_field_value( $args ); 211 212 if ( 'font-family' === $output['property'] ) { 213 if ( ! array_key_exists( $value, $this->fonts ) ) { 214 $this->fonts[ $value ] = array(); 215 } 216 } elseif ( 'font-weight' === $output['property'] ) { 217 foreach ( $this->fonts as $font => $variants ) { 218 if ( ! in_array( $value, $variants, true ) ) { 219 $this->fonts[ $font ][] = $value; 220 } 221 } 222 } elseif ( 'font-subset' === $output['property'] || 'subset' === $output['property'] || 'subsets' === $output['property'] ) { 223 if ( ! is_array( $value ) ) { 224 if ( ! in_array( $value, $this->subsets, true ) ) { 225 $this->subsets[] = $value; 226 } 227 } else { 228 foreach ( $value as $subset ) { 229 if ( ! in_array( $subset, $this->subsets, true ) ) { 230 $this->subsets[] = $subset; 231 } 232 } 233 } 234 } 235 } 236 } 237 } 238 } 239 240 /** 241 * Determines the vbalidity of the selected font as well as its properties. 242 * This is vital to make sure that the google-font script that we'll generate later 243 * does not contain any invalid options. 244 */ 245 private function process_fonts() { 246 247 // Early exit if font-family is empty. 248 if ( empty( $this->fonts ) ) { 249 return; 250 } 251 252 $valid_subsets = array(); 253 foreach ( $this->fonts as $font => $variants ) { 254 255 // Determine if this is indeed a google font or not. 256 // If it's not, then just remove it from the array. 257 if ( ! array_key_exists( $font, $this->google_fonts ) ) { 258 unset( $this->fonts[ $font ] ); 259 continue; 260 } 261 262 // Get all valid font variants for this font. 263 $font_variants = array(); 264 if ( isset( $this->google_fonts[ $font ]['variants'] ) ) { 265 $font_variants = $this->google_fonts[ $font ]['variants']; 266 } 267 foreach ( $variants as $variant ) { 268 269 // If this is not a valid variant for this font-family 270 // then unset it and move on to the next one. 271 if ( ! in_array( $variant, $font_variants, true ) ) { 272 $variant_key = array_search( $variant, $this->fonts[ $font ] ); 273 unset( $this->fonts[ $font ][ $variant_key ] ); 274 continue; 275 } 276 } 277 278 // Check if the selected subsets exist, even in one of the selected fonts. 279 // If they don't, then they have to be removed otherwise the link will fail. 280 if ( isset( $this->google_fonts[ $font ]['subsets'] ) ) { 281 foreach ( $this->subsets as $subset ) { 282 if ( in_array( $subset, $this->google_fonts[ $font ]['subsets'], true ) ) { 283 $valid_subsets[] = $subset; 284 } 285 } 286 } 287 } 288 $this->subsets = $valid_subsets; 289 } 290 291 /** 292 * Creates the google-fonts link. 293 */ 294 private function create_link() { 295 296 // If we don't have any fonts then we can exit. 297 if ( empty( $this->fonts ) ) { 298 return; 299 } 300 301 // Get font-family + subsets. 302 $link_fonts = array(); 303 foreach ( $this->fonts as $font => $variants ) { 304 305 // Are we force-loading all variants? 306 if ( true === self::$force_load_all_variants ) { 307 if ( isset( $this->google_fonts[ $font ]['variants'] ) ) { 308 $variants = $this->google_fonts[ $font ]['variants']; 309 } 310 } 311 $variants = implode( ',', $variants ); 312 313 $link_font = str_replace( ' ', '+', $font ); 314 if ( ! empty( $variants ) ) { 315 $link_font .= ':' . $variants; 316 } 317 $link_fonts[] = $link_font; 318 } 319 320 // Are we force-loading all subsets? 321 if ( true === self::$force_load_all_subsets ) { 322 323 if ( isset( $this->google_fonts[ $font ]['subsets'] ) ) { 324 foreach ( $this->google_fonts[ $font ]['subsets'] as $subset ) { 325 $this->subsets[] = $subset; 326 } 327 } 328 } 329 330 if ( ! empty( $this->subsets ) ) { 331 $this->subsets = array_unique( $this->subsets ); 332 } 333 334 $this->link = add_query_arg( array( 335 'family' => str_replace( '%2B', '+', urlencode( implode( '|', $link_fonts ) ) ), 336 'subset' => urlencode( implode( ',', $this->subsets ) ), 337 ), 'https://fonts.googleapis.com/css' ); 338 339 } 340 } 341 }