├── .gitignore ├── .gitmodules ├── README.md └── wp-sass.php /.gitignore: -------------------------------------------------------------------------------- 1 | *.komodoproject -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "phpsass"] 2 | path = phpsass 3 | url = https://github.com/richthegeek/phpsass.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enable Sass and Scss in WordPress 2 | 3 | This plugin allows you to write and edit .sass and .scss files directly and 4 | have WordPress do the job of compiling and caching the resulting CSS. It 5 | eliminates the extra step of having to compile the files into CSS yourself 6 | before deploying them. 7 | 8 | ## Installation: 9 | 10 | If you are using git to clone the repository do the following: 11 | 12 | git clone git://github.com/sanchothefat/wp-sass.git wp-sass 13 | git submodule update --init --recursive 14 | 15 | If you are downloading the zip or tar don't forget to download the phpsass 16 | dependency too https://github.com/richthegeek/phpsass and copy it into the `phpsass` 17 | folder. 18 | 19 | ## Usage: 20 | 21 | You can either install the script as a standard plugin or use it as an include within a theme or plugin. 22 | 23 | For use with themes add the following lines to your functions.php: 24 | 25 | ```php 26 | 41 | ``` 42 | 43 | Any registered styles with the .sass or .scss suffix will be compiled and the file URL 44 | rewritten. 45 | 46 | ### Using PHP in .sass and .scss files 47 | 48 | You can also create `.sass.php` or `.scss.php` files that will be preprocessed in the WordPress context. 49 | What this means is that you can use WordPress functions within the stylesheets themselves eg: 50 | 51 | ```sass 52 | $red: ; 53 | 54 | body { 55 | background: $red; 56 | } 57 | ``` 58 | 59 | ## Further Reading 60 | 61 | [Read the Sass and Scss documentation here](http://sass-lang.com/) 62 | 63 | 64 | ## License 65 | 66 | The software is licensed under the MIT license. 67 | -------------------------------------------------------------------------------- /wp-sass.php: -------------------------------------------------------------------------------- 1 | get_cache_dir() ) . "{$handle}.css"; 93 | 94 | $syntax = strstr( $sass_path, 'scss' ) ? 'scss' : 'sass'; 95 | 96 | // automatically regenerate files if source's modified time has changed or vars have changed 97 | try { 98 | // load the cache 99 | $cache_path = "{$css_path}.cache"; 100 | if ( file_exists( $cache_path ) ) 101 | $full_cache = unserialize( file_get_contents( $cache_path ) ); 102 | 103 | // If the root path in the cache is wrong then regenerate 104 | if ( ! isset( $full_cache ) ) 105 | $full_cache = array( 'root' => dirname( __FILE__ ), 'path' => $sass_path, 'css' => '', 'updated' => filemtime( $sass_path ) ); 106 | 107 | // check output after php has run for changes. Options are preloaded by default so the database hit shouldn't be too bad for most uses 108 | if ( strstr( $sass_path, '.php' ) ) { 109 | ob_start(); 110 | include( $sass_path ); 111 | $sass = ob_get_clean(); 112 | if ( ! file_exists( "{$cache_path}.preprocessed.{$syntax}" ) || ( file_exists( "{$cache_path}.preprocessed.{$syntax}" ) && $sass != file_get_contents( "{$cache_path}.preprocessed.{$syntax}" ) ) ) { 113 | $full_cache[ 'css' ] = ''; 114 | file_put_contents( "{$cache_path}.preprocessed.{$syntax}", $sass ); 115 | } 116 | } 117 | 118 | // parse if we need to 119 | if ( empty( $full_cache[ 'css' ] ) || filemtime( $sass_path ) > $full_cache[ 'updated' ] || $full_cache[ 'root' ] != dirname( __FILE__ ) ) { 120 | // preprocess php files in WP context 121 | if ( strstr( $sass_path, '.php' ) ) { 122 | $full_cache[ 'css' ] = $this->__parse( "{$cache_path}.preprocessed.{$syntax}", $syntax, "nested", array( dirname( $sass_path ) ) ); 123 | } else { 124 | $full_cache[ 'css' ] = $this->__parse( $sass_path, $syntax, "nested", array( dirname( $sass_path ) ) ); 125 | } 126 | // update cache creation time 127 | $full_cache[ 'updated' ] = filemtime( $sass_path ); 128 | file_put_contents( $cache_path, serialize( $full_cache ) ); 129 | file_put_contents( $css_path, $full_cache[ 'css' ] ); 130 | } 131 | } catch ( exception $ex ) { 132 | wp_die( $ex->getMessage() ); 133 | } 134 | 135 | // return the compiled stylesheet with the query string it had if any 136 | return trailingslashit( $this->get_cache_dir( false ) ) . "{$handle}.css" . ( ! empty( $query_string ) ? "?{$query_string}" : '' ); 137 | } 138 | 139 | public function __parse( $file, $syntax, $style = 'nested', $load_path = array() ) { 140 | $options = array( 141 | 'style' => $style, 142 | 'cache' => FALSE, 143 | 'syntax' => $syntax, 144 | 'debug' => FALSE, 145 | 'callbacks' => array( 146 | 'warn' => array( $this, 'cb_warn' ), 147 | 'debug' => array( $this, 'cb_debug' ), 148 | ), 149 | 'load_paths' => $load_path, 150 | ); 151 | // Execute the compiler. 152 | $parser = new SassParser( $options ); 153 | return $parser->toCss( $file ); 154 | } 155 | 156 | public function cb_warn( $message, $context ) { 157 | print "

WARN : "; 158 | print_r( $message ); 159 | print "

"; 160 | } 161 | 162 | public function cb_debug( $message ) { 163 | print "

DEBUG : "; 164 | print_r( $message ); 165 | print "

"; 166 | } 167 | 168 | 169 | /** 170 | * Compile editor stylesheets registered via add_editor_style() 171 | * 172 | * @param String $mce_css comma separated list of CSS file URLs 173 | * 174 | * @return String New comma separated list of CSS file URLs 175 | */ 176 | public function parse_editor_stylesheets( $mce_css ) { 177 | 178 | // extract CSS file URLs 179 | $style_sheets = explode( ",", $mce_css ); 180 | 181 | if ( count( $style_sheets ) ) { 182 | $compiled_css = array(); 183 | 184 | // loop through editor styles, any .sass or .scss files will be compiled and the compiled URL returned 185 | foreach( $style_sheets as $style_sheet ) 186 | $compiled_css[] = $this->parse_stylesheet( $style_sheet, $this->url_to_handle( $style_sheet ) ); 187 | 188 | $mce_css = implode( ",", $compiled_css ); 189 | } 190 | 191 | // return new URLs 192 | return $mce_css; 193 | } 194 | 195 | 196 | /** 197 | * Get a nice handle to use for the compiled CSS file name 198 | * 199 | * @param String $url File URL to generate a handle from 200 | * 201 | * @return String Sanitised string to use for handle 202 | */ 203 | public function url_to_handle( $url ) { 204 | 205 | $url = parse_url( $url ); 206 | $url = str_replace( '.sass', '', basename( $url[ 'path' ] ) ); 207 | $url = str_replace( '/', '-', $url ); 208 | 209 | return sanitize_key( $url ); 210 | } 211 | 212 | 213 | /** 214 | * Get (and create if unavailable) the compiled CSS cache directory 215 | * 216 | * @param Bool $path If true this method returns the cache's system path. Set to false to return the cache URL 217 | * 218 | * @return String The system path or URL of the cache folder 219 | */ 220 | public function get_cache_dir( $path = true ) { 221 | 222 | // get path and url info 223 | $upload_dir = wp_upload_dir(); 224 | 225 | if ( $path ) { 226 | $dir = apply_filters( 'wp_sass_cache_path', trailingslashit( $upload_dir[ 'basedir' ] ) . 'wp-sass-cache' ); 227 | // create folder if it doesn't exist yet 228 | if ( ! file_exists( $dir ) ) 229 | wp_mkdir_p( $dir ); 230 | } else { 231 | $dir = apply_filters( 'wp_sass_cache_url', trailingslashit( $upload_dir[ 'baseurl' ] ) . 'wp-sass-cache' ); 232 | } 233 | 234 | return rtrim( $dir, '/' ); 235 | } 236 | 237 | } // END class 238 | 239 | } // endif; --------------------------------------------------------------------------------