Skip to content

Instantly share code, notes, and snippets.

@perusoa
Forked from Robbertdk/kirki-sass-compiler.php
Created September 6, 2017 20:03
Show Gist options
  • Save perusoa/bd5d8a8f51551394d0df15e8e190f504 to your computer and use it in GitHub Desktop.
Save perusoa/bd5d8a8f51551394d0df15e8e190f504 to your computer and use it in GitHub Desktop.
<?php
/**
* Kirki Sass Compiler
*
* Create a CSS file based on a SCSS-file and Kirki variables
* File gets saved in the public folder with a cache buster.
*/
namespace App\Kirki;
use Leafo\ScssPhp\Compiler;
class DynamicCSS {
private $css_dir;
private $css_file_name;
private $css_file_url;
public function __construct($settings) {
$this->css_dir = $this->get_file_dir($settings['foldername']);
$this->css_file_name = $this->get_file_name($settings['filename']);
$this->css_file_url = $this->get_cached_file_url($settings['foldername']);
add_action( 'customize_save_after', array( $this, 'refresh_css' ) );
add_action( 'wp_enqueue_scripts', array($this, 'enqueue_dynamic_css'), 999);
}
/**
* Returns the path to the css file directory.
*
* @return string
*/
private function get_file_dir($folder = 'dynamic-css') {
$upload_dir = wp_upload_dir();
return $upload_dir['basedir'] . DIRECTORY_SEPARATOR . $folder;
}
/**
* Returns the file name adjusted for multisite.
*
* @return string
*/
private function get_file_name($basename = 'styles') {
// Add blog ID if on multisite
global $blog_id;
$blog_id = ( is_multisite() && $blog_id > 1 ) ? '_blog-' . $blog_id : null;
return $basename . $blog_id . '.css';
}
/**
* Returns the path to the css file with the cache buster in the filename.
*
* @param string cachebuster
* @return string
*/
private function get_cached_file_path($buster = false) {
// Get cache buster
if (!$buster) {
$buster = $this->get_cache_buster();
}
$file_name = str_replace('.css', '-' .$buster . '.css', $this->css_file_name);
return $this->css_dir . DIRECTORY_SEPARATOR . $file_name;
}
/**
* Returns the url to the css file name, adjusted for multisite.
* @param string foldername
* @return string
*/
private function get_cached_file_url($foldername = 'dynamic-styles'){
$upload_dir = wp_upload_dir();
$cache_buster = $this->get_cache_buster();
$file_name = str_replace('.css', '-' . $cache_buster . '.css', $this->css_file_name);
$css_url = trailingslashit( $upload_dir['baseurl'] ) . $foldername . '/' . $file_name;
// Take care of domain mapping
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' );
$css_url = str_replace( $original_domain, $mapped_domain, $css_url );
}
}
// Strip protocols
$css_url = str_replace( 'https://', '//', $css_url );
$css_url = str_replace( 'http://', '//', $css_url );
return $css_url;
}
/**
* Returns the cache buster id
* @return String
*/
private function get_cache_buster() {
$filename = $this->css_dir . DIRECTORY_SEPARATOR . 'assets.json';
$buster = file_exists($filename) ? json_decode(file_get_contents($filename), true) : false;
return $buster ? $buster['assets'] : Null;
}
/**
* Creates a json file with the cache buster
*
* @param string Cache buster id
* @return String
*/
private function set_cache_buster($id) {
global $wp_filesystem;
// Initialize the Wordpress filesystem.
if ( empty( $wp_filesystem ) ) {
require_once( ABSPATH . '/wp-admin/includes/file.php' );
WP_Filesystem();
}
$buster = ['assets' => $id];
$buster = json_encode($buster);
if ( ! $wp_filesystem->put_contents( $this->css_dir . DIRECTORY_SEPARATOR . 'assets.json', $buster, FS_CHMOD_FILE ) ) {
error_log('Can\'t create Cache buster. Something went wrong');
return false;
}
}
/**
* Delete all css-files, except the one with the new cache buster
* @return String
*/
private function delete_old_styles($new_file_buster) {
$files = glob( $this->css_dir . DIRECTORY_SEPARATOR . '*.css' );
error_log(json_encode($new_file_buster));
foreach ( $files as $file ) {
// If the file has the new buster, don't delete it (caus its new)!
if (is_file( $file ) && strpos(basename($file), $new_file_buster) === false) {
unlink( $file );
}
}
}
/**
* Enqueue the dynamic CSS.
*/
public function enqueue_dynamic_css() {
wp_enqueue_style( 'dynamic-css', $this->css_file_url );
}
public function refresh_css() {
global $wp_filesystem;
// Initialize the Wordpress filesystem.
if ( empty( $wp_filesystem ) ) {
require_once( ABSPATH . '/wp-admin/includes/file.php' );
WP_Filesystem();
}
$content = "/********* Compiled - Do not edit *********/\n" . $this->compile_scss();
// Take care of domain mapping
if ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ) {
if ( function_exists( 'domain_mapping_siteurl' ) && function_exists( 'get_original_url' ) ) {
$mapped_domain = domain_mapping_siteurl( false );
$mapped_domain = str_replace( 'https://', '//', $domain_mapping );
$mapped_domain = str_replace( 'http://', '//', $mapped_domain );
$original_domain = get_original_url( 'siteurl' );
$original_domain = str_replace( 'https://', '//', $original_domain );
$original_domain = str_replace( 'http://', '//', $original_domain );
$content = str_replace( $original_domain, $mapped_domain, $content );
}
}
// Strip protocols
$content = str_replace( 'https://', '//', $content );
$content = str_replace( 'http://', '//', $content );
// Create a unique buster
$buster = uniqid();
// Create file
if ($this->can_write()) {
if ( ! $wp_filesystem->put_contents( $this->get_cached_file_path($buster), $content, FS_CHMOD_FILE ) ) {
// Fail!
error_log('Can\'t create CSS. Something went wrong');
return false;
}
// Update the cache buster file
$this->set_cache_buster($buster);
// Delete old files
$this->delete_old_styles($buster);
} else {
error_log('Can\'t create CSS. File does not exist or is not writable');
}
}
/*
* Determines if the CSS file is writable.
*/
public function can_write() {
// Does the folder exist?
if ( file_exists( $this->css_dir ) ) {
// Folder exists, but is the folder writable?
if ( ! is_writable( $this->css_dir ) ) {
// Folder is not writable.
error_log('CSS file could not be written.');
return false;
}
} else {
// Can we create the folder?
// returns true if yes and false if not.
return wp_mkdir_p( $this->css_dir );
}
// all is well!
return true;
}
/**
* Compiles the Kirki Variables and SCSS-file to a CSS-string
*
* @return string
*/
public function compile_scss()
{
$scss = new Compiler();
$scss->setImportPaths( get_stylesheet_directory() . '/assets/styles' );
$scss->setFormatter( 'Leafo\ScssPhp\Formatter\Compressed' );
$variables = \Kirki_Util::get_variables();
$vars = '';
foreach ( $variables as $variable => $value ) {
$vars .= '$' . $variable . ':' . $value . ';';
}
// Create SCSS string from Kirki variables and scss functions we've written
$scss_string = $vars . '
@import "theme"';
// Compile SCSS string to CSS string
$css = $scss->compile( $scss_string );
return $css;
}
}
$compiler = new DynamicCSS([
'filename' => 'styles',
'foldername' => 'dynamic-css',
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment