init
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* Manage fonts downloading.
|
||||
*
|
||||
* @package Kirki
|
||||
* @category Core
|
||||
* @author Ari Stathopoulos (@aristath)
|
||||
* @copyright Copyright (c) 2020, David Vongries
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 3.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fonts-downloading manager.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class Kirki_Fonts_Downloader {
|
||||
|
||||
/**
|
||||
* Get styles from URL.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.1.0
|
||||
* @param string $url The URL.
|
||||
* @return string
|
||||
*/
|
||||
public function get_styles( $url ) {
|
||||
$css = $this->get_cached_url_contents( $url );
|
||||
return $this->get_local_font_styles( $css );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get styles with fonts downloaded locally.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.1.0
|
||||
* @param string $css The styles.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_local_font_styles( $css ) {
|
||||
$files = $this->get_local_files_from_css( $css );
|
||||
|
||||
// Convert paths to URLs.
|
||||
foreach ( $files as $remote => $local ) {
|
||||
$files[ $remote ] = str_replace( WP_CONTENT_DIR, content_url(), $local );
|
||||
}
|
||||
|
||||
return str_replace(
|
||||
array_keys( $files ),
|
||||
array_values( $files ),
|
||||
$css
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download files mentioned in our CSS locally.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.1.0
|
||||
* @param string $css The CSS we want to parse.
|
||||
* @return array Returns an array of remote URLs and their local counterparts.
|
||||
*/
|
||||
protected function get_local_files_from_css( $css ) {
|
||||
$font_files = $this->get_files_from_css( $css );
|
||||
$stored = get_option( 'kirki_downloaded_font_files', array() );
|
||||
$change = false; // If in the end this is true, we need to update the cache option.
|
||||
|
||||
// If the fonts folder don't exist, create it.
|
||||
if ( ! file_exists( WP_CONTENT_DIR . '/fonts' ) ) {
|
||||
wp_mkdir_p( WP_CONTENT_DIR . '/fonts' );
|
||||
}
|
||||
|
||||
foreach ( $font_files as $font_family => $files ) {
|
||||
|
||||
// The folder path for this font-family.
|
||||
$folder_path = WP_CONTENT_DIR . '/fonts/' . $font_family;
|
||||
|
||||
// If the folder doesn't exist, create it.
|
||||
if ( ! file_exists( $folder_path ) ) {
|
||||
wp_mkdir_p( $folder_path );
|
||||
}
|
||||
|
||||
foreach ( $files as $url ) {
|
||||
|
||||
// Get the filename.
|
||||
$filename = basename( wp_parse_url( $url, PHP_URL_PATH ) );
|
||||
$font_path = $folder_path . '/' . $filename;
|
||||
|
||||
if ( file_exists( $font_path ) ) {
|
||||
|
||||
// Skip if already cached.
|
||||
if ( isset( $stored[ $url ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stored[ $url ] = $font_path;
|
||||
$change = true;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'download_url' ) ) {
|
||||
require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
|
||||
}
|
||||
|
||||
// Download file to temporary location.
|
||||
$tmp_path = download_url( $url );
|
||||
|
||||
// Make sure there were no errors.
|
||||
if ( is_wp_error( $tmp_path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move temp file to final destination.
|
||||
$success = $this->get_filesystem()->move( $tmp_path, $font_path, true );
|
||||
if ( $success ) {
|
||||
$stored[ $url ] = $font_path;
|
||||
$change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $change ) {
|
||||
update_option( 'kirki_downloaded_font_files', $stored );
|
||||
}
|
||||
|
||||
return $stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached url contents.
|
||||
* If a cache doesn't already exist, get the URL contents from remote
|
||||
* and cache the result.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.1.0
|
||||
* @param string $url The URL we want to get the contents from.
|
||||
* @param string $user_agent The user-agent to use for our request.
|
||||
* @return string Returns the remote URL contents.
|
||||
*/
|
||||
public function get_cached_url_contents( $url = '', $user_agent = null ) {
|
||||
|
||||
// Try to retrieved cached response from the gfonts API.
|
||||
$contents = false;
|
||||
$cached_responses = get_transient( 'kirki_remote_url_contents' );
|
||||
$cached_responses = ( $cached_responses && is_array( $cached_responses ) ) ? $cached_responses : array();
|
||||
if ( isset( $cached_responses[ md5( $url . $user_agent ) ] ) ) {
|
||||
return $cached_responses[ md5( $url . $user_agent ) ];
|
||||
}
|
||||
|
||||
// Get the contents from remote.
|
||||
$contents = $this->get_url_contents( $url, $user_agent );
|
||||
|
||||
// If we got the contents successfully, store them in a transient.
|
||||
// We're using a transient and not an option because fonts get updated
|
||||
// so we want to be able to get the latest version weekly.
|
||||
if ( $contents ) {
|
||||
$cached_responses[ md5( $url . $user_agent ) ] = $contents;
|
||||
set_transient( 'kirki_remote_url_contents', $cached_responses, WEEK_IN_SECONDS );
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote file contents.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.1.0
|
||||
* @param string $url The URL we want to get the contents from.
|
||||
* @param string $user_agent The user-agent to use for our request.
|
||||
* @return string Returns the remote URL contents.
|
||||
*/
|
||||
public function get_url_contents( $url = '', $user_agent = null ) {
|
||||
|
||||
if ( ! $user_agent ) {
|
||||
|
||||
/**
|
||||
* The user-agent we want to use.
|
||||
*
|
||||
* For woff2 format, use'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0'.
|
||||
* The default user-agent is the only one compatible with woff (not woff2)
|
||||
* which also supports unicode ranges.
|
||||
*/
|
||||
$user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8';
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = wp_remote_get( $url, array( 'user-agent' => $user_agent ) );
|
||||
|
||||
// Early exit if there was an error.
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the CSS from our response.
|
||||
$contents = wp_remote_retrieve_body( $response );
|
||||
|
||||
// Early exit if there was an error.
|
||||
if ( is_wp_error( $contents ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get font files from the CSS.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.1.0
|
||||
* @param string $css The CSS we want to parse.
|
||||
* @return array Returns an array of font-families and the font-files used.
|
||||
*/
|
||||
public function get_files_from_css( $css ) {
|
||||
|
||||
$font_faces = explode( '@font-face', $css );
|
||||
|
||||
$result = array();
|
||||
|
||||
// Loop all our font-face declarations.
|
||||
foreach ( $font_faces as $font_face ) {
|
||||
|
||||
// Make sure we only process styles inside this declaration.
|
||||
$style = explode( '}', $font_face )[0];
|
||||
|
||||
// Sanity check.
|
||||
if ( false === strpos( $style, 'font-family' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get an array of our font-families.
|
||||
preg_match_all( '/font-family.*?\;/', $style, $matched_font_families );
|
||||
|
||||
// Get an array of our font-files.
|
||||
preg_match_all( '/url\(.*?\)/i', $style, $matched_font_files );
|
||||
|
||||
// Get the font-family name.
|
||||
$font_family = 'unknown';
|
||||
if ( isset( $matched_font_families[0] ) && isset( $matched_font_families[0][0] ) ) {
|
||||
$font_family = rtrim( ltrim( $matched_font_families[0][0], 'font-family:' ), ';' );
|
||||
$font_family = trim( str_replace( array( "'", ';' ), '', $font_family ) );
|
||||
$font_family = sanitize_key( strtolower( str_replace( ' ', '-', $font_family ) ) );
|
||||
}
|
||||
|
||||
// Make sure the font-family is set in our array.
|
||||
if ( ! isset( $result[ $font_family ] ) ) {
|
||||
$result[ $font_family ] = array();
|
||||
}
|
||||
|
||||
// Get files for this font-family and add them to the array.
|
||||
|
||||
foreach ( $matched_font_files as $match ) {
|
||||
|
||||
// Sanity check.
|
||||
if ( ! isset( $match[0] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the file URL.
|
||||
$result[ $font_family ][] = rtrim( ltrim( $match[0], 'url(' ), ')' );
|
||||
}
|
||||
|
||||
// Make sure we have unique items.
|
||||
// We're using array_flip here instead of array_unique for improved performance.
|
||||
$result[ $font_family ] = array_flip( array_flip( $result[ $font_family ] ) );
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filesystem.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.1.0
|
||||
* @return WP_Filesystem
|
||||
*/
|
||||
protected function get_filesystem() {
|
||||
global $wp_filesystem;
|
||||
if ( ! $wp_filesystem ) {
|
||||
if ( ! function_exists( 'WP_Filesystem' ) ) {
|
||||
require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
|
||||
}
|
||||
WP_Filesystem();
|
||||
}
|
||||
return $wp_filesystem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
/**
|
||||
* Processes typography-related fields
|
||||
* and generates the google-font link.
|
||||
*
|
||||
* @package Kirki
|
||||
* @category Core
|
||||
* @author Ari Stathopoulos (@aristath)
|
||||
* @copyright Copyright (c) 2020, David Vongries
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages the way Google Fonts are enqueued.
|
||||
*/
|
||||
final class Kirki_Fonts_Google {
|
||||
|
||||
/**
|
||||
* The Kirki_Fonts_Google instance.
|
||||
* We use the singleton pattern here to avoid loading the google-font array multiple times.
|
||||
* This is mostly a performance tweak.
|
||||
*
|
||||
* @access private
|
||||
* @var null|object
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* DUMMY. DOESN'T DO ANYTHING, SIMPLY BACKWARDS-COMPATIBILITY.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @var bool
|
||||
*/
|
||||
public static $force_load_all_subsets = false;
|
||||
|
||||
/**
|
||||
* If set to true, forces loading ALL variants.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @var bool
|
||||
*/
|
||||
public static $force_load_all_variants = false;
|
||||
|
||||
/**
|
||||
* The array of fonts
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
public $fonts = array();
|
||||
|
||||
/**
|
||||
* An array of all google fonts.
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $google_fonts = array();
|
||||
|
||||
/**
|
||||
* An array of fonts that should be hosted locally instead of served via the google-CDN.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.32
|
||||
* @var array
|
||||
*/
|
||||
protected $hosted_fonts = array();
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*/
|
||||
private function __construct() {
|
||||
$config = apply_filters( 'kirki_config', array() );
|
||||
|
||||
// If we have set $config['disable_google_fonts'] to true then do not proceed any further.
|
||||
if ( isset( $config['disable_google_fonts'] ) && true === $config['disable_google_fonts'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'wp_ajax_kirki_fonts_google_all_get', array( $this, 'get_googlefonts_json' ) );
|
||||
add_action( 'wp_ajax_nopriv_kirki_fonts_google_all_get', array( $this, 'get_googlefonts_json' ) );
|
||||
add_action( 'wp_ajax_kirki_fonts_standard_all_get', array( $this, 'get_standardfonts_json' ) );
|
||||
add_action( 'wp_ajax_nopriv_kirki_fonts_standard_all_get', array( $this, 'get_standardfonts_json' ) );
|
||||
|
||||
// Populate the array of google fonts.
|
||||
$this->google_fonts = Kirki_Fonts::get_google_fonts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the one, true instance of this class.
|
||||
* Prevents performance issues since this is only loaded once.
|
||||
*
|
||||
* @return object Kirki_Fonts_Google
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new Kirki_Fonts_Google();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the arguments of a field
|
||||
* determines if it's a typography field
|
||||
* and if it is, then takes appropriate actions.
|
||||
*
|
||||
* @param array $args The field arguments.
|
||||
*/
|
||||
public function generate_google_font( $args ) {
|
||||
|
||||
// Process typography fields.
|
||||
if ( isset( $args['type'] ) && 'kirki-typography' === $args['type'] ) {
|
||||
|
||||
// Get the value.
|
||||
$value = Kirki_Values::get_sanitized_field_value( $args );
|
||||
|
||||
// If we don't have a font-family then we can skip this.
|
||||
if ( ! isset( $value['font-family'] ) || in_array( $value['font-family'], $this->hosted_fonts, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If not a google-font, then we can skip this.
|
||||
if ( ! isset( $value['font-family'] ) || ! Kirki_Fonts::is_google_font( $value['font-family'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set a default value for variants.
|
||||
if ( ! isset( $value['variant'] ) ) {
|
||||
$value['variant'] = 'regular';
|
||||
}
|
||||
|
||||
// Add the requested google-font.
|
||||
if ( ! isset( $this->fonts[ $value['font-family'] ] ) ) {
|
||||
$this->fonts[ $value['font-family'] ] = array();
|
||||
}
|
||||
if ( ! in_array( $value['variant'], $this->fonts[ $value['font-family'] ], true ) ) {
|
||||
$this->fonts[ $value['font-family'] ][] = $value['variant'];
|
||||
}
|
||||
|
||||
// Are we force-loading all variants?
|
||||
if ( true === self::$force_load_all_variants ) {
|
||||
$all_variants = Kirki_Fonts::get_all_variants();
|
||||
$args['choices']['variant'] = array_keys( $all_variants );
|
||||
}
|
||||
|
||||
if ( ! empty( $args['choices']['variant'] ) && is_array( $args['choices']['variant'] ) ) {
|
||||
foreach ( $args['choices']['variant'] as $extra_variant ) {
|
||||
$this->fonts[ $value['font-family'] ][] = $extra_variant;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Process non-typography fields.
|
||||
if ( isset( $args['output'] ) && is_array( $args['output'] ) ) {
|
||||
foreach ( $args['output'] as $output ) {
|
||||
|
||||
// If we don't have a typography-related output argument we can skip this.
|
||||
if ( ! isset( $output['property'] ) || ! in_array( $output['property'], array( 'font-family', 'font-weight' ), true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the value.
|
||||
$value = Kirki_Values::get_sanitized_field_value( $args );
|
||||
|
||||
if ( is_string( $value ) ) {
|
||||
if ( 'font-family' === $output['property'] ) {
|
||||
if ( ! array_key_exists( $value, $this->fonts ) ) {
|
||||
$this->fonts[ $value ] = array();
|
||||
}
|
||||
} elseif ( 'font-weight' === $output['property'] ) {
|
||||
foreach ( $this->fonts as $font => $variants ) {
|
||||
if ( ! in_array( $value, $variants, true ) ) {
|
||||
$this->fonts[ $font ][] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the vbalidity of the selected font as well as its properties.
|
||||
* This is vital to make sure that the google-font script that we'll generate later
|
||||
* does not contain any invalid options.
|
||||
*/
|
||||
public function process_fonts() {
|
||||
|
||||
// Early exit if font-family is empty.
|
||||
if ( empty( $this->fonts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->fonts as $font => $variants ) {
|
||||
|
||||
// Determine if this is indeed a google font or not.
|
||||
// If it's not, then just remove it from the array.
|
||||
if ( ! array_key_exists( $font, $this->google_fonts ) ) {
|
||||
unset( $this->fonts[ $font ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get all valid font variants for this font.
|
||||
$font_variants = array();
|
||||
if ( isset( $this->google_fonts[ $font ]['variants'] ) ) {
|
||||
$font_variants = $this->google_fonts[ $font ]['variants'];
|
||||
}
|
||||
foreach ( $variants as $variant ) {
|
||||
|
||||
// If this is not a valid variant for this font-family
|
||||
// then unset it and move on to the next one.
|
||||
if ( ! in_array( strval( $variant ), $font_variants, true ) ) {
|
||||
$variant_key = array_search( $variant, $this->fonts[ $font ], true );
|
||||
unset( $this->fonts[ $font ][ $variant_key ] );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the googlefonts JSON file.
|
||||
*
|
||||
* @since 3.0.17
|
||||
* @return void
|
||||
*/
|
||||
public function get_googlefonts_json() {
|
||||
include wp_normalize_path( dirname( __FILE__ ) . '/webfonts.json' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the standard fonts JSON.
|
||||
*
|
||||
* @since 3.0.17
|
||||
* @return void
|
||||
*/
|
||||
public function get_standardfonts_json() {
|
||||
echo wp_json_encode( Kirki_Fonts::get_standard_fonts() );
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
/**
|
||||
* A simple object containing properties for fonts.
|
||||
*
|
||||
* @package Kirki
|
||||
* @category Core
|
||||
* @author Ari Stathopoulos (@aristath)
|
||||
* @copyright Copyright (c) 2020, David Vongries
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Kirki_Fonts object.
|
||||
*/
|
||||
final class Kirki_Fonts {
|
||||
|
||||
/**
|
||||
* The mode we'll be using to add google fonts.
|
||||
* This is a todo item, not yet functional.
|
||||
*
|
||||
* @static
|
||||
* @todo
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public static $mode = 'link';
|
||||
|
||||
/**
|
||||
* Holds a single instance of this object.
|
||||
*
|
||||
* @static
|
||||
* @access private
|
||||
* @var null|object
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* An array of our google fonts.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @var null|object
|
||||
*/
|
||||
public static $google_fonts = null;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Get the one, true instance of this class.
|
||||
* Prevents performance issues since this is only loaded once.
|
||||
*
|
||||
* @return object Kirki_Fonts
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile font options from different sources.
|
||||
*
|
||||
* @return array All available fonts.
|
||||
*/
|
||||
public static function get_all_fonts() {
|
||||
$standard_fonts = self::get_standard_fonts();
|
||||
$google_fonts = self::get_google_fonts();
|
||||
return apply_filters( 'kirki_fonts_all', array_merge( $standard_fonts, $google_fonts ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of standard websafe fonts.
|
||||
*
|
||||
* @return array Standard websafe fonts.
|
||||
*/
|
||||
public static function get_standard_fonts() {
|
||||
$standard_fonts = array(
|
||||
'serif' => array(
|
||||
'label' => 'Serif',
|
||||
'stack' => 'Georgia,Times,"Times New Roman",serif',
|
||||
),
|
||||
'sans-serif' => array(
|
||||
'label' => 'Sans Serif',
|
||||
'stack' => '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif',
|
||||
),
|
||||
'monospace' => array(
|
||||
'label' => 'Monospace',
|
||||
'stack' => 'Monaco,"Lucida Sans Typewriter","Lucida Typewriter","Courier New",Courier,monospace',
|
||||
),
|
||||
);
|
||||
return apply_filters( 'kirki_fonts_standard_fonts', $standard_fonts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of all available Google Fonts.
|
||||
*
|
||||
* @return array All Google Fonts.
|
||||
*/
|
||||
public static function get_google_fonts() {
|
||||
|
||||
// Get fonts from cache.
|
||||
self::$google_fonts = get_site_transient( 'kirki_googlefonts_cache' );
|
||||
|
||||
/**
|
||||
* Reset the cache if we're using action=kirki-reset-cache in the URL.
|
||||
*
|
||||
* Note to code reviewers:
|
||||
* There's no need to check nonces or anything else, this is a simple true/false evaluation.
|
||||
*/
|
||||
if ( ! empty( $_GET['action'] ) && 'kirki-reset-cache' === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
|
||||
self::$google_fonts = false;
|
||||
}
|
||||
|
||||
// If cache is populated, return cached fonts array.
|
||||
if ( self::$google_fonts ) {
|
||||
return self::$google_fonts;
|
||||
}
|
||||
|
||||
// If we got this far, cache was empty so we need to get from JSON.
|
||||
ob_start();
|
||||
include wp_normalize_path( dirname( __FILE__ ) . '/webfonts.json' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
|
||||
|
||||
$fonts_json = ob_get_clean();
|
||||
$fonts = json_decode( $fonts_json, true );
|
||||
|
||||
$google_fonts = array();
|
||||
if ( is_array( $fonts ) ) {
|
||||
foreach ( $fonts['items'] as $font ) {
|
||||
$google_fonts[ $font['family'] ] = array(
|
||||
'label' => $font['family'],
|
||||
'variants' => $font['variants'],
|
||||
'category' => $font['category'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the 'kirki_fonts_google_fonts' filter.
|
||||
self::$google_fonts = apply_filters( 'kirki_fonts_google_fonts', $google_fonts );
|
||||
|
||||
// Save the array in cache.
|
||||
$cache_time = apply_filters( 'kirki_googlefonts_transient_time', DAY_IN_SECONDS );
|
||||
set_site_transient( 'kirki_googlefonts_cache', self::$google_fonts, $cache_time );
|
||||
|
||||
return self::$google_fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all available subsets.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public static function get_google_font_subsets() {
|
||||
return array(
|
||||
'cyrillic' => 'Cyrillic',
|
||||
'cyrillic-ext' => 'Cyrillic Extended',
|
||||
'devanagari' => 'Devanagari',
|
||||
'greek' => 'Greek',
|
||||
'greek-ext' => 'Greek Extended',
|
||||
'khmer' => 'Khmer',
|
||||
'latin' => 'Latin',
|
||||
'latin-ext' => 'Latin Extended',
|
||||
'vietnamese' => 'Vietnamese',
|
||||
'hebrew' => 'Hebrew',
|
||||
'arabic' => 'Arabic',
|
||||
'bengali' => 'Bengali',
|
||||
'gujarati' => 'Gujarati',
|
||||
'tamil' => 'Tamil',
|
||||
'telugu' => 'Telugu',
|
||||
'thai' => 'Thai',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function to avoid issues with backwards-compatibility.
|
||||
* This is not functional, but it will prevent PHP Fatal errors.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
public static function get_google_font_uri() {}
|
||||
|
||||
/**
|
||||
* Returns an array of all available variants.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all_variants() {
|
||||
return array(
|
||||
'100' => esc_html__( 'Ultra-Light 100', 'kirki' ),
|
||||
'100light' => esc_html__( 'Ultra-Light 100', 'kirki' ),
|
||||
'100italic' => esc_html__( 'Ultra-Light 100 Italic', 'kirki' ),
|
||||
'200' => esc_html__( 'Light 200', 'kirki' ),
|
||||
'200italic' => esc_html__( 'Light 200 Italic', 'kirki' ),
|
||||
'300' => esc_html__( 'Book 300', 'kirki' ),
|
||||
'300italic' => esc_html__( 'Book 300 Italic', 'kirki' ),
|
||||
'400' => esc_html__( 'Normal 400', 'kirki' ),
|
||||
'regular' => esc_html__( 'Normal 400', 'kirki' ),
|
||||
'italic' => esc_html__( 'Normal 400 Italic', 'kirki' ),
|
||||
'500' => esc_html__( 'Medium 500', 'kirki' ),
|
||||
'500italic' => esc_html__( 'Medium 500 Italic', 'kirki' ),
|
||||
'600' => esc_html__( 'Semi-Bold 600', 'kirki' ),
|
||||
'600bold' => esc_html__( 'Semi-Bold 600', 'kirki' ),
|
||||
'600italic' => esc_html__( 'Semi-Bold 600 Italic', 'kirki' ),
|
||||
'700' => esc_html__( 'Bold 700', 'kirki' ),
|
||||
'700italic' => esc_html__( 'Bold 700 Italic', 'kirki' ),
|
||||
'800' => esc_html__( 'Extra-Bold 800', 'kirki' ),
|
||||
'800bold' => esc_html__( 'Extra-Bold 800', 'kirki' ),
|
||||
'800italic' => esc_html__( 'Extra-Bold 800 Italic', 'kirki' ),
|
||||
'900' => esc_html__( 'Ultra-Bold 900', 'kirki' ),
|
||||
'900bold' => esc_html__( 'Ultra-Bold 900', 'kirki' ),
|
||||
'900italic' => esc_html__( 'Ultra-Bold 900 Italic', 'kirki' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a font-name is a valid google font or not.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @param string $fontname The name of the font we want to check.
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_google_font( $fontname ) {
|
||||
return ( array_key_exists( $fontname, self::$google_fonts ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets available options for a font.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public static function get_font_choices() {
|
||||
$fonts = self::get_all_fonts();
|
||||
$fonts_array = array();
|
||||
foreach ( $fonts as $key => $args ) {
|
||||
$fonts_array[ $key ] = $key;
|
||||
}
|
||||
return $fonts_array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* Adds the Webfont Loader to load fonts asyncronously.
|
||||
*
|
||||
* @package Kirki
|
||||
* @category Core
|
||||
* @author Ari Stathopoulos (@aristath)
|
||||
* @copyright Copyright (c) 2020, David Vongries
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages the way Google Fonts are enqueued.
|
||||
*/
|
||||
final class Kirki_Modules_Webfonts_Async {
|
||||
|
||||
/**
|
||||
* The config ID.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $config_id;
|
||||
|
||||
/**
|
||||
* The Kirki_Modules_Webfonts object.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var object
|
||||
*/
|
||||
protected $webfonts;
|
||||
|
||||
/**
|
||||
* The Kirki_Fonts_Google object.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var object
|
||||
*/
|
||||
protected $googlefonts;
|
||||
|
||||
/**
|
||||
* Fonts to load.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.26
|
||||
* @var array
|
||||
*/
|
||||
protected $fonts_to_load = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0
|
||||
* @param string $config_id The config-ID.
|
||||
* @param object $webfonts The Kirki_Modules_Webfonts object.
|
||||
* @param object $googlefonts The Kirki_Fonts_Google object.
|
||||
* @param array $args Extra args we want to pass.
|
||||
*/
|
||||
public function __construct( $config_id, $webfonts, $googlefonts, $args = array() ) {
|
||||
$this->config_id = $config_id;
|
||||
$this->webfonts = $webfonts;
|
||||
$this->googlefonts = $googlefonts;
|
||||
|
||||
add_action( 'wp_head', array( $this, 'webfont_loader' ) );
|
||||
add_action( 'wp_head', array( $this, 'webfont_loader_script' ), 30 );
|
||||
|
||||
// Add these in the dashboard to support editor-styles.
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'webfont_loader' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'webfont_loader_script' ), 30 );
|
||||
|
||||
add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add preconnect for Google Fonts.
|
||||
*
|
||||
* @access public
|
||||
* @param array $urls URLs to print for resource hints.
|
||||
* @param string $relation_type The relation type the URLs are printed.
|
||||
* @return array $urls URLs to print for resource hints.
|
||||
*/
|
||||
public function resource_hints( $urls, $relation_type ) {
|
||||
$fonts_to_load = $this->googlefonts->fonts;
|
||||
|
||||
if ( ! empty( $fonts_to_load ) && 'preconnect' === $relation_type ) {
|
||||
$urls[] = array(
|
||||
'href' => 'https://fonts.gstatic.com',
|
||||
'crossorigin',
|
||||
);
|
||||
}
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Webfont Loader for Google Fonts.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function webfont_loader() {
|
||||
|
||||
// Go through our fields and populate $this->fonts.
|
||||
$this->webfonts->loop_fields( $this->config_id );
|
||||
|
||||
$this->googlefonts->fonts = apply_filters( 'kirki_enqueue_google_fonts', $this->googlefonts->fonts );
|
||||
|
||||
// Goes through $this->fonts and adds or removes things as needed.
|
||||
$this->googlefonts->process_fonts();
|
||||
|
||||
foreach ( $this->googlefonts->fonts as $font => $weights ) {
|
||||
foreach ( $weights as $key => $value ) {
|
||||
if ( 'italic' === $value ) {
|
||||
$weights[ $key ] = '400i';
|
||||
} else {
|
||||
$weights[ $key ] = str_replace( array( 'regular', 'bold', 'italic' ), array( '400', '', 'i' ), $value );
|
||||
}
|
||||
}
|
||||
$this->fonts_to_load[] = $font . ':' . join( ',', $weights ) . ':cyrillic,cyrillic-ext,devanagari,greek,greek-ext,khmer,latin,latin-ext,vietnamese,hebrew,arabic,bengali,gujarati,tamil,telugu,thai';
|
||||
}
|
||||
if ( ! empty( $this->fonts_to_load ) ) {
|
||||
Kirki_Modules_Webfont_Loader::$load = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Webfont Loader script for Google Fonts.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function webfont_loader_script() {
|
||||
if ( ! empty( $this->fonts_to_load ) ) {
|
||||
wp_add_inline_script(
|
||||
'webfont-loader',
|
||||
'WebFont.load({google:{families:[\'' . join( '\', \'', $this->fonts_to_load ) . '\']}});',
|
||||
'after'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* Adds the Webfont Loader to load fonts asyncronously.
|
||||
*
|
||||
* @package Kirki
|
||||
* @category Core
|
||||
* @author Ari Stathopoulos (@aristath)
|
||||
* @copyright Copyright (c) 2020, David Vongries
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages the way Google Fonts are enqueued.
|
||||
*/
|
||||
final class Kirki_Modules_Webfonts_Embed {
|
||||
|
||||
/**
|
||||
* The config ID.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $config_id;
|
||||
|
||||
/**
|
||||
* The Kirki_Modules_Webfonts object.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var object
|
||||
*/
|
||||
protected $webfonts;
|
||||
|
||||
/**
|
||||
* The Kirki_Fonts_Google object.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var object
|
||||
*/
|
||||
protected $googlefonts;
|
||||
|
||||
/**
|
||||
* Fonts to load.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.26
|
||||
* @var array
|
||||
*/
|
||||
protected $fonts_to_load = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0
|
||||
* @param string $config_id The config-ID.
|
||||
* @param object $webfonts The Kirki_Modules_Webfonts object.
|
||||
* @param object $googlefonts The Kirki_Fonts_Google object.
|
||||
* @param array $args Extra args we want to pass.
|
||||
*/
|
||||
public function __construct( $config_id, $webfonts, $googlefonts, $args = array() ) {
|
||||
$this->config_id = $config_id;
|
||||
$this->webfonts = $webfonts;
|
||||
$this->googlefonts = $googlefonts;
|
||||
|
||||
add_action( 'wp', array( $this, 'init' ), 9 );
|
||||
add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.36
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
$this->populate_fonts();
|
||||
add_action( 'kirki_dynamic_css', array( $this, 'the_css' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add preconnect for Google Fonts.
|
||||
*
|
||||
* @access public
|
||||
* @param array $urls URLs to print for resource hints.
|
||||
* @param string $relation_type The relation type the URLs are printed.
|
||||
* @return array $urls URLs to print for resource hints.
|
||||
*/
|
||||
public function resource_hints( $urls, $relation_type ) {
|
||||
$fonts_to_load = $this->googlefonts->fonts;
|
||||
|
||||
if ( ! empty( $fonts_to_load ) && 'preconnect' === $relation_type ) {
|
||||
$urls[] = array(
|
||||
'href' => 'https://fonts.gstatic.com',
|
||||
'crossorigin',
|
||||
);
|
||||
}
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Webfont Loader for Google Fonts.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function populate_fonts() {
|
||||
|
||||
// Go through our fields and populate $this->fonts.
|
||||
$this->webfonts->loop_fields( $this->config_id );
|
||||
|
||||
$this->googlefonts->fonts = apply_filters( 'kirki_enqueue_google_fonts', $this->googlefonts->fonts );
|
||||
|
||||
// Goes through $this->fonts and adds or removes things as needed.
|
||||
$this->googlefonts->process_fonts();
|
||||
|
||||
foreach ( $this->googlefonts->fonts as $font => $weights ) {
|
||||
foreach ( $weights as $key => $value ) {
|
||||
if ( 'italic' === $value ) {
|
||||
$weights[ $key ] = '400i';
|
||||
} else {
|
||||
$weights[ $key ] = str_replace( array( 'regular', 'bold', 'italic' ), array( '400', '', 'i' ), $value );
|
||||
}
|
||||
}
|
||||
$this->fonts_to_load[] = array(
|
||||
'family' => $font,
|
||||
'weights' => $weights,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Webfont Loader script for Google Fonts.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function the_css() {
|
||||
foreach ( $this->fonts_to_load as $font ) {
|
||||
$family = str_replace( ' ', '+', trim( $font['family'] ) );
|
||||
$weights = join( ',', $font['weights'] );
|
||||
$url = "https://fonts.googleapis.com/css?family={$family}:{$weights}&subset=cyrillic,cyrillic-ext,devanagari,greek,greek-ext,khmer,latin,latin-ext,vietnamese,hebrew,arabic,bengali,gujarati,tamil,telugu,thai&display=swap";
|
||||
|
||||
$transient_id = 'kirki_gfonts_' . md5( $url );
|
||||
$contents = get_transient( $transient_id );
|
||||
|
||||
if ( ! class_exists( 'Kirki_Fonts_Downloader' ) ) {
|
||||
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts-downloader.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
|
||||
}
|
||||
$downloader = new Kirki_Fonts_Downloader();
|
||||
$contents = $downloader->get_styles( $url );
|
||||
|
||||
if ( $contents ) {
|
||||
/**
|
||||
* Note to code reviewers:
|
||||
*
|
||||
* Though all output should be run through an escaping function, this is pure CSS
|
||||
* and it is added on a call that has a PHP `header( 'Content-type: text/css' );`.
|
||||
* No code, script or anything else can be executed from inside a stylesheet.
|
||||
* For extra security we're using the wp_strip_all_tags() function here
|
||||
* just to make sure there's no <script> tags in there or anything else.
|
||||
*/
|
||||
echo wp_strip_all_tags( $contents ); // phpcs:ignore WordPress.Security.EscapeOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles webfonts.
|
||||
*
|
||||
* @package Kirki
|
||||
* @category Modules
|
||||
* @author Ari Stathopoulos (@aristath)
|
||||
* @copyright Copyright (c) 2020, David Vongries
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds script for tooltips.
|
||||
*/
|
||||
class Kirki_Modules_Webfonts {
|
||||
|
||||
/**
|
||||
* The object instance.
|
||||
*
|
||||
* @static
|
||||
* @access private
|
||||
* @since 3.0.0
|
||||
* @var object
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* The Kirki_Fonts_Google object.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @var object
|
||||
*/
|
||||
protected $fonts_google;
|
||||
|
||||
/**
|
||||
* The class constructor
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function __construct() {
|
||||
|
||||
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
|
||||
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts-google.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
|
||||
|
||||
add_action( 'wp_loaded', array( $this, 'run' ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Run on after_setup_theme.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function run() {
|
||||
$this->fonts_google = Kirki_Fonts_Google::get_instance();
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of this object.
|
||||
* Prevents duplicate instances which avoid artefacts and improves performance.
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
* @return object
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init other objects depending on the method we'll be using.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function init() {
|
||||
foreach ( array_keys( Kirki::$config ) as $config_id ) {
|
||||
if ( 'async' === $this->get_method() ) {
|
||||
new Kirki_Modules_Webfonts_Async( $config_id, $this, $this->fonts_google );
|
||||
}
|
||||
new Kirki_Modules_Webfonts_Embed( $config_id, $this, $this->fonts_google );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method we're going to use.
|
||||
*
|
||||
* @access public
|
||||
* @since 3.0.0
|
||||
* @deprecated in 3.0.36.
|
||||
* @return string
|
||||
*/
|
||||
public function get_method() {
|
||||
return ( is_customize_preview() || is_admin() ) ? 'async' : 'embed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through all our fields and then populates the $this->fonts property.
|
||||
*
|
||||
* @access public
|
||||
* @param string $config_id The config-ID.
|
||||
*/
|
||||
public function loop_fields( $config_id ) {
|
||||
foreach ( Kirki::$fields as $field ) {
|
||||
if ( isset( $field['kirki_config'] ) && $config_id !== $field['kirki_config'] ) {
|
||||
continue;
|
||||
}
|
||||
if ( true === apply_filters( "kirki_{$config_id}_webfonts_skip_hidden", true ) ) {
|
||||
// Only continue if field dependencies are met.
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
$valid = true;
|
||||
|
||||
foreach ( $field['required'] as $requirement ) {
|
||||
if ( isset( $requirement['setting'] ) && isset( $requirement['value'] ) && isset( $requirement['operator'] ) ) {
|
||||
$controller_value = Kirki_Values::get_value( $config_id, $requirement['setting'] );
|
||||
if ( ! Kirki_Helper::compare_values( $controller_value, $requirement['value'], $requirement['operator'] ) ) {
|
||||
$valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $valid ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->fonts_google->generate_google_font( $field );
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user