Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Let's say you need to generate javascript or CSS code that depends on the current context.

For example you have a form on the homepage that fires an ajax request on submit, and a different form on the single page. Or in the case of CSS, you want to create a theme that allows its users to build their own layout, change colors etc.

Solutions I see so far:

  1. Include the code in the head section of the document (or at the end in case of JS)

  2. Do a special request that outputs the code, like site.com?get_assets. This is slow because WP gets loaded twice.

  3. Store it in temporary files for a certain amount of time, and load it from there. Not very reliable for public themes or plugins.

  4. Javascript only - make it static by putting it into a normal file that gets loaded every time. In this case you would have to make your code handle any situation

Do you know others? Which way would you go?

share|improve this question

4 Answers 4

up vote 7 down vote accepted

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&amp;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).

share|improve this answer
    
Brilliant answer! –  scribu Oct 30 '11 at 20:31
2  
Just a small addition: in case of JS, we can use wp_localize_sciprt to add dynamic variables. –  Rilwis Nov 2 '11 at 3:41

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.

share|improve this answer
1  
same as 1). This is what I'm doing now, but if you have like 40K of CSS you get a bulky html document –  onetrickpony Oct 29 '11 at 17:55
1  
But those 40K of CSS have to be output somewhere, right? And, definitely the same as #1, but is the right way to inject dynamic CSS in WordPress. :) –  Chip Bennett Oct 29 '11 at 19:16

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.

share|improve this answer
    
If you generate those files in wp-content/uploads (the only directory guaranteed to be writable from WP code), it could be a viable approach. I think even WP Core uses this technique for one js file. –  scribu Oct 31 '11 at 11:43
    
The drawback is that it's not really dynamic, i.e. it's the same for everyone on all pages. For each variation, you would have to generate a new file. It's still a good approach for theme/plugin options, as you mentioned. –  scribu Oct 31 '11 at 11:53
    
@scribu: yes its true. it can be a mess for something like. if we give users a customized profile page and have to write files each one of them. But it might be a good approach for something like if we do a visual website maker (drag and drop) where user changes the colors and add various effects (as of this question) etc.. and may be combined with WPMU ;) –  Sisir Oct 31 '11 at 12:08

Create a dynamic JS.php file and feed important query_vars to it. Those variables in $_GET will help the file determine context and in it you can cache and use readfile() for future requests... do whatever.

Just make sure that file loads the wp-load.php before anything else, so you have access to WP functions. Use relative path to current folder (dirname(__FILE__)) or just digg descending in the folder structure to locate wp-load.php regardless of plugin placement.

Code to seek wp-load.php from anywhere

// Ensure single declaration of function!
if(!function_exists('wp_locate_loader')):
    /**
     * Locates wp-load.php looking backwards on the directory structure.
     * It start from this file's folder.
     * Returns NULL on failure or wp-load.php path if found.
     * 
     * @author EarnestoDev
     * @return string|null
     */
    function wp_locate_loader(){
        $increments = preg_split('~[\\\\/]+~', dirname(__FILE__));
        $increments_paths = array();
        foreach($increments as $increments_offset => $increments_slice){
            $increments_chunk = array_slice($increments, 0, $increments_offset + 1);
            $increments_paths[] = implode(DIRECTORY_SEPARATOR, $increments_chunk);
        }
        $increments_paths = array_reverse($increments_paths);
        foreach($increments_paths as $increments_path){
            if(is_file($wp_load = $increments_path.DIRECTORY_SEPARATOR.'wp-load.php')){
                return $wp_load;
            }
        }
        return null;
    }
endif;
// Now try to load wp-load.php and pull it in
$mt = microtime(true);
if(!is_file($wp_loader = wp_locate_loader())){
    header("{$_SERVER['SERVER_PROTOCOL']} 403 Forbidden");
    header("Status: 403 Forbidden");
    echo 'Access denied!'; // Or whatever
    die;
}
require_once($wp_loader); // Pull it in
unset($wp_loader); // Cleanup variables

Cheers, Scribu!

PS: For complicated structures where folders don't follow the normal WP decremental structure, parent plugins can share informations with directly accessible files. A parent plugin that comes with a dynamic PHP file that renders CSS/JS can write into a file the realpath() of the wp-load.php and the standalone file can use that. This would be an issue for 0.1% of WP users. I think those who move folders and don't follow the normal structure know what they're doing and can probably PIMP plugins that need to load wp-load.php directly.

share|improve this answer
    
Cute! Haters, please append explanations. Enlighten me. Thanks ;) xoxo –  EarnestoDev Oct 29 '11 at 17:34
    
It's bad practice to include wp-load.php from a theme or plugin file, since the wp-content and/or plugins directories could be anywhere relative to the root WP dir. Remember WP_CONTENT_DIR and WP_PLUGINS_DIR. –  scribu Oct 30 '11 at 20:35
1  
@scribu And the standalone file can collaborate with a parent plugin. The parent plugin can store the wp-load.php in the folder where it's located and the dynamic js generator can read it from there. Simple... –  EarnestoDev Oct 30 '11 at 21:06
1  
Yes, the parent plugin approach could work. Write it up in your answer and I'll remove my downvote. PS: This site is in english; you might have problems if you continue to leave remarks in Romanian. –  scribu Oct 30 '11 at 21:32
4  
Cut the attitude. Manual core load is viable technique, but far from good first pick for most things. No one doubts that you can make it work. Votes are about quality of your answer, not your brain. –  Rarst Oct 30 '11 at 22:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.