Wordpress - Solutions for generating dynamic javascript / CSS
One additional option, depending on the kind of parameters you need to pass in. Let's call it (2a). You can also create PHP scripts which output dynamically-generated text/css
or text/javascript
rather than text/html
, and provide them the data that they need using GET parameters rather than by loading up WordPress. Of course this only works if you need to pass in a relatively small number of relatively compact parameters. So, for instance, say you need to pass in only the URL of a post or the directory of a file or similar, you can do something like this:
In header.php:
<script type="text/javascript" src="<?php print get_stylesheet_directory_uri();
?>/fancy-js.php?foo=bar&url=<?php print urlencode(get_permalink($post->ID)); ?>"></script>
In fancy-js.php:
<?php
header("Content-type: text/javascript");
?>
foo = <?php print json_encode($_GET['foo']); ?>;
url = <?php print json_encode($_GET['url']); ?>;
etc.
But this only allows you access to the data directly passed in the GET parameters; and it will only work if the number of things you need to pass in is relatively small, and the representation of those things relatively compact. (Basically handful of string or numeric values -- a username, say, or a directory; not a list of all of a user's recent posts or something like that.)
As for which one of these options is the best -- I don't know; that depends on your use case. Option (1) has the merit of being simple, and clearly allowing you access to any WordPress data you could possibly need, without the performance hit of loading WordPress twice. It's almost certainly what you should do unless you have a strong reason not to (e.g. due to the size of the stylesheet or script that you need to use).
If the size becomes big enough to cause a problem in terms of the weight of your one page, then you can try out (2) or (2a).
Or else -- this is probably the better idea -- you can try to separate out the parts of the script or the stylesheet that actually make use of the dynamic data from the parts that can be specified statically. Ssay you have a stylesheet that needs to be passed a directory from WordPress in order to set a background parameter for the #my-fancy element. You could put all of this into the head element:
<style type="text/css">
#my-fancy-element {
background-image: url(<?php print get_stylesheet_directory_uri(); ?>images/fancy.png);
padding: 20px;
margin: 20px;
font-weight: bold;
text-transform: uppercase;
font-size: 12pt;
/* ... KB and KB of additional styles ... */
}
#another-fancy-element {
/* ... KB and KB of additional styles ... */
}
/* ... KB and KB of additional styles ... */
</style>
But why would you need to do that? There's only one line here that depends on data from WordPress. Better to split out only the lines that depend on WordPress:
<style type="text/css">
#my-fancy-element {
background-image: url(<?php print get_stylesheet_directory_uri(); ?>images/fancy.png);
}
</style>
Put everything else in a static stylesheet that you load in with a standard link element (style.css or whatever):
#my-fancy-element {
/* background-image provided dynamically */
padding: 20px;
margin: 20px;
font-weight: bold;
text-transform: uppercase;
font-size: 12pt;
/* ... KB and KB of additional styles ... */
}
#another-fancy-element {
/* ... KB and KB of additional styles ... */
}
/* ... KB and KB of additional styles ... */
And let the cascade do the work.
The same goes for JavaScript: rather than doing this:
<script type="text/javascript">
// Here comes a huge function that uses WordPress data:
function my_huge_function () {
// Do a million things ...
jQuery('#my-fancy').append('<a href="'+<?php json_encode(get_permalink($GLOBALS['post']->ID)); ?>+'">foo</a>);
// Do a million more things ...
my_other_function(<?php print json_encode(get_userdata($GLOBALS['post']->post_author); ?>);
}
function my_other_function (user) {
// Do a million things ...
}
</script>
Instead put something like this in the head element:
<script type="text/javascript">
var WordPressPostData = {
url: <?php print json_encode(get_permalink($GLOBALS['post']->ID)); ?>,
author: <?php print json_encode(get_userdata($GLOBALS['post']->post_author)); ?>
}
</script>
And then drop the rest into a static JavaScript file, rewriting the my_huge_function() and my_other_function() to make use of the globals WordPressPostData.url and WordPressPostData.author.
40K of CSS or 40K of JS can almost always be split into <1K that actually depends on dynamic data, and the rest, which can be specified in a static external file and then recombined using either the cascade (for CSS) or globally-accessible variables (globals, DOM elements, or whatever other cubby-hole you prefer, for JS).
The dynamic CSS case is fairly simple.
Just create a function that outputs the dynamic CSS definitions inside of <style type="text/css"></style>
tags, and then hook that function into wp_print_styles
. e.g.
<?php
function mytheme_dynamic_css() {
$options = get_option( 'mytheme_options' );
?>
<style type="text/css">
/* Dynamic H1 font family */
h1 { font-family: <?php echo $options['h1_font_family']; ?>;
</style>
<?php
}
add_action( 'wp_print_styles', 'mytheme_dynamic_css' );
?>
Or, let's say you have pre-configured color schemes; you can enqueue the appropriate stylesheet according to the current user setting:
<?php
function mytheme_enqueue_colorscheme_stylesheet() {
$options = get_option( 'mytheme_options' );
$color_scheme = $options['color_scheme'];
wp_enqueue_style( $colorscheme, get_template_directory_uri() . '/css/' . $color_scheme . '.css' );
}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_colorscheme_stylesheet' );
?>
Note that, in this case, the function hooks into wp_enqueue_scripts
, since WordPress does not have a wp_enqueue_styles
action hook.
I was thinking that for a while now. Your question make me get back to it. Not sure it is a good idea or not, so i would like experts comments on that.
What if i write the javascript/css file via php when admin saving the data. It will be a one time write until user changes the layout again (which user may not do too often). That way we are accessing the database for the user settings only once when user saving data.
After writing the file it will be a regular javascript/css files so we dont have to call database everytime the theme loads.
One question that need answered: What will happen when a visitor try to access the site in the instant when php writing the file?
Let me know what you think.