* Created on: 29/08/2018 * * @package Neve\Views\Inline */ namespace Neve\Views\Inline; use Neve\Views\Base_View; use Neve\Views\Inline\Base_Inline as Base_Inline; /** * Class Style_Manager * * @package Neve\Views\Inline */ abstract class Base_Style_Manager extends Base_View { /** * Theme mod key for generated style version. * * @var string */ protected $style_version_theme_mod_key = 'neve_generated_style_version'; /** * Style which the inline style will be hooked to. * * @var string */ protected $style_hook_handle = ''; /** * Will the style be enqueued in admin? * * @var bool */ protected $admin = false; /** * Inline style handlers * * @var array */ protected $style_classes = array(); /** * Generated style file name. * * @var string */ protected $css_file_name = ''; /** * The enqueued style handle. * * @var string */ protected $style_handle = ''; /** * Generated inline style path. * * @var string */ private $style_path = ''; /** * Generated inline style url. * * @var string */ private $style_url = ''; /** * Mobile style -> global. * * @var string */ private $style = ''; /** * Tablet style -> min-width: 769px. * * Reference #{$tablet} in scss. * * @var string */ private $tablet_style = ''; /** * Desktop style -> min-width 960px. * * Reference #{$laptop} in scss. * * @var string */ private $desktop_style = ''; /** * Style_Manager constructor. */ public function __construct() { $wp_upload_dir = wp_upload_dir( null, false ); $this->style_path = $wp_upload_dir['basedir'] . '/neve-theme/'; $this->style_url = $wp_upload_dir['baseurl'] . '/neve-theme/'; if ( is_ssl() && ! strpos( $this->style_url, 'https://' ) ) { $this->style_url = str_replace( 'http://', 'https://', $this->style_url ); } } /** * Function that is run after instantiation. * * @return void */ public function init() { if ( empty( $this->style_classes ) ) { return; } if ( $this->admin === true ) { add_action( 'enqueue_block_editor_assets', array( $this, 'maybe_enqueue' ), 100 ); } else { add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue' ), 100 ); } add_action( 'customize_save_after', array( $this, 'wipe_customizer_css_file' ), 0 ); add_action( 'after_switch_theme', array( $this, 'wipe_customizer_css_file' ), 0 ); if ( ! is_customize_preview() ) { add_action( 'shutdown', array( $this, 'generate_customizer_css_file' ), PHP_INT_MAX ); } } /** * Maybe enqueue the generated style if it exists. */ public function maybe_enqueue() { $this->run_inline_styles(); $this->wrap_styles(); if ( $this->should_add_style() ) { wp_enqueue_style( $this->style_handle, $this->style_url . $this->css_file_name, array( $this->style_hook_handle ), $this->get_style_version() ); return; } wp_add_inline_style( $this->style_hook_handle, $this->get_style() ); } /** * Check if file should be enqueued or inline style added. * * @return bool */ private function should_add_style() { // If debug mode bail. if ( NEVE_DEBUG === true ) { return false; } $path = $this->style_path . $this->css_file_name; // If file doesn't exist bail. if ( ! file_exists( $path ) ) { return false; } // If file is not readable bail. if ( ! is_readable( $path ) ) { return false; } // If is customizer bail. if ( is_customize_preview() ) { return false; } // If the file content is different from the generated style bail. if ( $this->is_css_inline_diff() ) { return false; } return true; } /** * Check if there's a difference between the inline and generated style. * * @return bool */ private function is_css_inline_diff() { require_once ABSPATH . '/wp-admin/includes/file.php'; global $wp_filesystem; WP_Filesystem(); $inline_style = $this->get_style(); $css_contents = $wp_filesystem->get_contents( $this->style_path . $this->css_file_name ); if ( $css_contents !== $inline_style ) { $this->wipe_customizer_css_file(); return true; } return false; } /** * Generate the customizer file. */ public function generate_customizer_css_file() { $style = $this->get_style(); if ( empty( $style ) ) { return; } if ( file_exists( $this->style_path . $this->css_file_name ) && is_readable( $this->style_path . $this->css_file_name ) ) { return; } if ( ! is_dir( $this->style_path ) ) { wp_mkdir_p( $this->style_path ); } require_once ABSPATH . '/wp-admin/includes/file.php'; global $wp_filesystem; WP_Filesystem(); $wp_filesystem->put_contents( $this->style_path . $this->css_file_name, $style, 0644 ); } /** * Delete customizer generated CSS. * * Remove css and delete version key. */ public function wipe_customizer_css_file() { if ( ! file_exists( $this->style_path . $this->css_file_name ) || ! is_readable( $this->style_path . $this->css_file_name ) ) { return; } remove_theme_mod( $this->style_version_theme_mod_key ); if ( is_writable( $this->style_path . $this->css_file_name ) ) { unlink( $this->style_path . $this->css_file_name ); } } /** * Instantiate classes and get the style. */ private function run_inline_styles() { $this->style_classes = apply_filters( 'neve_filter_inline_style_classes', $this->style_classes, $this->style_handle ); foreach ( $this->style_classes as $style_class ) { if ( ! class_exists( $style_class ) ) { continue; } $class = new $style_class(); $this->add_style( $class ); } } /** * Add the styles from the inline style object. * * @param \Neve\Views\Inline\Base_Inline $style_class the class that handles the style output. */ private function add_style( Base_Inline $style_class ) { $this->style .= $style_class->get_style( 'mobile' ); $this->tablet_style .= $style_class->get_style( 'tablet' ); $this->desktop_style .= $style_class->get_style( 'desktop' ); } /** * Wrap the responsive styles in media queries. */ private function wrap_styles() { if ( ! empty( $this->tablet_style ) ) { $this->tablet_style = '@media(min-width: 576px){' . $this->tablet_style . '}'; } if ( ! empty( $this->desktop_style ) ) { $this->desktop_style = '@media(min-width: 960px){' . $this->desktop_style . '}'; } } /** * Get the whole style from component. * * @return string */ public function get_style() { $style = $this->style . $this->tablet_style . $this->desktop_style; $style = apply_filters( 'neve_style_output_' . $this->style_handle, $style ); return preg_replace( '!\s+!', ' ', $style ); } /** * Get the style version if it exists, else create one. * * @return string */ private function get_style_version() { $version = get_theme_mod( $this->style_version_theme_mod_key, false ); if ( empty( $version ) ) { set_theme_mod( $this->style_version_theme_mod_key, time() ); } return get_theme_mod( $this->style_version_theme_mod_key ); } /** * Get style from certain media query. * * @param string $query media query. * * @return string */ public function get_single_style( $query = '' ) { if ( empty( $query ) ) { return $this->style; } $accepted = array( 'tablet', 'desktop' ); if ( ! in_array( $query, $accepted ) ) { return ''; } if ( $query === 'tablet' ) { return $this->tablet_style; } if ( $query === 'desktop' ) { return $this->desktop_style; } } }