aristath/kirki

View on GitHub
packages/kirki-framework/module-webfonts/src/Webfonts/Google.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/**
 * Processes typography-related fields
 * and generates the google-font link.
 *
 * @package kirki-framework/module-webfonts
 * @author Ari Stathopoulos (@aristath)
 * @copyright Copyright (c) 2019, Ari Stathopoulos (@aristath)
 * @license https://opensource.org/licenses/MIT
 * @since 1.0.0
 */

namespace Kirki\Module\Webfonts;

use Kirki\Module\Webfonts\Fonts;
use Kirki\GoogleFonts;

/**
 * Manages the way Google Fonts are enqueued.
 */
final class Google {

    /**
     * The object instance.
     * We use the singleton pattern here to avoid loading the google-font array multiple times.
     * This is mostly a performance tweak.
     *
     * @access private
     * @var null|object
     */
    private static $instance = null;

    /**
     * DUMMY. DOESN'T DO ANYTHING, SIMPLY BACKWARDS-COMPATIBILITY.
     *
     * @static
     * @access public
     * @var bool
     */
    public static $force_load_all_subsets = false;

    /**
     * If set to true, forces loading ALL variants.
     *
     * @static
     * @access public
     * @var bool
     */
    public static $force_load_all_variants = false;

    /**
     * The array of fonts
     *
     * @access public
     * @var array
     */
    public $fonts = [];

    /**
     * An array of all google fonts.
     *
     * @access private
     * @var array
     */
    private $google_fonts = [];

    /**
     * An array of fonts that should be hosted locally instead of served via the google-CDN.
     *
     * @access protected
     * @since 1.0.0
     * @var array
     */
    protected $hosted_fonts = [];

    /**
     * The class constructor.
     */
    private function __construct() {
        $config = apply_filters( 'kirki_config', [] );

        // If we have set $config['disable_google_fonts'] to true then do not proceed any further.
        if ( isset( $config['disable_google_fonts'] ) && true === $config['disable_google_fonts'] ) {
            return;
        }

        new GoogleFonts();
        add_action( 'wp_ajax_kirki_fonts_standard_all_get', [ $this, 'get_standardfonts_json' ] );
        add_action( 'wp_ajax_nopriv_kirki_fonts_standard_all_get', [ $this, 'get_standardfonts_json' ] );

        // Populate the array of google fonts.
        $this->google_fonts = Fonts::get_google_fonts();
    }

    /**
     * Get the one, true instance of this class.
     * Prevents performance issues since this is only loaded once.
     *
     * @return object Google
     */
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Processes the arguments of a field
     * determines if it's a typography field
     * and if it is, then takes appropriate actions.
     *
     * @param array $args The field arguments.
     */
    public function generate_google_font( $args ) {

        // Process typography fields.
        $process = ( ( isset( $args['type'] ) && 'kirki-typography' === $args['type'] ) || ( isset( $args['choices'] ) && isset( $args['choices']['parent_type'] ) && 'kirki-typography' === $args['choices']['parent_type'] ) );
        if ( apply_filters( 'kirki_generate_google_font', $process, $args ) ) {

            // Get the value.
            $option_type = ( isset( $args['option_type'] ) ) ? $args['option_type'] : 'theme_mod';
            $default     = ( isset( $args['default'] ) ) ? $args['default'] : '';
            $value       = apply_filters( 'kirki_get_value', get_theme_mod( $args['settings'], $default ), $args['settings'], $default, $option_type );

            // If we don't have a font-family then we can skip this.
            if ( ! isset( $value['font-family'] ) || in_array( $value['font-family'], $this->hosted_fonts, true ) ) {
                return;
            }

            // If not a google-font, then we can skip this.
            if ( ! isset( $value['font-family'] ) || ! Fonts::is_google_font( $value['font-family'] ) ) {
                return;
            }

            // Set a default value for variants.
            if ( ! isset( $value['variant'] ) ) {
                $value['variant'] = 'regular';
            }

            // Add the requested google-font.
            if ( ! is_array( $value ) || ! isset( $value['font-family'] ) || ! isset( $this->fonts[ $value['font-family'] ] ) ) {
                $this->fonts[ $value['font-family'] ] = [];
            }
            if ( ! in_array( $value['variant'], $this->fonts[ $value['font-family'] ], true ) ) {
                $this->fonts[ $value['font-family'] ][] = $value['variant'];
            }

            // Are we force-loading all variants?
            if ( true === self::$force_load_all_variants ) {
                $all_variants               = Fonts::get_all_variants();
                $args['choices']['variant'] = array_keys( $all_variants );
            }

            if ( ! empty( $args['choices']['variant'] ) && is_array( $args['choices']['variant'] ) ) {
                foreach ( $args['choices']['variant'] as $extra_variant ) {
                    $this->fonts[ $value['font-family'] ][] = $extra_variant;
                }
            }
            return;
        }

        // Process non-typography fields.
        if ( isset( $args['output'] ) && is_array( $args['output'] ) ) {
            foreach ( $args['output'] as $output ) {

                // If we don't have a typography-related output argument we can skip this.
                if ( ! isset( $output['property'] ) || ! in_array( $output['property'], [ 'font-family', 'font-weight' ], true ) ) {
                    continue;
                }

                // Get the value.
                $option_type = ( isset( $args['option_type'] ) ) ? $args['option_type'] : 'theme_mod';
                $default     = ( isset( $args['default'] ) ) ? $args['default'] : '';
                $value       = apply_filters( 'kirki_get_value', get_theme_mod( $args['settings'], $default ), $args['settings'], $default, $option_type );

                if ( is_string( $value ) ) {
                    if ( 'font-family' === $output['property'] ) {
                        if ( ! array_key_exists( $value, $this->fonts ) ) {
                            $this->fonts[ $value ] = [];
                        }
                    } elseif ( 'font-weight' === $output['property'] ) {
                        foreach ( $this->fonts as $font => $variants ) {
                            if ( ! in_array( $value, $variants, true ) ) {
                                $this->fonts[ $font ][] = $value;
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Determines the vbalidity of the selected font as well as its properties.
     * This is vital to make sure that the google-font script that we'll generate later
     * does not contain any invalid options.
     */
    public function process_fonts() {

        // Early exit if font-family is empty.
        if ( empty( $this->fonts ) ) {
            return;
        }

        foreach ( $this->fonts as $font => $variants ) {

            // Determine if this is indeed a google font or not.
            // If it's not, then just remove it from the array.
            if ( ! array_key_exists( $font, $this->google_fonts ) ) {
                unset( $this->fonts[ $font ] );
                continue;
            }

            // Get all valid font variants for this font.
            $font_variants = [];
            if ( isset( $this->google_fonts[ $font ]['variants'] ) ) {
                $font_variants = $this->google_fonts[ $font ]['variants'];
            }
            foreach ( $variants as $variant ) {

                // If this is not a valid variant for this font-family
                // then unset it and move on to the next one.
                if ( ! in_array( strval( $variant ), $font_variants, true ) ) {
                    $variant_key = array_search( $variant, $this->fonts[ $font ], true );
                    unset( $this->fonts[ $font ][ $variant_key ] );
                    continue;
                }
            }
        }
    }

    /**
     * Get the standard fonts JSON.
     *
     * @since 1.0.0
     * @return void
     */
    public function get_standardfonts_json() {
        echo wp_json_encode( Fonts::get_standard_fonts() );
        wp_die();
    }
}