Posted by on in iDevelop, PHP | 0 comments

A change that I pushed in iG:Syntax Hiliter v4.2 was that shorthand style tags were enabled for all languages. Apart from the GeSHi language files bundled in the plugin, you can add additional language files in the “geshi” directory of your theme and those will be picked up by the plugin. Since the architecture of the plugin relies on Shortcode API of WordPress rather than doing its own regex for tag parsing, the plugin always needs to know what language files are available to it to be able to allow shorthand style tags else the code blocks won’t get picked up by the plugin.

Now this isn’t a problem if you use the full tag like [sourcecode lang="javascript"]//some code[/sourcecode] since in this case the language file is needed much later when the code is to be highlighted. But if you use something like [javascript]//some code[/javascript] then the plugin needs to know about the existence of javascript language file before it starts going through post/comment content so that it knows which code blocks to pick and which ones to leave out. Doing a wildcard lookup and discarding the ones which we don’t need isn’t an option, that would be poor software design and waste of resources.

The only feasible way to always be up-to-date on what language files are available is to scan plugin and theme directories for language files. That way plugin knows if any new language has been added or if one has been removed. And the names of these languages had to be cached, scanning the directories on every request would be dumb. Now, a couple of people asked me why I used Mark Jaquith’s WP TLC Transients instead of using the WordPress Cron.

php
…/class-ig-syntax-hiliter.php

  1. /**
  2.  * This function uses WP TLC class to fetch the language file names from supported directories
  3.  * and schedules a refresh of the transient cache. It also allows a force rebuild of
  4.  * transient cache via the optional $force_rebuild parameter.
  5.  */
  6. protected function _get_languages( $force_rebuild = 'no' ) {
  7.     $force_rebuild = ( ! $this->_is_yesno( $force_rebuild ) ) ? 'no' : strtolower( $force_rebuild );
  8.  
  9.     $transient = new TLC_Transient( self::plugin_id . '-languages' );
  10.  
  11.     if( $force_rebuild == 'yes' ) {
  12.         $transient->delete();   //delete existing cache so we'll get fresh one below
  13.     }
  14.  
  15.     $languages = $transient->updates_with( array( $this, 'build_language_list' ) )
  16.                 ->expires_in( self::languages_cache_life )
  17.                 ->get();
  18.  
  19.     if( empty( $languages ) ) {
  20.         return;
  21.     }
  22.  
  23.     return array_combine( $languages, $languages );
  24. }

The reason I went for WP TLC Transients over WordPress Cron is that in my experience WordPress Cron is a bit unreliable. You can’t always be sure it’ll run your callback when you want it and there is a minimum wait of one minute (something you can work around but that’s unnecessary extra work). While the WP TLC Transients just work, everytime. Transients aren’t for storing large data or for storing data for a long time, they can get wiped out anytime. The good thing about them (over wp_options) is if memcache is available then they can be stored in there making I/O quite fast. And since we will be scanning directories frequently for language files, the transients suit our purpose well for caching language names.