Getting the bloginfo correctly

A previous version of this site ran on an WordPress MS install.

As with most WordPress sites we use plugins to enhance WordPress, including Donncha O Caoimh‘s excellent WordPress MU Domain Mapping plugin. As the name implies, the domain mapping plugin allows us to use top level domains for each site rather than being stuck with sub-domains.

Taking care with plugins

Many plugins are tested for the single site version of WordPress only. I don’t have a problem with this as most plugins are released under the GPL and free in terms of both speech and beer. If I’m not paying for software, it’s up to me to test it in the fringe environment of WordPress MS.

Now that WordPress is WordPress MS is WordPress, more developers may test in both environments but they certainly can’t be expected to test with all manner of combinations of plugins.

The standout problem

One of the standout problems when using plugins with WordPress MS is when they define a constant for the plugin’s url as the script starts executing, the PHP code may look similar to:

<?php

  define('PLUGIN_DIR', get_bloginfo('url') . "/wp-content/plugins/peters-plugin");

  function plugin_js_css(){
    wp_enqueue_script('plugin-js', PLUGIN_DIR . '/script.js');
    wp_enqueue_style('plugin-css', PLUGIN_DIR . '/style.css');
  }

  add_action('init', 'plugin_js_css');

?>

The above stands equally for themes mapping the stylesheet directory at the start of execution:

<?php

  define('THEME_DIR', get_bloginfo('stylesheet_directory') );

  function theme_js_css(){
    wp_enqueue_script('theme-js', THEME_DIR . '/script.js');
    wp_enqueue_style('theme-css', THEME_DIR . '/style.css');
  }

  add_action('init', 'theme_js_css');

?>

The get_bloginfo and bloginfo functions return information about your blog and your theme settings including the site’s home page, the theme’s directory (as in the second code sample above) or the stylesheet url. bloginfo outputs the requested information to your HTML, get_bloginfo returns it for use in your PHP.

Outside of code samples, bloginfo and get_bloginfo are interchangeable throughout this article.

The problems occur when a subsequently loaded plugin needs to change something retrieved from bloginfo. In this site’s case, Domain Mapping changes all URLs obtained through bloginfo, but it could be a plugin that simply changes the stylesheet url to a subdomain to speed up page load.

In a recent case, a plugin – let’s call it Disqus – was defining a constant in this manner. As result an XSS error was occurring when attempting to use Facebook Connect. Replacing the constant with a bloginfo call fixed the problem.

The improved code for the first sample above is:

<?php

  function plugin_js_css(){
    wp_enqueue_script('plugin-js', get_bloginfo('url') . '/wp-content/plugins/peters-plugin/script.js');
    wp_enqueue_style('plugin-css', Pget_bloginfo('url') . '/wp-content/plugins/peters-plugin/style.css');
  }

  add_action('init', 'plugin_js_css');

?>

bloginfo doesn’t hit the database everytime

I presume the developers set their own constants because they’d like to avoid hitting the database repeatedly to receive the same information.

Having run some tests on my local install of WordPress, I can assure you this is not the case. Running bloginfo('stylesheet_directory') triggers a db call on the first occurrence, the information is then cached for subsequent calls.

I realise I sound incredibly fussy and that I’m suggesting we protect against edge cases on our edge cases. You’re right, and it’s not the first time, but as developers it’s the edge cases that we’re employed to avoid.

JavaScript the WordPress Way / Part 2

In Part 1 we discussed the conflicts that can occur on a WordPress site if themes and plugins add JavaScript using <script> tags. We introduced the wp_register_script and wp_enqueue_script functions developed to avoid these conflicts.

In this section we’ll deal with a more complicated example and use Google’s AJAX libraries API to lower your bandwidth costs. We’ll also take what we’ve learnt about including JavaScript and apply it to our CSS.

JavaScript the WordPress Way / Part 1

Two of the most important WordPress functions are often ignored by WordPress theme and plugin developers. This is the fault of the functions themselves, they need to improve their PR and hire better publicists.

It’s also possible your theme or plugin will work perfectly well without these functions on its own. Problems will arise when your theme or plugin both use the same JavaScript library or if Prototype and jQuery are both used on the same site.

These functions are used to add JavaScript to the html, either in the head or the footer.

Introducing wp_register_script and wp_enqueue_script

Charging for themes? Do the right thing!

Of all the WordPress functions, I think wp_register_script, wp_register_style, wp_enqueue_script, and, wp_enqueue_style are the most elegant. It’s possible to get away with using only the wp_enqueue_* functions, but I prefer to use both for a little bit more control.

For the uninitiated, these functions allow you to add JavaScript and CSS files to the header (or footer, in later versions of WP) without running of the risk of another plugin adding the same file, that is, you avoid the following:

<script type="text/javascript" source="http://.../a-plugin/jQuery.js"></script>
<script type="text/javascript" source="http://.../a-plugin/plugin.js"></script>
<script type="text/javascript" source="http://.../my-theme/jQuery.js"></script>
<script type="text/javascript" source="http://.../my-theme/theme.js"></script>

If you develop themes or plugins for WordPress and are unaware of these functions, you should refer to the codex to get the low down on at least wp_enqueue_script, and wp_enqueue_style – these register and queue the files, the wp_register_* functions register the file ready to be queued for output.

The Rant

Despite the value these functions can add to themes and plugins, they are under-utilised in development. The functions have wider adoption in plug-in development, but it’s still well below 100%. In theme development adoption is virtually non-existent (at least in the themes I’ve used).

This failure to code properly is evenly spread across both free and paid themes. I?m happy to look the other way for free themes. After all, the motivation behind the theme may have been to learn WordPress development.

In commercial themes, particularly those above the US$30-$35 price point, it’s downright frustrating that these products haven’t been developed properly.

When someone purchases a theme, they shouldn’t have to debug the product to find out why a JavaScript framework is being included twice. The reason for the purchase is that they either don’t want to, or know how to, develop.

Avoiding costly mistakes

Evaluating a commercial theme on behalf of a client triggered this rant. At $195, it’s quite expensive in the world of WordPress. As I was viewing the source code of the online demo, I discovered the faux pas. We’ll advise against using that theme as a starting point. In fact, within short time we’d found a theme $195 cheaper that would do the job.

Looking at the source code of a demo site is usually enough to tell you how the theme is inserting its scripts:

  • Both <link> and <script> tags will use single quotes around attributes (‘), rather than double quotes (“),
  • CSS <link> tags will have an ID attribute ending in -css, eg: id=’shadowbox-css-css’, and,
  • JavaScript and CSS files include the version number as a query string eg jQuery.js?ver=1.3.2 (although a hook can be used to remove this)

Making sure that the wp_register_script, wp_register_style, wp_enqueue_script, and, wp_enqueue_style are included properly will save time, bandwidth and also avoid some detrimental conflicts.

Including WordPress’s comment-reply.js (the right way)

Since threaded comments were enabled in WordPress 2.7, most themes include the following line in header.php

<?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>

This code checks if the visitor is browsing either a page or a post and adds the JavaScript required for threaded comments if they are.

I prefer a slight variation

<?php
if ( is_singular() && comments_open() && get_option('thread_comments') )
  wp_enqueue_script( 'comment-reply' );
?>

My variation checks if the visitor is browsing either a page or a post, if comments are open for the entry, and finally, if threaded comments are enabled. If all of these conditions are met, the JavaScript required for threaded comments is added.

If you run your wp_enqueue_script calls in functions.php, as I do, this is the code to use:

<?php
function theme_queue_js(){
if ( (!is_admin()) && is_singular() && comments_open() && get_option('thread_comments') )
  wp_enqueue_script( 'comment-reply' );
}
add_action('wp_print_scripts', 'theme_queue_js');
?>

The call is added to the wp_print_scripts action as is_singular and comments_open are unknown during the init action.

 

Note: I’ve written a plugin to make the comment-reply JavaScript unobtrusive, it’s call Rapid Comment Reply.