File: /home/grainesdfo/www/wp-content/plugins/LayerSlider/assets/classes/class.ls.googlefonts.php
<?php
class LS_GoogleFontsManager {
// Shared among instances, it's a global list of loaded fonts and
// their variants to prevent loading the same font multiple times.
private static $loadedFonts = [];
// Instance specific array of fonts to load.
private $fonts = [];
private $uploadsBaseDir;
private $googleFontsDir;
public function __construct() {
$uploads = wp_upload_dir();
$this->uploadsBaseDir = $uploads['basedir'];
$this->googleFontsDir = $this->uploadsBaseDir.'/layerslider/google-fonts';
}
public function getInlineStyle( $fontList ) {
// Return empty string if the font list is empty or not an array
if( empty( $fontList ) || ! is_array( $fontList ) ) {
return '';
}
// Normalize & process font list
$this->fonts = $this->processFontList( $fontList );
// Load from local cache
if( get_option('layerslider-google-fonts-host-locally', false ) ) {
return $this->getInlineStyleLocal();
// Load from Google
} else {
return $this->getInlineStyleRemote();
}
}
private function processFontList( $fontList ) {
$fontsIndex = [];
$allVariants = [
'100', '100i',
'200', '200i',
'300', '300i',
'400', '400i',
'500', '500i',
'600', '600i',
'700', '700i',
'800', '800i',
'900', '900i'
];
foreach( $fontList as $font ) {
$fontData = explode( ':' , $font['param'] );
$fontName = urldecode( $fontData[0] );
$fontVariants = $allVariants;
// TODO: Temporarily disabled due to issues when a font doesn't have the explicit variant
// used in project editor. For example, if a font only has 800 font-weight variant,
// but the user set 900 in the editor (since moving the slider would result in the
// same appearance in both cases and could accidentally set either of them), then
// the editor would display the font as expected, but the layer would look differently
// in embedded sliders on the frontend.
// if( ! empty( $font['variants'] ) && is_array( $font['variants'] ) ) {
// $fontVariants = $font['variants'];
// }
// Add font-weight 400 if not present to ensure a successful request to the Google Fonts API.
// Having the regular variant loaded is also a good practice to handle unexpected cases.
if( ! in_array( '400', $fontVariants ) ) {
$fontVariants[] = '400';
}
foreach( $fontVariants as $fontVariant ) {
// This specific font and specific variant is not yet loaded.
if( empty( self::$loadedFonts[ $fontName ][ $fontVariant ] ) ) {
// Global marker to prevent loading it again
self::$loadedFonts[ $fontName ][ $fontVariant ] = true;
// Instance marker to load the font
$fontsIndex[ $fontName ][ $fontVariant ] = true;
}
}
}
foreach( $fontsIndex as $fontName => $fontVariants ) {
$fontsIndex[ $fontName ] = [
'name' => $fontName,
'url' => urlencode( $fontName ) .':'. implode( ',', array_keys( $fontVariants ) ),
'variants' => array_keys( $fontVariants )
];
}
return $fontsIndex;
}
// ----- REMOTE FUNCTIONS -----
private function getInlineStyleRemote() {
if( empty( $this->fonts ) ) {
return '';
}
return '<link href="'.$this->getRemoteURL().'" rel="stylesheet">';
}
private function getRemoteURL() {
$fontURLs = [];
foreach( $this->fonts as $fontName => $fontData ) {
$fontURLs[] = $fontData['url'];
}
return 'https://fonts.googleapis.com/css?family='.implode( '%7C', $fontURLs );
}
// ----- LOCAL FUNCTIONS -----
private function getFontFilesFromCache( $fontData ) {
// var_dump( $fontData);
$folderName = sanitize_file_name( $fontData['name'] );
$fontFolder = $this->googleFontsDir.'/'.$folderName;
$files = glob( $fontFolder.'/*.woff2' );
if( ! file_exists( $fontFolder ) || empty( $files ) ) {
$this->downloadFontFilesToCache( $fontData );
$files = glob( $fontFolder.'/*.woff2' );
}
return ! empty( $files ) ? $files : [];
}
private function downloadFontFilesToCache( $fontData ) {
if (!function_exists('download_url')) require_once ABSPATH . 'wp-admin/includes/file.php';
$folderName = sanitize_file_name( $fontData['name'] );
$fontFolder = $this->googleFontsDir.'/'.$folderName;
$dlURLs = [];
wp_mkdir_p( $fontFolder );
if( ! is_writable( $fontFolder ) ) {
return false;
}
$response = wp_remote_retrieve_body( wp_remote_get( 'https://fonts.googleapis.com/css?family='.$fontData['url'], [
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
]));
if( empty( $response ) ) {
return false;
}
preg_match_all( '/http.*?\.woff2/', $response, $dlURLs );
if( ! empty( $dlURLs[0] ) ) {
foreach( $dlURLs[0] as $url ) {
$fileName = sanitize_file_name( basename( $url ) );
$filePath = $fontFolder.'/'.$fileName;
$tmp = download_url( $url );
copy( $tmp, $filePath );
unlink( $tmp );
}
}
return true;
}
private function getFontFaceRule( $fontData ) {
$files = $this->getFontFilesFromCache( $fontData );
$cssRules = [];
$cssRules[] = '@font-face {';
$cssRules[] = 'font-family: "'.$fontData['name'].'";';
$cssRules[] = 'font-style: normal;';
$cssRules[] = 'font-weight: 400;';
$cssRules[] = 'src: local("'.$fontData['name'].'"), url("'.$this->googleFontsDir.'.woff2") format("woff2");';
$cssRules[] = '}';
return implode( ' ', $cssRules );
}
private function getInlineStyleLocal() {
$cssRules = [];
foreach( $this->fonts as $fontData ) {
$cssRules[] = $this->getFontFaceRule( $fontData );
}
if( ! empty( $cssRules ) ) {
return '<style>'.implode( ' ', $cssRules ).'</style>';
}
return '';
}
}