This commit is contained in:
Alexander Agnarson 2019-02-17 14:28:35 +01:00
parent b14ccb1b03
commit 7e3774b663
168 changed files with 2453 additions and 2788 deletions

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.28
*/

View file

@ -1,143 +0,0 @@
<?php
/**
* Writes compiled CSS to a file.
*
* @package Kirki
* @subpackage CSS Module
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
/**
* Handles writing CSS to a file.
*/
class Kirki_CSS_To_File {
/**
* Fallback to inline CSS?
*
* @access protected
* @since 3.0.0
* @var bool
*/
protected $fallback = false;
/**
* Constructor.
*
* @access public
* @since 3.0.0
*/
public function __construct() {
// If the file doesn't exist, create it.
if ( ! file_exists( $this->get_path( 'file' ) ) ) {
// If the file-write fails, fallback to inline
// and cache the failure so we don't try again immediately.
$this->write_file();
}
add_action( 'customize_save_after', array( $this, 'write_file' ) );
}
/**
* Gets the path of the CSS file and folder in the filesystem.
*
* @access protected
* @since 3.0.0
* @param string $context Can be "file" or "folder". If empty, returns both as array.
* @return string|array
*/
protected function get_path( $context = '' ) {
$upload_dir = wp_upload_dir();
$paths = array(
'file' => wp_normalize_path( $upload_dir['basedir'] . '/kirki-css/styles.css' ),
'folder' => wp_normalize_path( $upload_dir['basedir'] . '/kirki-css' ),
);
if ( 'file' === $context ) {
return $paths['file'];
}
if ( 'folder' === $context ) {
return $paths['folder'];
}
return $paths;
}
/**
* Gets the URL of the CSS file in the filesystem.
*
* @access public
* @since 3.0.0
* @return string
*/
public function get_url() {
$upload_dir = wp_upload_dir();
return esc_url_raw( $upload_dir['baseurl'] . '/kirki-css/styles.css' );
}
/**
* Gets the timestamp of the file.
* This will be used as "version" for cache-busting purposes.
*
* @access public
* @since 3.0.0
* @return integer|false
*/
public function get_timestamp() {
if ( file_exists( $this->get_path( 'file' ) ) ) {
return filemtime( $this->get_path( 'file' ) );
}
return false;
}
/**
* Writes the file to disk.
*
* @access public
* @since 3.0.0
* @return bool
*/
public function write_file() {
$css = array();
$configs = Kirki::$config;
foreach ( $configs as $config_id => $args ) {
// Get the CSS we want to write.
$css[ $config_id ] = apply_filters( "kirki_{$config_id}_dynamic_css", Kirki_Modules_CSS::loop_controls( $config_id ) );
}
$css = implode( $css, '' );
// If the folder doesn't exist, create it.
if ( ! file_exists( $this->get_path( 'folder' ) ) ) {
wp_mkdir_p( $this->get_path( 'folder' ) );
}
$filesystem = $this->get_filesystem();
$write_file = (bool) $filesystem->put_contents( $this->get_path( 'file' ), $css );
if ( ! $write_file ) {
$this->fallback = true;
set_transient( 'kirki_css_write_to_file_failed', true, HOUR_IN_SECONDS );
}
return $write_file;
}
/**
* Gets the WP_Filesystem object.
*
* @access protected
* @since 3.0.0
* @return object
*/
protected function get_filesystem() {
// The WordPress filesystem.
global $wp_filesystem;
if ( empty( $wp_filesystem ) ) {
require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
WP_Filesystem();
}
return $wp_filesystem;
}
}

View file

@ -5,8 +5,8 @@
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 1.0
*/
@ -164,15 +164,15 @@ final class Kirki_Modules_CSS_Generator {
// Find the class that will handle the outpout for this field.
$classname = 'Kirki_Output';
$field_output_classes = apply_filters(
"kirki_{$field['kirki_config']}_output_control_classnames", array(
'kirki-background' => 'Kirki_Output_Field_Background',
'kirki-dimensions' => 'Kirki_Output_Field_Dimensions',
'kirki-image' => 'Kirki_Output_Field_Image',
'kirki-typography' => 'Kirki_Output_Field_Typography',
'kirki-multicolor' => 'Kirki_Output_Field_Multicolor',
)
$default_classnames = array(
'kirki-background' => 'Kirki_Output_Field_Background',
'kirki-dimensions' => 'Kirki_Output_Field_Dimensions',
'kirki-image' => 'Kirki_Output_Field_Image',
'kirki-typography' => 'Kirki_Output_Field_Typography',
'kirki-multicolor' => 'Kirki_Output_Field_Multicolor',
);
$field_output_classes = apply_filters( 'kirki_output_control_classnames', $default_classnames );
$field_output_classes = apply_filters( "kirki_{$field['kirki_config']}_output_control_classnames", $field_output_classes );
if ( array_key_exists( self::$field_type, $field_output_classes ) ) {
$classname = $field_output_classes[ self::$field_type ];
}
@ -238,7 +238,8 @@ final class Kirki_Modules_CSS_Generator {
// Add -webkit-* and -moz-*.
if ( is_string( $property ) && in_array(
$property, array(
$property,
array(
'border-radius',
'box-shadow',
'box-sizing',
@ -247,7 +248,8 @@ final class Kirki_Modules_CSS_Generator {
'background-size',
'transition',
'transition-property',
), true
),
true
) ) {
unset( $css[ $media_query ][ $element ][ $property ] );
$css[ $media_query ][ $element ][ '-webkit-' . $property ] = $value;
@ -257,12 +259,14 @@ final class Kirki_Modules_CSS_Generator {
// Add -ms-* and -o-*.
if ( is_string( $property ) && in_array(
$property, array(
$property,
array(
'transform',
'background-size',
'transition',
'transition-property',
), true
),
true
) ) {
unset( $css[ $media_query ][ $element ][ $property ] );
$css[ $media_query ][ $element ][ '-ms-' . $property ] = $value;

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
@ -25,14 +25,6 @@ class Kirki_Modules_CSS {
*/
private static $instance;
/**
* Whether we've already processed this or not.
*
* @access public
* @var bool
*/
public $processed = false;
/**
* The CSS array
*
@ -41,23 +33,6 @@ class Kirki_Modules_CSS {
*/
public static $css_array = array();
/**
* Set to true if you want to use the AJAX method.
*
* @access public
* @var bool
*/
public static $ajax = false;
/**
* The Kirki_CSS_To_File object.
*
* @access protected
* @since 3.0.0
* @var object
*/
protected $css_to_file;
/**
* Should we enqueue font-awesome?
*
@ -75,7 +50,6 @@ class Kirki_Modules_CSS {
*/
protected function __construct() {
$class_files = array(
'Kirki_CSS_To_File' => '/class-kirki-css-to-file.php',
'Kirki_Modules_CSS_Generator' => '/class-kirki-modules-css-generator.php',
'Kirki_Output' => '/class-kirki-output.php',
'Kirki_Output_Field_Background' => '/field/class-kirki-output-field-background.php',
@ -91,7 +65,7 @@ class Kirki_Modules_CSS {
foreach ( $class_files as $class_name => $file ) {
if ( ! class_exists( $class_name ) ) {
include_once wp_normalize_path( dirname( __FILE__ ) . $file );
include_once wp_normalize_path( dirname( __FILE__ ) . $file ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
}
}
add_action( 'init', array( $this, 'init' ) );
@ -119,125 +93,128 @@ class Kirki_Modules_CSS {
* @access public
*/
public function init() {
global $wp_customize;
Kirki_Modules_Webfonts::get_instance();
$config = apply_filters( 'kirki_config', array() );
$priority = 999;
if ( isset( $config['styles_priority'] ) ) {
$priority = absint( $config['styles_priority'] );
}
// Allow completely disabling Kirki CSS output.
if ( ( defined( 'KIRKI_NO_OUTPUT' ) && true === KIRKI_NO_OUTPUT ) || ( isset( $config['disable_output'] ) && true === $config['disable_output'] ) ) {
return;
}
$method = apply_filters( 'kirki_dynamic_css_method', 'inline' );
if ( $wp_customize ) {
// Admin styles, adds compatibility with the new WordPress editor (Gutenberg).
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_styles' ), 100 );
// If we're in the customizer, load inline no matter what.
add_action( 'wp_enqueue_scripts', array( $this, 'inline_dynamic_css' ), $priority );
add_action( 'enqueue_block_editor_assets', array( $this, 'inline_dynamic_css' ), $priority );
// If we're using file method, on save write the new styles.
if ( 'file' === $method ) {
$this->css_to_file = new Kirki_CSS_To_File();
add_action( 'customize_save_after', array( $this->css_to_file, 'write_file' ) );
if ( ! apply_filters( 'kirki_output_inline_styles', true ) ) {
$config = apply_filters( 'kirki_config', array() );
$priority = 999;
if ( isset( $config['styles_priority'] ) ) {
$priority = absint( $config['styles_priority'] );
}
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ), $priority );
// Prints the styles.
add_action( 'wp', array( $this, 'print_styles_action' ) );
return;
}
if ( 'file' === $method ) {
// Attempt to write the CSS to file.
$this->css_to_file = new Kirki_CSS_To_File();
// If we succesd, load this file.
$failed = get_transient( 'kirki_css_write_to_file_failed' );
// If writing CSS to file hasn't failed, just enqueue this file.
if ( ! $failed ) {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_compiled_file' ), $priority );
return;
}
}
// If we are in the customizer, load CSS using inline-styles.
// If we are in the frontend AND self::$ajax is true, then load dynamic CSS using AJAX.
if ( ( true === self::$ajax ) || ( isset( $config['inline_css'] ) && false === $config['inline_css'] ) ) {
add_action( 'wp_enqueue_scripts', array( $this, 'frontend_styles' ), $priority );
add_action( 'wp_ajax_kirki_dynamic_css', array( $this, 'ajax_dynamic_css' ) );
add_action( 'wp_ajax_nopriv_kirki_dynamic_css', array( $this, 'ajax_dynamic_css' ) );
return;
}
// If we got this far then add styles inline.
add_action( 'wp_enqueue_scripts', array( $this, 'inline_dynamic_css' ), $priority );
// Admin styles, adds Gutenberg compatibility.
add_action( 'admin_enqueue_scripts', array( $this, 'inline_dynamic_css' ), $priority );
add_action( 'wp_head', array( $this, 'print_styles_inline' ), 999 );
}
/**
* Enqueues compiled CSS file.
* Print styles inline.
*
* @access public
* @since 3.0.0
* @since 3.0.36
* @return void
*/
public function enqueue_compiled_file() {
wp_enqueue_style( 'kirki-styles', $this->css_to_file->get_url(), array(), $this->css_to_file->get_timestamp() );
public function print_styles_inline() {
echo '<style id="kirki-inline-styles">';
$this->print_styles();
echo '</style>';
}
/**
* Adds inline styles.
* Enqueue the styles.
*
* @access public
* @since 3.0.36
* @return void
*/
public function inline_dynamic_css() {
$configs = Kirki::$config;
if ( ! $this->processed ) {
foreach ( $configs as $config_id => $args ) {
if ( isset( $args['disable_output'] ) && true === $args['disable_output'] ) {
continue;
}
$styles = self::loop_controls( $config_id );
$styles = apply_filters( "kirki_{$config_id}_dynamic_css", $styles );
if ( ! empty( $styles ) ) {
$stylesheet = apply_filters( "kirki_{$config_id}_stylesheet", false );
if ( $stylesheet ) {
wp_add_inline_style( $stylesheet, $styles );
continue;
}
wp_enqueue_style( 'kirki-styles-' . $config_id, trailingslashit( Kirki::$url ) . 'assets/css/kirki-styles.css', array(), KIRKI_VERSION );
wp_add_inline_style( 'kirki-styles-' . $config_id, $styles );
}
}
$this->processed = true;
}
public function enqueue_styles() {
// Enqueue the dynamic stylesheet.
wp_enqueue_style(
'kirki-styles',
add_query_arg(
'action',
apply_filters( 'kirki_styles_action_handle', 'kirki-styles' ),
site_url()
),
array(),
KIRKI_VERSION
);
// Enqueue FA if needed (I hope not, this FA version is pretty old, only kept here for backwards-compatibility purposes).
if ( self::$enqueue_fa && apply_filters( 'kirki_load_fontawesome', true ) ) {
wp_enqueue_script( 'kirki-fontawesome-font', 'https://use.fontawesome.com/30858dc40a.js', array(), '4.0.7', true );
}
}
/**
* Get the dynamic-css.php file
* Prints the styles as an enqueued file.
*
* @access public
* @since 3.0.36
* @return void
*/
public function ajax_dynamic_css() {
require wp_normalize_path( Kirki::$path . '/modules/css/dynamic-css.php' );
public function print_styles_action() {
/**
* Note to code reviewers:
* There is no need for a nonce check here, we're only checking if this is a valid request or not.
*/
if ( empty( $_GET['action'] ) || apply_filters( 'kirki_styles_action_handle', 'kirki-styles' ) !== $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
return;
}
// This is a stylesheet.
header( 'Content-type: text/css' );
$this->print_styles();
exit;
}
/**
* Enqueues the ajax stylesheet.
* Prints the styles.
*
* @access public
*/
public function frontend_styles() {
wp_enqueue_style( 'kirki-styles-php', admin_url( 'admin-ajax.php' ) . '?action=kirki_dynamic_css', array(), KIRKI_VERSION );
public function print_styles() {
// Go through all configs.
$configs = Kirki::$config;
foreach ( $configs as $config_id => $args ) {
if ( isset( $args['disable_output'] ) && true === $args['disable_output'] ) {
continue;
}
$styles = self::loop_controls( $config_id );
$styles = apply_filters( "kirki_{$config_id}_dynamic_css", $styles );
if ( ! empty( $styles ) ) {
/**
* Note to code reviewers:
*
* Though all output should be run through an escaping function, this is pure CSS.
*
* When used in the print_styles_action() method the PHP header() call makes the browser interpret it as such.
* No code, script or anything else can be executed from inside a stylesheet.
*
* When using in the print_styles_inline() method the wp_strip_all_tags call we use below
* strips anything that has the possibility to be malicious, and since this is inslide a <style> tag
* it can only be interpreted by the browser as such.
* wp_strip_all_tags() excludes the possibility of someone closing the <style> tag and then opening something else.
*/
echo wp_strip_all_tags( $styles ); // phpcs:ignore WordPress.Security.EscapeOutput
}
}
do_action( 'kirki_dynamic_css' );
}
/**
@ -326,7 +303,7 @@ class Kirki_Modules_CSS {
* @static
* @since 3.0.35
* @access public
* @return void
* @return bool
*/
public static function get_enqueue_fa() {
return self::$enqueue_fa;

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/
@ -106,7 +106,7 @@ class Kirki_Output {
}
if ( is_array( $value ) ) {
foreach ( array_keys( $value ) as $value_k ) {
if ( ! is_string( $value[ $value_k ] ) ) {
if ( is_array( $value[ $value_k ] ) ) {
continue;
}
if ( isset( $output['choice'] ) ) {
@ -164,6 +164,9 @@ class Kirki_Output {
break;
default:
$replacement = get_theme_mod( $replace );
if ( ! $replacement ) {
$replacement = Kirki_Values::get_value( $this->field['kirki_config'], $replace );
}
}
$replacement = ( false === $replacement ) ? '' : $replacement;
if ( is_array( $value ) ) {
@ -243,10 +246,10 @@ class Kirki_Output {
if ( is_admin() && ! is_customize_preview() ) {
// Check if this is an admin style.
if ( ! isset( $output['context'] ) || ! in_array( 'editor', $output['context'] ) ) {
if ( ! isset( $output['context'] ) || ! in_array( 'editor', $output['context'], true ) ) {
continue;
}
} elseif ( isset( $output['context'] ) && ! in_array( 'front', $output['context'] ) ) {
} elseif ( isset( $output['context'] ) && ! in_array( 'front', $output['context'], true ) ) {
// Check if this is a frontend style.
continue;
@ -304,7 +307,8 @@ class Kirki_Output {
*/
protected function process_property_value( $property, $value ) {
$properties = apply_filters(
"kirki_{$this->config_id}_output_property_classnames", array(
"kirki_{$this->config_id}_output_property_classnames",
array(
'font-family' => 'Kirki_Output_Property_Font_Family',
'background-image' => 'Kirki_Output_Property_Background_Image',
'background-position' => 'Kirki_Output_Property_Background_Position',

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/
@ -23,7 +23,8 @@ class Kirki_Output_Field_Dimensions extends Kirki_Output {
*/
protected function process_output( $output, $value ) {
$output = wp_parse_args(
$output, array(
$output,
array(
'element' => '',
'property' => '',
'media_query' => 'global',

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.10
*/
@ -26,7 +26,8 @@ class Kirki_Output_Field_Image extends Kirki_Output {
return;
}
$output = wp_parse_args(
$output, array(
$output,
array(
'media_query' => 'global',
'prefix' => '',
'units' => '',

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/
@ -81,7 +81,8 @@ class Kirki_Output_Field_Typography extends Kirki_Output {
if ( 'font-family' === $property ) {
$value['font-backup'] = ( isset( $value['font-backup'] ) ) ? $value['font-backup'] : '';
$property_value = $this->process_property_value(
$property, array(
$property,
array(
$value['font-family'],
$value['font-backup'],
)

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -5,7 +5,7 @@
*
* @package Kirki
* @subpackage Controls
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -5,8 +5,8 @@
* @package Kirki
* @category Modules
* @subpackage Custom Sections Module
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
@ -81,6 +81,7 @@ class Kirki_Modules_Custom_Sections {
'kirki-default' => 'Kirki_Sections_Default_Section',
'kirki-expanded' => 'Kirki_Sections_Expanded_Section',
'kirki-nested' => 'Kirki_Sections_Nested_Section',
'kirki-link' => 'Kirki_Sections_Link_Section',
);
return array_merge( $section_types, $new_types );
}
@ -116,12 +117,12 @@ class Kirki_Modules_Custom_Sections {
if ( ! class_exists( $class ) ) {
$path = wp_normalize_path( $folder_path . 'class-kirki-sections-' . $id . '-section.php' );
if ( file_exists( $path ) ) {
include_once $path;
include_once $path; // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
continue;
}
$path = str_replace( 'class-kirki-sections-kirki-', 'class-kirki-sections-', $path );
if ( file_exists( $path ) ) {
include_once $path;
include_once $path; // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
}
}
}
@ -134,12 +135,12 @@ class Kirki_Modules_Custom_Sections {
if ( ! class_exists( $class ) ) {
$path = wp_normalize_path( $folder_path . 'class-kirki-panels-' . $id . '-panel.php' );
if ( file_exists( $path ) ) {
include_once $path;
include_once $path; // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
continue;
}
$path = str_replace( 'class-kirki-panels-kirki-', 'class-kirki-panels-', $path );
if ( file_exists( $path ) ) {
include_once $path;
include_once $path; // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
}
}
}

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Custom Sections Module
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
@ -41,7 +41,8 @@ class Kirki_Panels_Nested_Panel extends WP_Customize_Panel {
*/
public function json() {
$array = wp_array_slice_assoc(
(array) $this, array(
(array) $this,
array(
'id',
'description',
'priority',

View file

@ -1,26 +1,22 @@
#customize-theme-controls .control-section-kirki-expanded .accordion-section-title {
display: none;
}
display: none; }
#customize-theme-controls .control-section-kirki-expanded .customize-section-back {
display: none;
}
display: none; }
#customize-theme-controls .customize-pane-child.control-section-kirki-expanded {
position: relative;
visibility: visible;
height: auto;
margin-left: -100%;
}
#customize-theme-controls .customize-pane-child.control-section-kirki-expanded h3 .customize-action {
display: none;
}
margin-left: -100%; }
#customize-theme-controls .customize-pane-child.control-section-kirki-expanded h3 .customize-action {
display: none; }
#customize-theme-controls .control-section-kirki-link .button {
margin-top: -3px; }
#customize-theme-controls .customize-pane-child.current-section-parent,
.in-sub-panel #customize-theme-controls .customize-pane-child.current-panel-parent {
transform: translateX(-100%);
}
transform: translateX(-100%); }
.control-section-kirki-nested {
margin: 0 -12px;
}
margin: 0 -12px; }
/*# sourceMappingURL=sections.css.map */

View file

@ -15,9 +15,20 @@ jQuery( document ).ready( function() {
}
} );
} );
/**
* See https://github.com/justintadlock/trt-customizer-pro
*/
( function() {
wp.customize.sectionConstructor['kirki-link'] = wp.customize.Section.extend( {
attachEvents: function() {},
isContextuallyActive: function() {
return true;
}
} );
} () );
/**
* @see https://wordpress.stackexchange.com/a/256103/17078
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Custom Sections Module
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Custom Sections Module
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/

View file

@ -0,0 +1,78 @@
<?php
/**
* The default section.
* Inspired from https://github.com/justintadlock/trt-customizer-pro
*
* @package Kirki
* @subpackage Custom Sections Module
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.36
*/
/**
* Link Section.
*/
class Kirki_Sections_Link_Section extends WP_Customize_Section {
/**
* The section type.
*
* @since 3.0.36
* @access public
* @var string
*/
public $type = 'kirki-link';
/**
* Button Text
*
* @since 3.0.36
* @access public
* @var string
*/
public $button_text = '';
/**
* Button URL.
*
* @since 3.0.36
* @access public
* @var string
*/
public $button_url = '';
/**
* Gather the parameters passed to client JavaScript via JSON.
*
* @access public
* @since 3.0.36
* @return array The array to be exported to the client as JSON.
*/
public function json() {
$json = parent::json();
$json['button_text'] = $this->button_text;
$json['button_url'] = esc_url( $this->button_url );
return $json;
}
/**
* Outputs the Underscore.js template.
*
* @since 3.0.36
* @access public
* @return void
*/
protected function render_template() {
?>
<li id="accordion-section-{{ data.id }}" class="accordion-section control-section control-section-{{ data.type }} cannot-expand">
<h3 class="accordion-section-title">
{{ data.title }}
<a href="{{ data.button_url }}" class="button alignright" target="_blank" rel="nofollow">{{ data.button_text }}</a>
</h3>
</li>
<?php
}
}

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Custom Sections Module
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 2.2.0
*/
@ -41,7 +41,8 @@ class Kirki_Sections_Nested_Section extends WP_Customize_Section {
*/
public function json() {
$array = wp_array_slice_assoc(
(array) $this, array(
(array) $this,
array(
'id',
'description',
'priority',

View file

@ -6,8 +6,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -7,8 +7,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -9,7 +9,7 @@
* @package Kirki
* @category Core
* @author Tim Elsass
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.35
*/
@ -76,15 +76,6 @@ class Kirki_Modules_Gutenberg {
*/
private $google_fonts;
/**
* Webfonts Loader Module reference.
*
* @access public
* @since 3.0.35
* @var object $modules_webfonts
*/
private $modules_webfont_loader;
/**
* Constructor.
*
@ -108,7 +99,6 @@ class Kirki_Modules_Gutenberg {
$this->set_modules_css();
$this->set_google_fonts();
$this->set_modules_webfonts();
$this->set_modules_webfont_loader();
$this->add_hooks();
}
@ -137,7 +127,6 @@ class Kirki_Modules_Gutenberg {
protected function add_hooks() {
if ( ! $this->is_disabled() ) {
add_action( 'after_setup_theme', array( $this, 'add_theme_support' ), 999 );
add_action( 'enqueue_block_editor_assets', array( $this, 'load_fonts' ) );
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_fontawesome' ) );
add_filter( 'block_editor_settings', array( $this, 'enqueue' ) );
}
@ -162,6 +151,7 @@ class Kirki_Modules_Gutenberg {
* Enqueue styles to Gutenberg Editor.
*
* @access public
* @param array $settings The settings for styles.
* @since 3.0.35
*/
public function enqueue( $settings ) {
@ -193,7 +183,7 @@ class Kirki_Modules_Gutenberg {
}
$modules_css = $this->modules_css;
$styles = $modules_css::loop_controls( $config_id );
$styles = $modules_css::loop_controls( $config_id ); // phpcs:ignore PHPCompatibility.Syntax.NewDynamicAccessToStatic
$styles = apply_filters( "kirki_gutenberg_{$config_id}_dynamic_css", $styles );
if ( empty( $styles ) ) {
@ -211,6 +201,7 @@ class Kirki_Modules_Gutenberg {
* gutenbeg_support argument, and disabled output argument.
*
* @access public
* @param array $args An array of arguments.
* @since 3.0.35
*
* @return bool $disabled Is gutenberg integration feature disabled?
@ -233,45 +224,6 @@ class Kirki_Modules_Gutenberg {
return false;
}
/**
* Load Fonts in Gutenberg Editor.
*
* @access public
* @since 3.0.35
*/
public function load_fonts() {
$modules_webfonts = $this->modules_webfonts;
$google_fonts = $this->google_fonts;
foreach ( $this->configs as $config_id => $args ) {
if ( $this->is_disabled( $args ) ) {
continue;
}
$this->modules_webfont_loader->set_load( true );
$this->modules_webfont_loader->enqueue_scripts();
$async = new Kirki_Modules_Webfonts_Async(
$config_id,
$modules_webfonts::get_instance(),
$google_fonts::get_instance()
);
$async->webfont_loader();
$async->webfont_loader_script();
$local_fonts = new Kirki_Modules_Webfonts_Local(
$modules_webfonts::get_instance(),
$google_fonts::get_instance()
);
$local_fonts->add_styles();
return;
}
}
/**
* Enqueue fontawesome in Gutenberg Editor.
*
@ -285,7 +237,7 @@ class Kirki_Modules_Gutenberg {
continue;
}
$modules_css = $this->modules_css;
if ( $modules_css::get_enqueue_fa() && apply_filters( 'kirki_load_fontawesome', true ) ) {
if ( $modules_css::get_enqueue_fa() && apply_filters( 'kirki_load_fontawesome', true ) ) { // phpcs:ignore PHPCompatibility.Syntax.NewDynamicAccessToStatic
wp_enqueue_script( 'kirki-fontawesome-font', 'https://use.fontawesome.com/30858dc40a.js', array(), '4.0.7', true );
}
@ -300,7 +252,8 @@ class Kirki_Modules_Gutenberg {
* @since 3.0.35
*/
private function set_configs() {
return $this->configs = Kirki::$config;
$this->configs = Kirki::$config;
return $this->configs;
}
/**
@ -342,14 +295,4 @@ class Kirki_Modules_Gutenberg {
private function set_modules_webfonts() {
$this->modules_webfonts = Kirki_Modules_Webfonts::get_instance();
}
/**
* Set class property for $modules_webfont_loader.
*
* @access private
* @since 3.0.35
*/
private function set_modules_webfont_loader() {
$this->modules_webfont_loader = Kirki_Modules_Webfont_Loader::get_instance();
}
}

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -4,7 +4,7 @@
*
* @package Kirki
* @subpackage Modules
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
@ -30,15 +30,6 @@ class Kirki_Modules_PostMessage {
*/
private static $instance;
/**
* The script.
*
* @access protected
* @since 3.0.0
* @var string
*/
protected $script = '';
/**
* Constructor.
*
@ -73,443 +64,12 @@ class Kirki_Modules_PostMessage {
public function postmessage() {
wp_enqueue_script( 'kirki_auto_postmessage', trailingslashit( Kirki::$url ) . 'modules/postmessage/postmessage.js', array( 'jquery', 'customize-preview' ), KIRKI_VERSION, true );
$fields = Kirki::$fields;
$data = array();
foreach ( $fields as $field ) {
if ( isset( $field['transport'] ) && 'postMessage' === $field['transport'] && isset( $field['js_vars'] ) && ! empty( $field['js_vars'] ) && is_array( $field['js_vars'] ) && isset( $field['settings'] ) ) {
$this->script .= $this->script( $field );
$data[] = $field;
}
}
$this->script = apply_filters( 'kirki_postmessage_script', $this->script );
wp_add_inline_script( 'kirki_auto_postmessage', $this->script, 'after' );
}
/**
* Generates script for a single field.
*
* @access protected
* @since 3.0.0
* @param array $args The arguments.
*/
protected function script( $args ) {
$script = 'wp.customize(\'' . $args['settings'] . '\',function(value){value.bind(function(newval){';
$add_css = false;
foreach ( $args['js_vars'] as $js_var ) {
if ( ! isset( $js_var['function'] ) || 'html' !== $js_var['function'] ) {
$add_css = true;
}
}
if ( $add_css ) {
// append unique style tag if not exist
// The style ID.
$style_id = 'kirki-postmessage-' . str_replace( array( '[', ']' ), '', $args['settings'] );
$script .= 'if(null===document.getElementById(\'' . $style_id . '\')||\'undefined\'===typeof document.getElementById(\'' . $style_id . '\')){jQuery(\'head\').append(\'<style id="' . $style_id . '"></style>\');}';
}
// Add anything we need before the main script.
$script .= $this->before_script( $args );
$field = array(
'scripts' => array(),
);
// Loop through the js_vars and generate the script.
foreach ( $args['js_vars'] as $key => $js_var ) {
// Skip styles if "exclude" is defined and value is excluded.
if ( isset( $js_var['exclude'] ) ) {
$js_var['exclude'] = (array) $js_var['exclude'];
$script .= 'exclude=false;';
foreach ( $js_var['exclude'] as $exclussion ) {
$script .= "if(newval=='{$exclussion}'||(''==='{$exclussion}'&&_.isObject(newval)&&_.isEmpty(newval))){exclude=true;}";
}
}
if ( isset( $js_var['element'] ) ) {
// Array to string.
if ( is_array( $js_var['element'] ) ) {
$js_var['element'] = implode( ',', $js_var['element'] );
}
// Replace single quotes with double quotes to avoid issues with the compiled JS.
$js_var['element'] = str_replace( '\'', '"', $js_var['element'] );
}
if ( isset( $js_var['function'] ) && 'html' === $js_var['function'] ) {
$script .= $this->script_html_var( $js_var );
continue;
}
$js_var['index_key'] = $key;
$callback = $this->get_callback( $args );
if ( is_callable( $callback ) ) {
$field['scripts'][ $key ] = call_user_func_array( $callback, array( $js_var, $args ) );
continue;
}
$field['scripts'][ $key ] = $this->script_var( $js_var );
}
$combo_extra_script = '';
$combo_css_script = '';
foreach ( $field['scripts'] as $script_array ) {
$combo_extra_script .= $script_array['script'];
$combo_css_script .= ( 'css' !== $combo_css_script ) ? $script_array['css'] : '';
}
$text = ( 'css' === $combo_css_script ) ? 'css' : '\'' . $combo_css_script . '\'';
$script .= $combo_extra_script . "var cssContent={$text};";
if ( isset( $js_var['exclude'] ) ) {
$script .= 'if(true===exclude){cssContent="";}';
}
if ( $add_css ) {
$script .= "jQuery('#{$style_id}').text(cssContent);jQuery('#{$style_id}').appendTo('head');";
}
$script .= '});});';
return $script;
}
/**
* Generates script for a single js_var when using "html" as function.
*
* @access protected
* @since 3.0.0
* @param array $args The arguments for this js_var.
*/
protected function script_html_var( $args ) {
$script = ( isset( $args['choice'] ) ) ? "newval=newval['{$args['choice']}'];" : '';
// Apply the value_pattern.
if ( isset( $args['value_pattern'] ) && '' !== $args['value_pattern'] ) {
$script .= $this->value_pattern_replacements( 'newval', $args );
}
if ( isset( $args['attr'] ) ) {
$script .= "jQuery('{$args['element']}').attr('{$args['attr']}',newval);";
return $script;
}
$script .= "jQuery('{$args['element']}').html(newval);";
return $script;
}
/**
* Generates script for a single js_var.
*
* @access protected
* @since 3.0.0
* @param array $args The arguments for this js_var.
*/
protected function script_var( $args ) {
$script = '';
$property_script = '';
$value_key = 'newval' . $args['index_key'];
$property_script .= $value_key . '=newval;';
$args = $this->get_args( $args );
// Apply callback to the value if a callback is defined.
if ( ! empty( $args['js_callback'] ) && is_array( $args['js_callback'] ) && isset( $args['js_callback'][0] ) && ! empty( $args['js_callback'][0] ) ) {
$script .= $value_key . '=' . $args['js_callback'][0] . '(' . $value_key . ',' . $args['js_callback'][1] . ');';
}
// Apply the value_pattern.
if ( '' !== $args['value_pattern'] ) {
$script .= $this->value_pattern_replacements( $value_key, $args );
}
// Tweak to add url() for background-images.
if ( 'background-image' === $args['property'] && ( ! isset( $args['value_pattern'] ) || false === strpos( $args['value_pattern'], 'gradient' ) ) ) {
$script .= 'if(-1===' . $value_key . '.indexOf(\'url(\')){' . $value_key . '=\'url("\'+' . $value_key . '+\'")\';}';
}
// Apply prefix.
$value = $value_key;
if ( '' !== $args['prefix'] ) {
$value = "'" . $args['prefix'] . "'+" . $value_key;
}
$css = $args['element'] . '{' . $args['property'] . ':\'+' . $value . '+\'' . $args['units'] . $args['suffix'] . ';}';
if ( isset( $args['media_query'] ) ) {
$css = $args['media_query'] . '{' . $css . '}';
}
return array(
'script' => $property_script . $script,
'css' => $css,
);
}
/**
* Processes script generation for fields that save an array.
*
* @access protected
* @since 3.0.0
* @param array $args The arguments for this js_var.
*/
protected function script_var_array( $args ) {
$script = ( 0 === $args['index_key'] ) ? 'css=\'\';' : '';
$property_script = '';
// Define choice.
$choice = ( isset( $args['choice'] ) && '' !== $args['choice'] ) ? $args['choice'] : '';
$value_key = 'newval' . $args['index_key'];
$property_script .= $value_key . '=newval;';
$args = $this->get_args( $args );
// Apply callback to the value if a callback is defined.
if ( ! empty( $args['js_callback'] ) && is_array( $args['js_callback'] ) && isset( $args['js_callback'][0] ) && ! empty( $args['js_callback'][0] ) ) {
$script .= $value_key . '=' . $args['js_callback'][0] . '(' . $value_key . ',' . $args['js_callback'][1] . ');';
}
$script .= '_.each(' . $value_key . ', function(subValue,subKey){';
// Apply the value_pattern.
if ( '' !== $args['value_pattern'] ) {
$script .= $this->value_pattern_replacements( 'subValue', $args );
}
// Tweak to add url() for background-images.
if ( '' === $choice || 'background-image' === $choice ) {
$script .= 'if(\'background-image\'===\'' . $args['property'] . '\'||\'background-image\'===subKey){if(-1===subValue.indexOf(\'url(\')){subValue=\'url("\'+subValue+\'")\';}}';
}
// Apply prefix.
$value = $value_key;
if ( '' !== $args['prefix'] ) {
$value = '\'' . $args['prefix'] . '\'+subValue';
}
// Mostly used for padding, margin & position properties.
$direction_script = 'if(_.contains([\'top\',\'bottom\',\'left\',\'right\'],subKey)){';
$direction_script .= 'css+=\'' . $args['element'] . '{' . $args['property'] . '-\'+subKey+\':\'+subValue+\'' . $args['units'] . $args['suffix'] . ';}\';}';
// Allows us to apply this just for a specific choice in the array of the values.
if ( '' !== $choice ) {
$choice_is_direction = ( false !== strpos( $choice, 'top' ) || false !== strpos( $choice, 'bottom' ) || false !== strpos( $choice, 'left' ) || false !== strpos( $choice, 'right' ) );
// The script.
$script .= 'if(\'' . $choice . '\'===subKey){';
$script .= ( $choice_is_direction ) ? $direction_script . 'else{' : '';
$script .= 'css+=\'' . $args['element'] . '{' . $args['property'] . ':\'+subValue+\';}\';';
$script .= ( $choice_is_direction ) ? '}' : '';
$script .= '}';
} else {
// This is where most object-based fields will go.
$script .= $direction_script . 'else{css+=\'' . $args['element'] . '{\'+subKey+\':\'+subValue+\'' . $args['units'] . $args['suffix'] . ';}\';}';
}
$script .= '});';
if ( isset( $args['media_query'] ) ) {
$script .= 'css=\'' . $args['media_query'] . '{\'+css+\'}\';';
}
return array(
'script' => $property_script . $script,
'css' => 'css',
);
}
/**
* Processes script generation for typography fields.
*
* @access protected
* @since 3.0.0
* @param array $args The arguments for this js_var.
* @param array $field The field arguments.
*/
protected function script_var_typography( $args, $field ) {
$args = $this->get_args( $args );
$script = '';
$css = '';
// Load the font using WenFontloader.
// This is a bit ugly because wp_add_inline_script doesn't allow adding <script> directly.
$webfont_loader = 'sc=\'a\';jQuery(\'head\').append(sc.replace(\'a\',\'<\')+\'script>if(!_.isUndefined(WebFont)&&fontFamily){WebFont.load({google:{families:["\'+fontFamily.replace( /\"/g, \'&quot;\' )+\':\'+variant+\':cyrillic,cyrillic-ext,devanagari,greek,greek-ext,khmer,latin,latin-ext,vietnamese,hebrew,arabic,bengali,gujarati,tamil,telugu,thai"]}});}\'+sc.replace(\'a\',\'<\')+\'/script>\');';
// Add the css.
$css_build_array = array(
'font-family' => 'fontFamily',
'font-size' => 'fontSize',
'line-height' => 'lineHeight',
'letter-spacing' => 'letterSpacing',
'word-spacing' => 'wordSpacing',
'text-align' => 'textAlign',
'text-transform' => 'textTransform',
'text-decoration' => 'textDecoration',
'color' => 'color',
'font-weight' => 'fontWeight',
'font-style' => 'fontStyle',
);
$choice_condition = ( isset( $args['choice'] ) && '' !== $args['choice'] && isset( $css_build_array[ $args['choice'] ] ) );
$script .= ( ! $choice_condition ) ? $webfont_loader : '';
foreach ( $css_build_array as $property => $var ) {
if ( $choice_condition && $property !== $args['choice'] ) {
continue;
}
// Fixes https://github.com/aristath/kirki/issues/1436.
if ( ! isset( $field['default'] ) || (
( 'font-family' === $property && ! isset( $field['default']['font-family'] ) ) ||
( 'font-size' === $property && ! isset( $field['default']['font-size'] ) ) ||
( 'line-height' === $property && ! isset( $field['default']['line-height'] ) ) ||
( 'letter-spacing' === $property && ! isset( $field['default']['letter-spacing'] ) ) ||
( 'word-spacing' === $property && ! isset( $field['default']['word-spacing'] ) ) ||
( 'text-align' === $property && ! isset( $field['default']['text-align'] ) ) ||
( 'text-transform' === $property && ! isset( $field['default']['text-transform'] ) ) ||
( 'text-decoration' === $property && ! isset( $field['default']['text-decoration'] ) ) ||
( 'color' === $property && ! isset( $field['default']['color'] ) ) ||
( 'font-weight' === $property && ! isset( $field['default']['variant'] ) && ! isset( $field['default']['font-weight'] ) ) ||
( 'font-style' === $property && ! isset( $field['default']['variant'] ) && ! isset( $field['default']['font-style'] ) )
) ) {
continue;
}
$script .= ( $choice_condition && 'font-family' === $args['choice'] ) ? $webfont_loader : '';
if ( 'font-family' === $property || ( isset( $args['choice'] ) && 'font-family' === $args['choice'] ) ) {
$css .= 'fontFamilyCSS=fontFamily;if(0<fontFamily.indexOf(\' \')&&-1===fontFamily.indexOf(\'"\')){fontFamilyCSS=\'"\'+fontFamily+\'"\';}';
$var = 'fontFamilyCSS';
}
$var = ( ( empty( $args['prefix'] ) ) ? '' : '\'' . $args['prefix'] . '\'+' ) . $var . ( ( empty( $args['units'] ) ) ? '' : '+\'' . $args['units'] . '\'' ) . ( ( empty( $args['suffix'] ) ) ? '' : '+\'' . $args['suffix'] . '\'' );
$css .= 'css+=(\'\'!==' . $var . ')?\'' . $args['element'] . '\'+\'{' . $property . ':\'+' . $var . '+\';}\':\'\';';
}
$script .= $css;
if ( isset( $args['media_query'] ) ) {
$script .= 'css=\'' . $args['media_query'] . '{\'+css+\'}\';';
}
return array(
'script' => $script,
'css' => 'css',
);
}
/**
* Processes script generation for typography fields.
*
* @access protected
* @since 3.0.0
* @param array $args The arguments for this js_var.
*/
protected function script_var_image( $args ) {
$return = $this->script_var( $args );
return array(
'script' => 'newval=(!_.isUndefined(newval.url))?newval.url:newval;' . $return['script'],
'css' => $return['css'],
);
}
/**
* Adds anything we need before the main script.
*
* @access private
* @since 3.0.0
* @param array $args The field args.
* @return string
*/
private function before_script( $args ) {
$script = '';
if ( isset( $args['type'] ) ) {
switch ( $args['type'] ) {
case 'kirki-typography':
$script .= 'fontFamily=(_.isUndefined(newval[\'font-family\']))?\'\':newval[\'font-family\'];variant=(_.isUndefined(newval.variant))?\'400\':newval.variant;fontSize=(_.isUndefined(newval[\'font-size\']))?\'\':newval[\'font-size\'];lineHeight=(_.isUndefined(newval[\'line-height\']))?\'\':newval[\'line-height\'];letterSpacing=(_.isUndefined(newval[\'letter-spacing\']))?\'\':newval[\'letter-spacing\'];wordSpacing=(_.isUndefined(newval[\'word-spacing\']))?\'\':newval[\'word-spacing\'];textAlign=(_.isUndefined(newval[\'text-align\']))?\'\':newval[\'text-align\'];textTransform=(_.isUndefined(newval[\'text-transform\']))?\'\':newval[\'text-transform\'];textDecoration=(_.isUndefined(newval[\'text-decoration\']))?\'\':newval[\'text-decoration\'];color=(_.isUndefined(newval.color))?\'\':newval.color;fw=(!_.isString(newval.variant))?\'400\':newval.variant.match(/\d/g);fontWeight=(!_.isObject(fw))?400:fw.join(\'\');fontStyle=(variant&&-1!==variant.indexOf(\'italic\'))?\'italic\':\'normal\';css=\'\';';
break;
}
}
return $script;
}
/**
* Sanitizes the arguments and makes sure they are all there.
*
* @access private
* @since 3.0.0
* @param array $args The arguments.
* @return array
*/
private function get_args( $args ) {
// Make sure everything is defined to avoid "undefined index" errors.
$args = wp_parse_args(
$args, array(
'element' => '',
'property' => '',
'prefix' => '',
'suffix' => '',
'units' => '',
'js_callback' => array( '', '' ),
'value_pattern' => '',
)
);
// Element should be a string.
if ( is_array( $args['element'] ) ) {
$args['element'] = implode( ',', $args['element'] );
}
// Make sure arguments that are passed-on to callbacks are strings.
if ( is_array( $args['js_callback'] ) && isset( $args['js_callback'][1] ) && is_array( $args['js_callback'][1] ) ) {
$args['js_callback'][1] = wp_json_encode( $args['js_callback'][1] );
}
if ( ! isset( $args['js_callback'][1] ) ) {
$args['js_callback'][1] = '';
}
return $args;
}
/**
* Returns script for value_pattern & replacements.
*
* @access private
* @since 3.0.0
* @param string $value The value placeholder.
* @param array $js_vars The js_vars argument.
* @return string The script.
*/
private function value_pattern_replacements( $value, $js_vars ) {
$script = '';
$alias = $value;
if ( ! isset( $js_vars['value_pattern'] ) ) {
return $value;
}
$value = $js_vars['value_pattern'];
if ( isset( $js_vars['pattern_replace'] ) ) {
$script .= 'settings=window.wp.customize.get();';
foreach ( $js_vars['pattern_replace'] as $search => $replace ) {
$replace = '\'+settings["' . $replace . '"]+\'';
$value = str_replace( $search, $replace, $js_vars['value_pattern'] );
$value = trim( $value, '+' );
}
}
$value_compiled = str_replace( '$', '\'+' . $alias . '+\'', $value );
$value_compiled = trim( $value_compiled, '+' );
return $script . $alias . '=\'' . $value_compiled . '\';';
}
/**
* Get the callback function/method we're going to use for this field.
*
* @access private
* @since 3.0.0
* @param array $args The field args.
* @return string|array A callable function or method.
*/
protected function get_callback( $args ) {
switch ( $args['type'] ) {
case 'kirki-background':
case 'kirki-dimensions':
case 'kirki-multicolor':
case 'kirki-sortable':
$callback = array( $this, 'script_var_array' );
break;
case 'kirki-typography':
$callback = array( $this, 'script_var_typography' );
break;
case 'kirki-image':
$callback = array( $this, 'script_var_image' );
break;
default:
$callback = array( $this, 'script_var' );
}
return $callback;
wp_localize_script( 'kirki_auto_postmessage', 'kirkiPostMessageFields', $data );
}
}

View file

@ -1,4 +1,344 @@
/**
* This file is empty on purpose.
* Scripts are added dynamically using wp_add_inline_script() on this.
*/
/* global kirkiPostMessageFields, WebFont */
var kirkiPostMessage = {
/**
* The fields.
*
* @since 3.0.26
*/
fields: {},
/**
* A collection of methods for the <style> tags.
*
* @since 3.0.26
*/
styleTag: {
/**
* Add a <style> tag in <head> if it doesn't already exist.
*
* @since 3.0.26
* @param {string} id - The field-ID.
* @returns {void}
*/
add: function( id ) {
if ( null === document.getElementById( 'kirki-postmessage-' + id ) || 'undefined' === typeof document.getElementById( 'kirki-postmessage-' + id ) ) {
jQuery( 'head' ).append( '<style id="kirki-postmessage-' + id + '"></style>' );
}
},
/**
* Add a <style> tag in <head> if it doesn't already exist,
* by calling the this.add method, and then add styles inside it.
*
* @since 3.0.26
* @param {string} id - The field-ID.
* @param {string} styles - The styles to add.
* @returns {void}
*/
addData: function( id, styles ) {
kirkiPostMessage.styleTag.add( id );
jQuery( '#kirki-postmessage-' + id ).text( styles );
}
},
/**
* Common utilities.
*
* @since 3.0.26
*/
util: {
/**
* Processes the value and applies any replacements and/or additions.
*
* @since 3.0.26
* @param {Object} output - The output (js_vars) argument.
* @param {mixed} value - The value.
* @param {string} controlType - The control-type.
* @returns {string|false} - Returns false if value is excluded, otherwise a string.
*/
processValue: function( output, value ) {
var self = this,
settings = window.parent.wp.customize.get(),
excluded = false;
if ( 'object' === typeof value ) {
_.each( value, function( subValue, key ) {
value[ key ] = self.processValue( output, subValue );
} );
return value;
}
output = _.defaults( output, {
prefix: '',
units: '',
suffix: '',
value_pattern: '$',
pattern_replace: {},
exclude: []
} );
if ( 1 <= output.exclude.length ) {
_.each( output.exclude, function( exclusion ) {
if ( value == exclusion ) {
excluded = true;
}
} );
}
if ( excluded ) {
return false;
}
value = output.value_pattern.replace( new RegExp( '\\$', 'g' ), value );
_.each( output.pattern_replace, function( id, placeholder ) {
if ( ! _.isUndefined( settings[ id ] ) ) {
value = value.replace( placeholder, settings[ id ] );
}
} );
return output.prefix + value + output.units + output.suffix;
},
/**
* Make sure urls are properly formatted for background-image properties.
*
* @since 3.0.26
* @param {string} url - The URL.
* @returns {string}
*/
backgroundImageValue: function( url ) {
return ( -1 === url.indexOf( 'url(' ) ) ? 'url(' + url + ')' : url;
}
},
/**
* A collection of utilities for CSS generation.
*
* @since 3.0.26
*/
css: {
/**
* Generates the CSS from the output (js_vars) parameter.
*
* @since 3.0.26
* @param {Object} output - The output (js_vars) argument.
* @param {mixed} value - The value.
* @param {string} controlType - The control-type.
* @returns {string}
*/
fromOutput: function( output, value, controlType ) {
var styles = '',
kirkiParent = window.parent.kirki,
googleFont = '',
mediaQuery = false,
processedValue;
if ( output.js_callback && 'function' === typeof window[ output.js_callback ] ) {
value = window[ output.js_callback[0] ]( value, output.js_callback[1] );
}
switch ( controlType ) {
case 'kirki-typography':
styles += output.element + '{';
_.each( value, function( val, key ) {
if ( output.choice && key !== output.choice ) {
return;
}
processedValue = kirkiPostMessage.util.processValue( output, val );
if ( false !== processedValue ) {
styles += key + ':' + processedValue + ';';
}
} );
styles += '}';
// Check if this is a googlefont so that we may load it.
if ( ! _.isUndefined( WebFont ) && value['font-family'] && 'google' === kirkiParent.util.webfonts.getFontType( value['font-family'] ) ) {
// Calculate the googlefont params.
googleFont = value['font-family'].replace( /\"/g, '&quot;' );
if ( value.variant ) {
if ( 'regular' === value.variant ) {
googleFont += ':400';
} else if ( 'italic' === value.variant ) {
googleFont += ':400i';
} else {
googleFont += ':' + value.variant;
}
}
googleFont += ':cyrillic,cyrillic-ext,devanagari,greek,greek-ext,khmer,latin,latin-ext,vietnamese,hebrew,arabic,bengali,gujarati,tamil,telugu,thai';
WebFont.load( {
google: {
families: [ googleFont ]
}
} );
}
break;
case 'kirki-background':
case 'kirki-dimensions':
case 'kirki-multicolor':
case 'kirki-sortable':
styles += output.element + '{';
_.each( value, function( val, key ) {
if ( output.choice && key !== output.choice ) {
return;
}
if ( 'background-image' === key ) {
val = kirkiPostMessage.util.backgroundImageValue( val );
}
processedValue = kirkiPostMessage.util.processValue( output, val );
if ( false !== processedValue ) {
// Mostly used for padding, margin & position properties.
if ( output.property ) {
styles += output.property;
if ( '' !== output.property && ( 'top' === key || 'bottom' === key || 'left' === key || 'right' === key ) ) {
styles += '-' + key;
}
styles += ':' + processedValue + ';';
} else {
styles += key + ':' + processedValue + ';';
}
}
} );
styles += '}';
break;
default:
if ( 'kirki-image' === controlType ) {
value = ( ! _.isUndefined( value.url ) ) ? kirkiPostMessage.util.backgroundImageValue( value.url ) : kirkiPostMessage.util.backgroundImageValue( value );
}
if ( _.isObject( value ) ) {
styles += output.element + '{';
_.each( value, function( val, key ) {
if ( output.choice && key !== output.choice ) {
return;
}
processedValue = kirkiPostMessage.util.processValue( output, val );
if ( ! output.property ) {
output.property = key;
}
if ( false !== processedValue ) {
styles += output.property + ':' + processedValue + ';';
}
} );
styles += '}';
} else {
processedValue = kirkiPostMessage.util.processValue( output, value );
if ( false !== processedValue ) {
styles += output.element + '{' + output.property + ':' + processedValue + ';}';
}
}
break;
}
// Get the media-query.
if ( output.media_query && 'string' === typeof output.media_query && ! _.isEmpty( output.media_query ) ) {
mediaQuery = output.media_query;
if ( -1 === mediaQuery.indexOf( '@media' ) ) {
mediaQuery = '@media ' + mediaQuery;
}
}
// If we have a media-query, add it and return.
if ( mediaQuery ) {
return mediaQuery + '{' + styles + '}';
}
// Return the styles.
return styles;
}
},
/**
* A collection of utilities to change the HTML in the document.
*
* @since 3.0.26
*/
html: {
/**
* Modifies the HTML from the output (js_vars) parameter.
*
* @since 3.0.26
* @param {Object} output - The output (js_vars) argument.
* @param {mixed} value - The value.
* @returns {string}
*/
fromOutput: function( output, value ) {
if ( output.js_callback && 'function' === typeof window[ output.js_callback ] ) {
value = window[ output.js_callback[0] ]( value, output.js_callback[1] );
}
if ( _.isObject( value ) || _.isArray( value ) ) {
if ( ! output.choice ) {
return;
}
_.each( value, function( val, key ) {
if ( output.choice && key !== output.choice ) {
return;
}
value = val;
} );
}
value = kirkiPostMessage.util.processValue( output, value );
if ( output.attr ) {
jQuery( output.element ).attr( output.attr, value );
} else {
jQuery( output.element ).html( value );
}
}
},
/**
* A collection of utilities to allow toggling a CSS class.
*
* @since 3.0.26
*/
toggleClass: {
/**
* Toggles a CSS class from the output (js_vars) parameter.
*
* @since 3.0.21
* @param {Object} output - The output (js_vars) argument.
* @param {mixed} value - The value.
* @returns {string}
*/
fromOutput: function( output, value ) {
if ( 'undefined' === typeof output.class || 'undefined' === typeof output.value ) {
return;
}
if ( value === output.value && ! jQuery( output.element ).hasClass( output.class ) ) {
jQuery( output.element ).addClass( output.class );
} else {
jQuery( output.element ).removeClass( output.class );
}
}
}
};
jQuery( document ).ready( function() {
_.each( kirkiPostMessageFields, function( field ) {
wp.customize( field.settings, function( value ) {
value.bind( function( newVal ) {
var styles = '';
_.each( field.js_vars, function( output ) {
if ( ! output.function || 'undefined' === typeof kirkiPostMessage[ output.function ] ) {
output.function = 'css';
}
if ( 'css' === output.function ) {
styles += kirkiPostMessage.css.fromOutput( output, newVal, field.type );
} else {
kirkiPostMessage[ output.function ].fromOutput( output, newVal, field.type );
}
} );
kirkiPostMessage.styleTag.addData( field.settings, styles );
} );
} );
} );
} );

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.26
*/

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
@ -75,7 +75,8 @@ class Kirki_Modules_Selective_Refresh {
// If we have all we need, create the selective refresh call.
if ( isset( $partial_refresh_args['render_callback'] ) && isset( $partial_refresh_args['selector'] ) ) {
$partial_refresh_args = wp_parse_args(
$partial_refresh_args, array(
$partial_refresh_args,
array(
'settings' => $field['settings'],
)
);

View file

@ -0,0 +1,295 @@
<?php
/**
* Telemetry implementation for Kirki.
*
* @package Kirki
* @category Core
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license http://opensource.org/licenses/https://opensource.org/licenses/MIT
* @since 3.0.36
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Telemetry implementation.
*/
final class Kirki_Modules_Telemetry {
/**
* The object instance.
*
* @static
* @access private
* @since 3.0.36
* @var object
*/
private static $instance;
/**
* Constructor.
*
* @access protected
* @since 3.0.36
*/
protected function __construct() {
// Early exit if telemetry is disabled.
if ( ! apply_filters( 'kirki_telemetry', true ) ) {
return;
}
add_action( 'init', array( $this, 'init' ) );
add_action( 'admin_notices', array( $this, 'admin_notice' ) );
}
/**
* Gets an instance of this object.
* Prevents duplicate instances which avoid artefacts and improves performance.
*
* @static
* @access public
* @since 3.0.36
* @return object
*/
public static function get_instance() {
if ( ! self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Additional actions that run on init.
*
* @access public
* @since 3.0.36
* @return void
*/
public function init() {
$this->dismiss_notice();
$this->consent();
// This is the last thing to run. No impact on performance or anything else.
add_action( 'wp_footer', array( $this, 'maybe_send_data' ), 99999 );
}
/**
* Maybe send data.
*
* @access public
* @since 3.0.36
* @return void
*/
public function maybe_send_data() {
// Check if the user has consented to the data sending.
if ( ! get_option( 'kirki_telemetry_optin' ) ) {
return;
}
// Only send data once/month. We use an option instead of a transient
// because transients in some managed hosting environments don't properly update
// due to their caching implementations.
$sent = get_option( 'kirki_telemetry_sent' );
if ( ! $sent || $sent < time() - MONTH_IN_SECONDS ) {
$this->send_data();
update_option( 'kirki_telemetry_sent', time() );
}
}
/**
* Sends data.
*
* @access private
* @since 3.0.36
* @return void
*/
private function send_data() {
// Ping remote server.
wp_remote_post(
'https://wplemon.com/?action=kirki-stats',
array(
'method' => 'POST',
'blocking' => false,
'body' => array_merge(
array(
'action' => 'kirki-stats',
),
$this->get_data()
),
)
);
}
/**
* The admin-notice.
*
* @access private
* @since 3.0.36
* @return void
*/
public function admin_notice() {
// Early exit if the user has dismissed the consent, or if they have opted-in.
if ( get_option( 'kirki_telemetry_no_consent' ) || get_option( 'kirki_telemetry_optin' ) ) {
return;
}
$data = $this->get_data();
?>
<div class="notice notice-info kirki-telemetry">
<h3><strong><?php esc_html_e( 'Help us improve Kirki.', 'kirki' ); ?></strong></h3>
<p style="max-width: 76em;"><?php _e( 'Help us begin a dialogue with theme developers, collaborate and improve both the theme you are using and the Kirki framework by agreeing to send anonymous data. <strong>The data is completely anonymous and we will never collect any identifyable information about you or your website.</strong>', 'kirki' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></p>
<table class="data-to-send hidden widefat">
<thead>
<tr>
<th colspan="2"><?php esc_html_e( 'Data that will be sent', 'kirki' ); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td style="min-width: 200px;"><?php esc_html_e( 'PHP Version', 'kirki' ); ?></td>
<td><code><?php echo esc_html( $data['phpVer'] ); ?></code></td>
</tr>
<tr>
<td><?php esc_html_e( 'Theme Name', 'kirki' ); ?></td>
<td><code><?php echo esc_html( $data['themeName'] ); ?></code></td>
</tr>
<tr>
<td><?php esc_html_e( 'Theme Author', 'kirki' ); ?></td>
<td><code><?php echo esc_html( $data['themeAuthor'] ); ?></code></td>
</tr>
<tr>
<td><?php esc_html_e( 'Theme URI', 'kirki' ); ?></td>
<td><code><?php echo esc_html( $data['themeURI'] ); ?></code></td>
</tr>
<tr>
<td><?php esc_html_e( 'Field Types Used', 'kirki' ); ?></td>
<td><code><?php echo esc_html( implode( ',', $data['fieldTypes'] ) ); ?></code></td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2">
<?php
printf(
/* translators: %1$s: URL to the server plugin code. %2$s: URL to the stats page. */
__( 'We believe in complete transparency. You can see the code used on our server <a href="%1$s" rel="nofollow">here</a>, and the results of the statistics we\'re gathering on <a href="%2$s" rel="nofollow">this page</a>.', 'kirki' ), // phpcs:ignore WordPress.Security.EscapeOutput
'https://github.com/aristath/kirki-telemetry-server',
'https://wplemon.com/kirki-telemetry-statistics/'
);
?>
</th>
</tr>
</tfoot>
</table>
<p class="actions">
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'kirki-consent-notice', 'telemetry' ) ) ); ?>" class="button button-primary consent"><?php esc_html_e( 'I agree', 'kirki' ); ?></a>
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'kirki-hide-notice', 'telemetry' ) ) ); ?>" class="button button-secondary dismiss"><?php esc_html_e( 'No thanks', 'kirki' ); ?></a>
<a class="button button-link details details-show"><?php esc_html_e( 'Show me the data', 'kirki' ); ?></a>
<a class="button button-link details details-hide hidden"><?php esc_html_e( 'Collapse data', 'kirki' ); ?></a>
</p>
<script>
jQuery( '.kirki-telemetry a.details' ).on( 'click', function() {
jQuery( '.kirki-telemetry .data-to-send' ).toggleClass( 'hidden' );
jQuery( '.kirki-telemetry a.details-show' ).toggleClass( 'hidden' );
jQuery( '.kirki-telemetry a.details-hide' ).toggleClass( 'hidden' );
});
</script>
</div>
<?php
}
/**
* Builds and returns the data or uses cached if data already exists.
*
* @access private
* @since 3.0.36
* @return array
*/
private function get_data() {
// Get the theme.
$theme = wp_get_theme();
// Format the PHP version.
$php_version = phpversion( 'tidy' );
if ( ! $php_version ) {
$php_version = array_merge( explode( '.', phpversion() ), array( 0, 0 ) );
$php_version = "{$php_version[0]}.{$php_version[1]}";
}
// Build data and return the array.
return array(
'phpVer' => $php_version,
'themeName' => $theme->get( 'Name' ),
'themeAuthor' => $theme->get( 'Author' ),
'themeURI' => $theme->get( 'ThemeURI' ),
'fieldTypes' => $this->get_field_types(),
);
}
/**
* Get the field-types used.
*
* @access private
* @since 3.0.36
* @return array
*/
public function get_field_types() {
$types = array();
foreach ( Kirki::$fields as $field ) {
if ( isset( $field['type'] ) ) {
$types[] = $field['type'];
}
}
return $types;
}
/**
* Dismisses the notice.
*
* @access private
* @since 3.0.36
* @return void
*/
private function dismiss_notice() {
// Check if this is the request we want.
if ( isset( $_GET['_wpnonce'] ) && isset( $_GET['kirki-hide-notice'] ) ) {
if ( 'telemetry' === sanitize_text_field( wp_unslash( $_GET['kirki-hide-notice'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
// Check the wp-nonce.
if ( wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
// All good, we can save the option to dismiss this notice.
update_option( 'kirki_telemetry_no_consent', true );
}
}
}
}
/**
* Dismisses the notice.
*
* @access private
* @since 3.0.36
* @return void
*/
private function consent() {
// Check if this is the request we want.
if ( isset( $_GET['_wpnonce'] ) && isset( $_GET['kirki-consent-notice'] ) ) {
if ( 'telemetry' === sanitize_text_field( wp_unslash( $_GET['kirki-consent-notice'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
// Check the wp-nonce.
if ( wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
// All good, we can save the option to dismiss this notice.
update_option( 'kirki_telemetry_optin', true );
}
}
}
}
}

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/

View file

@ -1,36 +1,30 @@
@charset "UTF-8";
.tooltip-wrapper {
float: right;
position: relative;
}
.tooltip-wrapper .tooltip-trigger {
text-decoration: none;
cursor: help;
}
.tooltip-wrapper .tooltip-content {
position: absolute;
width: 200px;
height: auto;
top: -10px;
left: -225px;
background: #FFC107;
color: #000;
padding: 10px;
z-index: 99999;
border-radius: 3px;
line-height: 1.4em;
}
.tooltip-wrapper .tooltip-content a {
color: #000;
}
.tooltip-wrapper .tooltip-content:after {
content: "";
font-family: dashicons;
position: absolute;
right: -12px;
top: 11px;
color: #FFC107;
font-size: 20px;
}
position: relative; }
.tooltip-wrapper .tooltip-trigger {
text-decoration: none;
cursor: help; }
.tooltip-wrapper .tooltip-content {
position: absolute;
width: 200px;
height: auto;
top: -10px;
left: -225px;
background: #FFC107;
color: #000;
padding: 10px;
z-index: 99999;
border-radius: 3px;
line-height: 1.4em; }
.tooltip-wrapper .tooltip-content a {
color: #000; }
.tooltip-wrapper .tooltip-content:after {
content: "\f139";
font-family: dashicons;
position: absolute;
right: -12px;
top: 11px;
color: #FFC107;
font-size: 20px; }
/*# sourceMappingURL=tooltip.css.map */

View file

@ -5,8 +5,8 @@
* @see https://github.com/typekit/webfontloader
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.26
*/

View file

@ -1,483 +0,0 @@
<?php
/**
* Handles downloading a font from the google-fonts API locally.
* Solves privacy concerns with Google's CDN
* and their sometimes less-than-transparent policies.
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @license https://opensource.org/licenses/MIT
* @since 3.0.28
*/
// Do not allow directly accessing this file.
if ( ! defined( 'ABSPATH' ) ) {
exit( 'Direct script access denied.' );
}
/**
* The Kirki_Fonts object.
*
* @since 3.0.28
*/
final class Kirki_Fonts_Google_Local {
/**
* The name of the font-family
*
* @access private
* @since 3.0.28
* @var string
*/
private $family;
/**
* The system path where font-files are stored.
*
* @access private
* @since 3.0.28
* @var string
*/
private $folder_path;
/**
* The URL where files for this font can be found.
*
* @access private
* @since 3.0.28
* @var string
*/
private $folder_url;
/**
* The font-family array from the google-fonts API.
*
* @access private
* @since 3.0.28
* @var array
*/
private $font;
/**
* An array of instances for this object.
*
* @static
* @access private
* @since 3.0.28
* @var array
*/
private static $instances = array();
/**
* Create an instance of this object for a specific font-family.
*
* @static
* @access public
* @since 3.0.28
* @param string $family The font-family name.
* @return Kirki_Fonts_Google_Local
*/
public static function init( $family ) {
$key = sanitize_key( $family );
if ( ! isset( self::$instances[ $key ] ) ) {
self::$instances[ $key ] = new self( $family );
}
return self::$instances[ $key ];
}
/**
* Constructor.
*
* @access private
* @since 3.0.28
* @param string $family The font-family name.
*/
private function __construct( $family ) {
$this->family = $family;
$key = sanitize_key( $this->family );
$this->folder_path = $this->get_root_path() . "/$key";
$this->folder_url = $this->get_root_url() . "/$key";
$this->files = $this->get_font_family();
}
/**
* Gets the @font-face CSS.
*
* @access public
* @since 3.0.28
* @param array $variants The variants we want to get.
* @return string
*/
public function get_css( $variants = array() ) {
if ( ! $this->files ) {
return;
}
$key = md5( wp_json_encode( $this->files ) );
$cached = get_transient( $key );
if ( $cached ) {
return $cached;
}
$css = '';
// If $variants is empty then use all variants available.
if ( empty( $variants ) ) {
$variants = array_keys( $this->files );
}
// Download files.
$this->download_font_family( $variants );
// Create the @font-face CSS.
foreach ( $variants as $variant ) {
$css .= $this->get_variant_fontface_css( $variant );
}
set_transient( $key, $css, DAY_IN_SECONDS );
return $css;
}
/**
* Get the @font-face CSS for a specific variant.
*
* @access public
* @since 3.0.28
* @param string $variant The variant.
* @return string
*/
public function get_variant_fontface_css( $variant ) {
$font_face = "@font-face{font-family:'{$this->family}';";
// Get the font-style.
$font_style = ( false !== strpos( $variant, 'italic' ) ) ? 'italic' : 'normal';
$font_face .= "font-style:{$font_style};";
// Get the font-weight.
$font_weight = '400';
$font_weight = str_replace( 'italic', '', $variant );
$font_weight = ( ! $font_weight || 'regular' === $font_weight ) ? '400' : $font_weight;
$font_face .= "font-weight:{$font_weight};";
// Get the font-names.
$font_name_0 = $this->get_local_font_name( $variant, false );
$font_name_1 = $this->get_local_font_name( $variant, true );
$font_face .= "src:local('{$font_name_0}'),";
if ( $font_name_0 !== $font_name_1 ) {
$font_face .= "local('{$font_name_1}'),";
}
// Get the font-url.
$font_url = $this->get_variant_local_url( $variant );
$paths = $this->get_font_files_paths();
if ( ! file_exists( $paths[ $variant ] ) ) {
$font_url = $this->files[ $variant ];
}
// Get the font-format.
$font_format = ( strpos( $font_url, '.woff2' ) ) ? 'woff2' : 'truetype';
$font_format = ( strpos( $font_url, '.woff' ) && ! strpos( $font_url, '.woff2' ) ) ? 'woff' : $font_format;
$font_face .= "url({$font_url}) format('{$font_format}');}";
return $font_face;
}
/**
* Gets the local URL for a variant.
*
* @access public
* @since 3.0.28
* @param string $variant The variant.
* @return string The URL.
*/
public function get_variant_local_url( $variant ) {
$local_urls = $this->get_font_files_urls_local();
if ( empty( $local_urls ) ) {
return;
}
// Return the specific variant if we can find it.
if ( isset( $local_urls[ $variant ] ) ) {
return $local_urls[ $variant ];
}
// Return regular if the one we want could not be found.
if ( isset( $local_urls['regular'] ) ) {
return $local_urls['regular'];
}
// Return the first available if all else failed.
$vals = array_values( $local_urls );
return $vals[0];
}
/**
* Get the name of the font-family.
* This is used by @font-face in case the user already has the font downloaded locally.
*
* @access public
* @since 3.0.28
* @param string $variant The variant.
* @param bool $compact Whether we want the compact formatting or not.
* @return string
*/
public function get_local_font_name( $variant, $compact = false ) {
$variant_names = array(
'100' => 'Thin',
'100i' => 'Thin Italic',
'100italic' => 'Thin Italic',
'200' => 'Extra-Light',
'200i' => 'Extra-Light Italic',
'200italic' => 'Extra-Light Italic',
'300' => 'Light',
'300i' => 'Light Italic',
'300italic' => 'Light Italic',
'400' => 'Regular',
'regular' => 'Regular',
'400i' => 'Regular Italic',
'italic' => 'Italic',
'400italic' => 'Regular Italic',
'500' => 'Medium',
'500i' => 'Medium Italic',
'500italic' => 'Medium Italic',
'600' => 'Semi-Bold',
'600i' => 'Semi-Bold Italic',
'600italic' => 'Semi-Bold Italic',
'700' => 'Bold',
'700i' => 'Bold Italic',
'700italic' => 'Bold Italic',
'800' => 'Extra-Bold',
'800i' => 'Extra-Bold Italic',
'800italic' => 'Extra-Bold Italic',
'900' => 'Black',
'900i' => 'Black Italic',
'900italic' => 'Black Italic',
);
$variant = (string) $variant;
if ( $compact ) {
if ( isset( $variant_names[ $variant ] ) ) {
return str_replace( array( ' ', '-' ), '', $this->family ) . '-' . str_replace( array( ' ', '-' ), '', $variant_names[ $variant ] );
}
return str_replace( array( ' ', '-' ), '', $this->family );
}
if ( isset( $variant_names[ $variant ] ) ) {
return $this->family . ' ' . $variant_names[ $variant ];
}
return $this->family;
}
/**
* Get an array of font-files.
* Only contains the filenames.
*
* @access public
* @since 3.0.28
* @return array
*/
public function get_font_files() {
$files = array();
foreach ( $this->files as $key => $url ) {
$files[ $key ] = $this->get_filename_from_url( $url );
}
return $files;
}
/**
* Get an array of local file URLs.
*
* @access public
* @since 3.0.28
* @return array
*/
public function get_font_files_urls_local() {
$urls = array();
$files = $this->get_font_files();
foreach ( $files as $key => $file ) {
$urls[ $key ] = $this->folder_url . '/' . $file;
}
return $urls;
}
/**
* Get an array of local file paths.
*
* @access public
* @since 3.0.28
* @return array
*/
public function get_font_files_paths() {
$paths = array();
$files = $this->get_font_files();
foreach ( $files as $key => $file ) {
$paths[ $key ] = $this->folder_path . '/' . $file;
}
return $paths;
}
/**
* Downloads a font-file and saves it locally.
*
* @access private
* @since 3.0.28
* @param string $url The URL of the file we want to get.
* @return bool
*/
private function download_font_file( $url ) {
$contents = $this->get_remote_url_contents( $url );
$path = $this->folder_path . '/' . $this->get_filename_from_url( $url );
// If the folder doesn't exist, create it.
if ( ! file_exists( $this->folder_path ) ) {
wp_mkdir_p( $this->folder_path );
}
// If the file exists no reason to do anything.
if ( file_exists( $path ) ) {
return true;
}
// Write file.
return Kirki_Helper::init_filesystem()->put_contents( $path, $contents, FS_CHMOD_FILE );
}
/**
* Get a font-family from the array of google-fonts.
*
* @access public
* @since 3.0.28
* @return array
*/
public function get_font_family() {
// Get the fonts array.
$fonts = $this->get_fonts();
if ( isset( $fonts[ $this->family ] ) ) {
return $fonts[ $this->family ];
}
return array();
}
/**
* Gets the filename by breaking-down the URL parts.
*
* @access private
* @since 3.0.28
* @param string $url The URL.
* @return string The filename.
*/
private function get_filename_from_url( $url ) {
$url_parts = explode( '/', $url );
$parts_count = count( $url_parts );
if ( 1 < $parts_count ) {
return $url_parts[ count( $url_parts ) - 1 ];
}
return $url;
}
/**
* Get the font defined in the google-fonts API.
*
* @access private
* @since 3.0.28
* @return array
*/
private function get_fonts() {
ob_start();
include wp_normalize_path( dirname( __FILE__ ) . '/webfont-files.json' );
$json = ob_get_clean();
return json_decode( $json, true );
}
/**
* Gets the root fonts folder path.
* Other paths are built based on this.
*
* @since 1.5
* @access public
* @return string
*/
public function get_root_path() {
// Get the upload directory for this site.
$upload_dir = wp_upload_dir();
$path = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/webfonts';
// If the folder doesn't exist, create it.
if ( ! file_exists( $path ) ) {
wp_mkdir_p( $path );
}
// Return the path.
return apply_filters( 'kirki_googlefonts_root_path', $path );
}
/**
* Gets the root folder url.
* Other urls are built based on this.
*
* @since 1.5
* @access public
* @return string
*/
public function get_root_url() {
// Get the upload directory for this site.
$upload_dir = wp_upload_dir();
// The URL.
$url = trailingslashit( $upload_dir['baseurl'] );
// Take care of domain mapping.
// When using domain mapping we have to make sure that the URL to the file
// does not include the original domain but instead the mapped domain.
if ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ) {
if ( function_exists( 'domain_mapping_siteurl' ) && function_exists( 'get_original_url' ) ) {
$mapped_domain = domain_mapping_siteurl( false );
$original_domain = get_original_url( 'siteurl' );
$url = str_replace( $original_domain, $mapped_domain, $url );
}
}
$url = str_replace( array( 'https://', 'http://' ), '//', $url );
return apply_filters( 'kirki_googlefonts_root_url', untrailingslashit( esc_url_raw( $url ) ) . '/webfonts' );
}
/**
* Download font-family files.
*
* @access public
* @since 3.0.28
* @param array $variants An array of variants to download. Leave empty to download all.
* @return void
*/
public function download_font_family( $variants = array() ) {
if ( empty( $variants ) ) {
$variants = array_keys( $this->files );
}
foreach ( $this->files as $variant => $file ) {
if ( in_array( $variant, $variants ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
$this->download_font_file( $file );
}
}
}
/**
* Gets the remote URL contents.
*
* @access private
* @since 3.0.28
* @param string $url The URL we want to get.
* @return string The contents of the remote URL.
*/
public function get_remote_url_contents( $url ) {
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) ) {
return array();
}
$html = wp_remote_retrieve_body( $response );
if ( is_wp_error( $html ) ) {
return;
}
return $html;
}
}

View file

@ -5,8 +5,8 @@
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 1.0
*/
@ -110,7 +110,6 @@ final class Kirki_Fonts_Google {
* @param array $args The field arguments.
*/
public function generate_google_font( $args ) {
global $wp_customize;
// Process typography fields.
if ( isset( $args['type'] ) && 'kirki-typography' === $args['type'] ) {
@ -118,12 +117,8 @@ final class Kirki_Fonts_Google {
// Get the value.
$value = Kirki_Values::get_sanitized_field_value( $args );
if ( isset( $value['downloadFont'] ) && $value['downloadFont'] ) {
$this->hosted_fonts[] = $value['font-family'];
}
// If we don't have a font-family then we can skip this.
if ( ! $wp_customize && ( ! isset( $value['font-family'] ) || in_array( $value['font-family'], $this->hosted_fonts, true ) ) ) {
if ( ! isset( $value['font-family'] ) || in_array( $value['font-family'], $this->hosted_fonts, true ) ) {
return;
}
@ -234,7 +229,7 @@ final class Kirki_Fonts_Google {
* @return void
*/
public function get_googlefonts_json() {
include wp_normalize_path( dirname( __FILE__ ) . '/webfonts.json' );
include wp_normalize_path( dirname( __FILE__ ) . '/webfonts.json' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
wp_die();
}
@ -248,15 +243,4 @@ final class Kirki_Fonts_Google {
echo wp_json_encode( Kirki_Fonts::get_standard_fonts() );
wp_die();
}
/**
* Gets $this->hosted_fonts.
*
* @access public
* @since 3.0.32
* @return array
*/
public function get_hosted_fonts() {
return $this->hosted_fonts;
}
}

View file

@ -0,0 +1,164 @@
<?php
/**
* Helper methods for fonts.
*
* @package Kirki
* @category Core
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.36
*/
// Do not allow directly accessing this file.
if ( ! defined( 'ABSPATH' ) ) {
exit( 'Direct script access denied.' );
}
/**
* The Kirki_Fonts object.
*
* @since 3.0.28
*/
final class Kirki_Fonts_Helper {
/**
* Gets the remote URL contents.
*
* @static
* @access public
* @since 3.0.36
* @param string $url The URL we want to get.
* @param array $args An array of arguments for the wp_remote_retrieve_body() function.
* @return string The contents of the remote URL.
*/
public static function get_remote_url_contents( $url, $args = array() ) {
$response = wp_remote_get( $url, $args );
if ( is_wp_error( $response ) ) {
return array();
}
$html = wp_remote_retrieve_body( $response );
if ( is_wp_error( $html ) ) {
return;
}
return $html;
}
/**
* Gets the root fonts folder path.
* Other paths are built based on this.
*
* @static
* @since 3.0.36
* @access public
* @return string
*/
public static function get_root_path() {
// Get the upload directory for this site.
$upload_dir = wp_upload_dir();
$path = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/webfonts';
// If the folder doesn't exist, create it.
if ( ! file_exists( $path ) ) {
wp_mkdir_p( $path );
}
// Return the path.
return apply_filters( 'kirki_googlefonts_root_path', $path );
}
/**
* Gets the filename by breaking-down the URL parts.
*
* @static
* @access private
* @since 3.0.28
* @param string $url The URL.
* @return string The filename.
*/
private static function get_filename_from_url( $url ) {
$url_parts = explode( '/', $url );
$parts_count = count( $url_parts );
if ( 1 < $parts_count ) {
return $url_parts[ count( $url_parts ) - 1 ];
}
return $url;
}
/**
* Downloads a font-file and saves it locally.
*
* @access public
* @since 3.0.28
* @param string $url The URL of the file we want to get.
* @return bool
*/
public static function download_font_file( $url ) {
// Gives us access to the download_url() and wp_handle_sideload() functions.
require_once ABSPATH . 'wp-admin/includes/file.php';
$timeout_seconds = 5;
// Download file to temp dir.
$temp_file = download_url( $url, $timeout_seconds );
if ( is_wp_error( $temp_file ) ) {
return false;
}
// Array based on $_FILE as seen in PHP file uploads.
$file = array(
'name' => basename( $url ),
'type' => 'font/woff',
'tmp_name' => $temp_file,
'error' => 0,
'size' => filesize( $temp_file ),
);
$overrides = array(
'test_form' => false,
'test_size' => true,
);
// Move the temporary file into the uploads directory.
$results = wp_handle_sideload( $file, $overrides );
if ( empty( $results['error'] ) ) {
return $results['url'];
}
return false;
}
/**
* Gets the root folder url.
* Other urls are built based on this.
*
* @static
* @since 3.0.36
* @access public
* @return string
*/
public static function get_root_url() {
// Get the upload directory for this site.
$upload_dir = wp_upload_dir();
// The URL.
$url = trailingslashit( $upload_dir['baseurl'] );
// Take care of domain mapping.
// When using domain mapping we have to make sure that the URL to the file
// does not include the original domain but instead the mapped domain.
if ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ) {
if ( function_exists( 'domain_mapping_siteurl' ) && function_exists( 'get_original_url' ) ) {
$mapped_domain = domain_mapping_siteurl( false );
$original_domain = get_original_url( 'siteurl' );
$url = str_replace( $original_domain, $mapped_domain, $url );
}
}
$url = str_replace( array( 'https://', 'http://' ), '//', $url );
return apply_filters( 'kirki_googlefonts_root_url', untrailingslashit( esc_url_raw( $url ) ) . '/webfonts' );
}
}

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 1.0
*/
@ -134,7 +134,7 @@ final class Kirki_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' );
include wp_normalize_path( dirname( __FILE__ ) . '/webfonts.json' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
$fonts_json = ob_get_clean();
$fonts = json_decode( $fonts_json, true );

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0
*/

View file

@ -0,0 +1,236 @@
<?php
/**
* Adds the Webfont Loader to load fonts asyncronously.
*
* @package Kirki
* @category Core
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @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";
$transient_id = 'kirki_gfonts_' . md5( $url );
$contents = get_site_transient( $transient_id );
/**
* 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
$contents = false;
}
if ( ! $contents ) {
// Get the contents of the remote URL.
$contents = Kirki_Fonts_Helper::get_remote_url_contents(
$url,
array(
'headers' => array(
/**
* Set user-agent to firefox so that we get woff files.
* If we want woff2, use this instead: 'Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0'
*/
'user-agent' => 'Mozilla/5.0 (X11; Linux i686; rv:21.0) Gecko/20100101 Firefox/21.0',
),
)
);
/**
* Allow filtering the font-display property.
*/
$font_display = apply_filters( 'kirki_googlefonts_font_display', 'swap' );
if ( $contents ) {
// Add font-display:swap to improve rendering speed.
$contents = str_replace( '@font-face {', '@font-face{', $contents );
$contents = str_replace( '@font-face{', '@font-face{font-display:' . $font_display . ';', $contents );
// Remove blank lines and extra spaces.
$contents = str_replace(
array( ': ', '; ', '; ', ' ' ),
array( ':', ';', ';', ' ' ),
preg_replace( "/\r|\n/", '', $contents )
);
// Use local fonts.
if ( apply_filters( 'kirki_use_local_fonts', true ) ) {
$contents = $this->use_local_files( $contents );
}
// Set the transient for a week.
set_site_transient( $transient_id, $contents, WEEK_IN_SECONDS );
}
}
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
}
}
}
/**
* Downloads font-files locally and uses the local files instead of the ones from Google's servers.
* This addresses any and all GDPR concerns, as well as firewalls that exist in some parts of the world.
*
* @access private
* @since 3.0.36
* @param string $css The CSS with original URLs.
* @return string The CSS with local URLs.
*/
private function use_local_files( $css ) {
preg_match( '/https\:.*?\.woff/', $css, $matches );
foreach ( $matches as $match ) {
if ( 0 === strpos( $match, 'https://fonts.gstatic.com' ) ) {
$new_url = Kirki_Fonts_Helper::download_font_file( $match );
if ( $new_url ) {
$css = str_replace( $match, $new_url, $css );
}
}
}
return $css;
}
}

View file

@ -1,105 +0,0 @@
<?php
/**
* Handles adding to the footer the @font-face CSS for locally-hosted google-fonts.
* Solves privacy concerns with Google's CDN and their sometimes less-than-transparent policies.
*
* @package Kirki
* @category Core
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @license https://opensource.org/licenses/MIT
* @since 3.0.28
*/
/**
* Manages the way Google Fonts are enqueued.
*/
final class Kirki_Modules_Webfonts_Local {
/**
* The config ID.
*
* @access protected
* @since 3.0.28
* @var string
*/
protected $config_id;
/**
* The Kirki_Modules_Webfonts object.
*
* @access protected
* @since 3.0.28
* @var object
*/
protected $webfonts;
/**
* The Kirki_Fonts_Google object.
*
* @access protected
* @since 3.0.28
* @var object
*/
protected $googlefonts;
/**
* Fonts to load.
*
* @access protected
* @since 3.0.28
* @var array
*/
protected $fonts_to_load = array();
/**
* Constructor.
*
* @access public
* @since 3..28
* @param object $webfonts The Kirki_Modules_Webfonts object.
* @param object $googlefonts The Kirki_Fonts_Google object.
*/
public function __construct( $webfonts, $googlefonts ) {
$this->webfonts = $webfonts;
$this->googlefonts = $googlefonts;
add_action( 'wp_footer', array( $this, 'add_styles' ) );
add_action( 'admin_footer', array( $this, 'add_styles' ) );
}
/**
* Webfont Loader for Google Fonts.
*
* @access public
* @since 3.0.28
*/
public function add_styles() {
// Go through our fields and populate $this->fonts.
$this->webfonts->loop_fields( $this->config_id );
$this->googlefonts->process_fonts();
$hosted_fonts = $this->googlefonts->get_hosted_fonts();
// Early exit if we don't need to add any fonts.
if ( empty( $hosted_fonts ) ) {
return;
}
// Make sure we only do this once per font-family.
$hosted_fonts = array_unique( $hosted_fonts );
// Start CSS.
$css = '';
foreach ( $hosted_fonts as $family ) {
// Add the @font-face CSS for this font-family.
$css .= Kirki_Fonts_Google_Local::init( $family )->get_css();
}
// If we've got CSS, add to the footer.
if ( $css ) {
echo '<style id="kirki-local-webfonts-' . esc_attr( sanitize_key( $this->config_id ) ) . '">' . $css . '</style>'; // WPCS: XSS ok.
}
}
}

View file

@ -4,8 +4,8 @@
*
* @package Kirki
* @category Modules
* @author Aristeides Stathopoulos
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
* @author Ari Stathopoulos (@aristath)
* @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
* @license https://opensource.org/licenses/MIT
* @since 3.0.0
*/
@ -47,9 +47,9 @@ class Kirki_Modules_Webfonts {
*/
protected function __construct() {
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts.php' );
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts-google.php' );
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts-google-local.php' );
include_once wp_normalize_path( dirname( __FILE__ ) . '/class-kirki-fonts-helper.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude
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' ) );
@ -90,11 +90,11 @@ class Kirki_Modules_Webfonts {
*/
protected function init() {
foreach ( array_keys( Kirki::$config ) as $config_id ) {
$method = $this->get_method( $config_id );
$classname = 'Kirki_Modules_Webfonts_' . ucfirst( $method );
new $classname( $config_id, $this, $this->fonts_google );
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 );
}
new Kirki_Modules_Webfonts_Local( $this, $this->fonts_google );
}
/**
@ -102,27 +102,11 @@ class Kirki_Modules_Webfonts {
*
* @access public
* @since 3.0.0
* @deprecated in 3.0.36.
* @return string
*/
public function get_method() {
// Figure out which method to use.
$method = apply_filters( 'kirki_googlefonts_load_method', 'async' );
// Fallback to 'async' if value is invalid.
if ( 'async' !== $method && 'embed' !== $method && 'link' !== $method ) {
$method = 'async';
}
$classname = 'Kirki_Modules_Webfonts_' . ucfirst( $method );
if ( ! class_exists( $classname ) ) {
$method = 'async';
}
// Force using the JS method while in the customizer.
// This will help us work-out the live-previews for typography fields.
// If we're not in the customizer use the defined method.
return ( is_customize_preview() ) ? 'async' : $method;
return ( is_customize_preview() ) ? 'async' : 'embed';
}
/**

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