GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

DynamicCSSCompiler::get_instance()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package   WordPress Dynamic CSS
4
 * @version   1.0.5
5
 * @author    Askupa Software <[email protected]>
6
 * @link      https://github.com/askupasoftware/wp-dynamic-css
7
 * @copyright 2016 Askupa Software
8
 */
9
10
/**
11
 * Dynamic CSS Compiler Utility Class
12
 * 
13
 * 
14
 * Dynamic CSS Syntax
15
 * ------------------
16
 * <pre>
17
 * body {color: $body_color;} 
18
 * </pre>
19
 * In the above example, the variable $body_color is replaced by a value 
20
 * retrieved by the value callback function. The function is passed the variable 
21
 * name without the dollar sign, which can be used with get_option() or 
22
 * get_theme_mod() etc.
23
 */
24
class DynamicCSSCompiler
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
25
{
26
    /**
27
     * @var DynamicCSSCompiler The reference to *Singleton* instance of this class
28
     */
29
    private static $instance;
30
    
31
    /**
32
     * @var array The list of dynamic styles paths to compile
33
     */
34
    private $stylesheets = array();
35
    
36
    /**
37
     * @var array The list of registered callbacks
38
     */
39
    private $callbacks = array();
40
    
41
    /**
42
     * @var aray The list of registered filters
43
     */
44
    private $filters = array();
45
    
46
    /**
47
     * Returns the *Singleton* instance of this class.
48
     *
49
     * @return DynamicCSSCompiler The *Singleton* instance.
50
     */
51
    public static function get_instance()
52
    {
53
        if (null === static::$instance) 
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
54
        {
55
            static::$instance = new static();
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
56
        }
57
        return static::$instance;
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
58
    }
59
    
60
    /**
61
     * Enqueue all registered stylesheets.
62
     */
63
    public function enqueue_styles()
64
    {
65
        foreach( $this->stylesheets as $stylesheet )
66
        {
67
            if( $this->callback_exists( $stylesheet['handle'] ) )
68
            {
69
                $this->enqueue_style( $stylesheet );
70
            }
71
        }
72
    }
73
    
74
    /**
75
     * Enqueue a single registered stylesheet.
76
     * 
77
     * @param array $stylesheet
78
     */
79
    public function enqueue_style( $stylesheet )
80
    {
81
        $handle = 'wp-dynamic-css-'.$stylesheet['handle'];
82
        $print  = $stylesheet['print'];
83
        
84
        wp_register_style( 
85
            $handle,
86
            // Don't pass a URL if this style is to be printed
87
            $print ? false : $this->get_ajax_callback_url( $stylesheet['handle'] )
88
        );
89
90
        wp_enqueue_style( $handle );
91
        
92
        // Add inline styles for styles that are set to be printed
93
        if( $print )
94
        {
95
            // Inline styles only work if the handle has already been registered and enqueued
96
            wp_add_inline_style( $handle, $this->get_compiled_style( $stylesheet ) );
97
        }
98
    }
99
    
100
    /**
101
     * This is the AJAX callback used for loading styles externally via an http 
102
     * request.
103
     */
104
    public function ajax_callback()
105
    {
106
        header( "Content-type: text/css; charset: UTF-8" );
107
        $handle = filter_input( INPUT_GET, 'handle' );
108
        
109
        foreach( $this->stylesheets as $stylesheet )
110
        {
111
            if( $handle === $stylesheet['handle'] )
112
            {
113
                echo $this->get_compiled_style( $stylesheet );
114
            }
115
        }
116
        
117
        wp_die();
118
    }
119
    
120
    /**
121
     * Add a style path to the pool of styles to be compiled
122
     * 
123
     * @param string $handle The stylesheet's name/id
124
     * @param string $path The absolute path to the dynamic style
125
     * @param boolean $print Whether to print the compiled CSS to the document
126
     * head, or include it as an external CSS file
127
     * @param boolean $minify Whether to minify the CSS output
128
     * @param boolean $cache Whether to store the compiled version of this 
129
     * stylesheet in cache to avoid compilation on every page load.
130
     */
131
    public function register_style( $handle, $path, $print, $minify, $cache )
132
    {
133
        $this->stylesheets[] = array(
134
            'handle'=> $handle,
135
            'path'  => $path,
136
            'print' => $print,
137
            'minify'=> $minify,
138
            'cache' => $cache
139
        );
140
    }
141
    
142
    /**
143
     * Register a value retrieval function and associate it with the given handle
144
     * 
145
     * @param string $handle The stylesheet's name/id
146
     * @param callable $callback
147
     */
148
    public function register_callback( $handle, $callback )
149
    {
150
        $this->callbacks[$handle] = $callback;
151
    }
152
    
153
    /**
154
     * Register a filter function for a given stylesheet handle.
155
     */
156
    public function register_filter( $handle, $filter_name, $callback )
157
    {
158
        if( !array_key_exists( $handle, $this->filters ) )
159
        {
160
            $this->filters[$handle] = array();
161
        }
162
        $this->filters[$handle][$filter_name] = $callback;
163
    }
164
    
165
    /**
166
     * Get the compiled CSS for the given style. Skips compilation if the compiled
167
     * version can be found in cache.
168
     * 
169
     * @param array $style List of styles with the same structure as they are 
170
     * stored in $this->stylesheets
171
     * @return string The compiled CSS for this stylesheet
172
     */
173
    protected function get_compiled_style( $style )
174
    {
175
        $cache = DynamicCSSCache::get_instance();
176
        
177
        // Use cached compiled CSS if applicable
178
        if( $style['cache'] )
179
        {
180
            $cached_css = $cache->get( $style['handle'] );
181
            if( false !== $cached_css )
182
            {
183
                return $cached_css;
184
            }
185
        }
186
187
        $css = file_get_contents( $style['path'] );
188
        if( $style['minify'] ) $css = $this->minify_css( $css );
189
        
190
        // Compile the dynamic CSS
191
        $compiled_css = $this->compile_css( 
192
            $css, 
193
            $this->callbacks[$style['handle']], 
194
            (array) @$this->filters[$style['handle']]
195
        );
196
        
197
        $cache->update( $style['handle'], $compiled_css );
198
        return $this->add_meta_info( $compiled_css );
199
    }
200
    
201
    /**
202
     * Add meta information to the compiled CSS
203
     * 
204
     * @param string $compiled_css The compiled CSS
205
     * @return string The compiled CSS with the meta information added to it
206
     */
207
    protected function add_meta_info( $compiled_css )
208
    {
209
        return "/**\n".
210
               " * Compiled using wp-dynamic-css\n".
211
               " * https://github.com/askupasoftware/wp-dynamic-css\n".
212
               " */\n\n".
213
               $compiled_css;
214
    }
215
    
216
    /**
217
     * Get the callback URL for enqueuing the stylesheet extrnally
218
     * 
219
     * @param string $handle The stylesheet's handle
220
     * @return string The URL for the given handle
221
     */
222
    protected function get_ajax_callback_url( $handle )
223
    {
224
        return esc_url_raw( 
225
            add_query_arg(array(
226
                'action' => 'wp_dynamic_css',
227
                'handle' => $handle
228
            ), 
229
            admin_url( 'admin-ajax.php'))
230
        );
231
    }
232
    
233
    /**
234
     * Minify a given CSS string by removing comments, whitespaces and newlines
235
     * 
236
     * @see http://stackoverflow.com/a/6630103/1096470
237
     * @param string $css CSS style to minify
238
     * @return string Minified CSS
239
     */
240
    protected function minify_css( $css )
241
    {
242
        return preg_replace( '@({)\s+|(\;)\s+|/\*.+?\*\/|\R@is', '$1$2 ', $css );
243
    }
244
    
245
    /**
246
     * Check if a callback function has been register for the given handle.
247
     * 
248
     * @param string $handle 
249
     * @return boolean
250
     */
251
    protected function callback_exists( $handle )
252
    {
253
        if( array_key_exists( $handle, $this->callbacks ) )
254
        {
255
            return true;
256
        }
257
        trigger_error( 
258
            "There is no callback function associated with the handle '$handle'. ".
259
            "Use <b>wp_dynamic_css_set_callback()</b> to register a callback function for this handle." 
260
        );
261
        return false;
262
    }
263
    
264
    /**
265
     * Parse the given CSS string by converting the variables to their 
266
     * corresponding values retrieved by applying the callback function
267
     * 
268
     * @param callable $callback A function that replaces the variables with 
269
     * their values. The function accepts the variable's name as a parameter
270
     * @param string $css A string containing dynamic CSS (pre-compiled CSS with 
271
     * variables)
272
     * @return string The compiled CSS after converting the variables to their 
273
     * corresponding values
274
     */
275
    protected function compile_css( $css, $callback, $filters )
276
    {
277
        return preg_replace_callback( 
278
                
279
            "#".                        // Begin
280
            "\\$".                      // Must start with $
281
            "([\\w-]+)".                // Match alphanumeric characters and dashes
282
            "((?:\\['?[\\w-]+'?\\])*)". // Optionally match array subscripts i.e. $myVar['index']
283
            "((?:".                     // Optionally match pipe filters i.e. $myVar|myFilter
284
                "\\|[\\w-]+".           // Starting with the | character
285
                "(\([\w\.,']+\))?".     // Filters can have strings and numbers i.e myFilter('string',1,2.5)
286
            ")*)".                      // Allow for 0 or more piped filters
287
            "#",                        // End
288
            
289
            function( $matches ) use ( $callback, $filters ) 
290
            {
291
                $subscripts = array();
292
                
293
                // If this variable is an array, get the subscripts
294
                if( '' !== $matches[2] )
295
                {
296
                    preg_match_all('/[\w-]+/i', $matches[2], $subscripts);
297
                }
298
                
299
                $val = call_user_func_array( $callback, array( $matches[1],@$subscripts[0] ) );
300
                
301
                // If there are filters, apply them
302
                if( '' !== $matches[3] )
303
                {
304
                    $val = $this->apply_filters( substr( $matches[3], 1 ), $val, $filters );
305
                }
306
                
307
                return $val;
308
            }, $css
309
        );
310
    }
311
    
312
    /**
313
     * Apply the filters specified in $filters_string to the given $value.
314
     * 
315
     * @param string $filters_string 
316
     * @param string $value
317
     * @param array $filters Array of callback functions
318
     * @return string The value after all filters have been applied
319
     */
320
    protected function apply_filters( $filters_string, $value, $filters = array() )
321
    {
322
        foreach( explode( '|', $filters_string) as $filter )
323
        {
324
            $args = array( $value );
325
            
326
            if( false !== strrpos( $filters_string, "(" ) )
327
            {
328
                $pieces = explode( '(', $filter );
329
                $filter = $pieces[0];
330
                $params = explode( ',', str_replace( ')', '', $pieces[1] ) );
331
                array_walk( $params, array( $this, 'strtoval' ) ); // Convert string values to actual values
332
                $args = array_merge( $args, $params );
333
            }
334
            
335
            if( key_exists( $filter, $filters ) )
336
            {
337
                $value = call_user_func_array( $filters[$filter], $args );
338
            }
339
        }
340
        return $value;
341
    }
342
    
343
    /**
344
     * Convert the given string to its actual value.
345
     * 
346
     * @param string $str The string to be converted (passed by reference)
347
     */
348
    protected function strtoval( &$str )
349
    {
350
        if( 'false' === strtolower($str) ) $str = false;
351
        if( 'true' === strtolower($str) ) $str = true;
352
        if( false !== strrpos( $str, "'" ) ) $str = str_replace ( "'", "", $str );
353
        if( is_numeric( $str ) ) $str = floatval( $str );
354
    }
355
}
356