Customizer Compile CSS Endless Loop

I’m using BB Theme 1.3.1.3 on WordPress 4.3.1, but I have a unique production/development environment that I’m working on. Essentially both the production and development servers have wordpress installed and the same themes/plugins, but they also point to the same database. The production server has full access to the database whereas the development server only has read access. This occasionally poses a problem with transients/options/theme_mods as the development server will make requests to update the database but doesn’t have access. Normally this silently fails, or isn’t a problem at all because transients/options/theme_mods have already been set in the database via the production server. However I ran into a problem with the way the BB Theme compiles css where it gets into an endless loop.

When viewing a site on the production server, opening the customizer, and setting the site to a new “Preset” (skin) and then view the same site on the development server I’m getting an error:

Fatal error: Maximum execution time of 30 seconds exceeded in /var/www/wp-content/themes/bb-theme/classes/class-lessc.php on line 3337

I’ve double checked that the ./uploads/bb-theme directory is writable on production and development.

The problem seems to be that the CSS file has not been created yet on the development server so it attempts to create it. The endless loop happens when _compile_css creates a new css_key and then saves the file, but isn’t able to save the new_css_key via update_option. So when css_url is called again (through recursion) the file still doesn’t exists because it’s using the old css_key so it tries to create the css file again. (and again and again)

So, I know this is an edge-case, but would you guys consider changing the _compile_css code from:

$new_css_key  = uniqid();
$css_slug     = self::_css_slug();

to:

$css_slug     = self::_css_slug();
$new_css_key  = get_option( self::$_css_key . '-' . $css_slug ) !== false ? get_option( self::$_css_key . '-' . $css_slug ) : uniqid();

If this doesn’t work, do you have any other suggestions?

Thanks for the detailed info on this issue! We can certainly look into that for you. I’ll do some testing next week and get back to you when I’m done with that.

Justin

I’ve been chewing on this one for the last week or so and the main issue I see is that with the workaround you proposed, the key will never change after the first time. The reason that is an issue is because the key needs to change so cache will get updated, especially for CDN’s like CloudFront that don’t respect query string cache busters.

Do you have any other ideas that might help in your situation?

Thanks!
Justin

Thanks for taking the time to consider how to fix this problem. After posting my original solution I realized caching would be a problem, since the name would never change. Another possible solution is to check to see if update_option was successful, by changing the last few lines of code in _compile_css:

// Save the new css key.
		if ( ! update_option( self::$_css_key . '-' . $css_slug, $new_css_key ) && get_option( self::$_css_key . '-' . $css_slug ) !== false ) {
            $new_css_key = get_option( self::$_css_key . '-' . $css_slug );
        }
        
		// Save the new css.
		file_put_contents( $cache_dir['path'] . $css_slug . '-' . $new_css_key . '.css', $css );

This does exactly what it’s supposed to on a production box (where it can update the database), but falls back to the existing key on the development box. I just don’t like it cause it feels like a hack that shouldn’t be necessary (except in this specific situation).

I thought about a filter, but again outside of this situation it seems unnecessary. I could probably do something (through an MU plugin on my dev box) hooking into the updated_option action and rename the css file to use the key already saved in the option. I’ll look into that more tomorrow and let you know if it works, but I suspect it will.

Thanks again!
John

I was able to get it working using the update_option hook and an MU plugin. It’s not completely update proof, but will meet my needs. It should work in all situations, but in my particular situation (since you cannot log into WordPress on the dev box) I could forego the _css_slug method and just set $css_slug to ‘skin’.

class Custom_FLCustomizer {
    static private $_css_key = 'fl_theme_css_key';
    
    private static function _css_slug() {
        if ( FLCustomizer::is_preset_preview() ) {
            			$slug = 'preview-' . $_GET['fl-preview'];
        		}
        		else if ( FLCustomizer::is_customizer_preview() ) {
            			$slug = 'customizer';
		        }
		        else {
            			$slug = 'skin';
		        }

        		return $slug;
    }
    
    public static function compile_css_rename($option, $old_css_key, $new_css_key) {
        if (stripos($option, self::$_css_key) !== false && $old_css_key !== false) {
            $cache_dir = FLCustomizer::get_cache_dir();
            $css_slug = self::_css_slug();
            $old_filename = $cache_dir['path'] . $css_slug . '-' . $new_css_key . '.css';
            $new_filename = $cache_dir['path'] . $css_slug . '-' . $old_css_key . '.css';

            if (file_exists($old_filename)) {
                rename($old_filename, $new_filename);
            }
        }
    }
}
add_action('update_option', 'Custom_FLCustomizer::compile_css_rename', 10, 3);

If you see any reason to not go this route let me know, otherwise I think this is my best option.

Thanks!
John

Hey John,

Thanks for taking the time to work on this, it’s a big help! :slight_smile:

I’d say that going the update_option action route is solid since it taps into WP’s internals. We’re also not planning to rework this stuff anytime soon (or ever), so it should be update proof. Future theme dev is going to revolve around more header layouts and Customizer settings.

Let me know if you want to discuss anything further.

Justin

Hi Justin,

No problem! Working on things like this just make me that much more familiar with BB theme/builder, which is certainly a good thing since I’m using them more and more.

Taping into WP’s internals is always preferred, but I’m glad to hear this stuff within BB won’t likely be changing anytime soon. Thanks for your help with this and keep up the good work!

John