Ransford Okpoti's Dev Notes

August 24, 2009

Building Modifiers and Functions In Smarty

Filed under: PHP,Smarty — Tags: , , — admin @ 10:17 am

In this article, we will be looking at how to build modifiers and functions in Smarty, a very popular templating engine in PHP. If you don’t know how to setup Smarty up in your project, you can refer to my earlier post on Smarty Templating Overview which is accompanied by a screencast.

A quick look into the Smarty plugins directory should give you an idea of what’s under the hood, the obvious thing you would notice is the file naming convention adopted:
type.function_name.php
where type could be modifier, function, etc.
So, you will typically end up with file names of this structure:

  • modifier.[modifier name goes here].php
  • function.[function name goes here].php
  • etc

MODIFIERS

To be a little curious, lets open modifier.lower.php

<?php
// Comments removed for brevity
function smarty_modifier_lower($string)
{
    return strtolower($string);
}
?>

The above file only shows you that a Smarty plugin is just a normal PHP function, as you may be aware functions are first class citizens in PHP, which accepts arguments and returns a value that would be placed at the location it was called in the template file it self. So, {'Hmm, Interesting Discovery' | lower} in a template file would result in hmm, interesting discovery being substituted in the place of {'Hmm, Interesting Discovery' | lower} in the generated file from that template.
General usage:
{ argument_to_pass_to_the_modifier | modifier_name_goes_here}

The modifier always appears at the right, and there is a pipe | separating it and the argument it will work on.

Ok, so now what? Do you have a website with funny, and uninteresting URLs like
http://mysite.com/article.php?id=2,
where 2 may refer to an article with the title “All You Need To Know To Build Smarty Plugins”.
Let’s try and create a Search Engine Optimization or pretty URL for that article which would result in us having a new friendly URL like

http://mysite.com/article/all-you-need-to-know-to-build-smarty-plugins-2*

* To show the article, you will need to use apache mod_rewrite, but that is not the topic for discussion now, we just want to transform or slugify All You Need To Know To Build Smarty Plugins to all-you-need-to-know-to-build-smarty-plugins. And as a personal preference, i always append the unique id at the end of the generated URL so I do not run into problems when the title of the article is changed.

STEPS

Go into the plugins directory and create a file with the name modifier.seourl.php
Open the file and place the content below into it.

<?php
/**
 * Smarty seourl modifier plugin
 *
 * Type:     modifier<br>
 * Name:     seourl<br>
 * Purpose:  creates a Search Engine Optimized string
 *
 * @author   Ransford Okpoti <ranskills at yahoo dot co dot uk>
 * @param string
 * @return string
 */
function smarty_modifier_seourl($string) {
    $notAcceptableCharactersRegex = '#[^-a-zA-Z0-9_ ]#';
    $string = trim(preg_replace($notAcceptableCharactersRegex, '', strtolower($string)));
    return preg_replace('#[-_ ]+#', '-', $string);
}
 
?>

Once the file is saved, you can go to your template and use it like any normal modifier. E.g.
{$articleTitle | seourl}, {'Just what to see it working' | seourl}.
That’s it for modifiers, so just feel at home and create one if you see the need to.

FUNCTIONS

Smarty functions are similar in nature to their modifiers counterpart,but there is substantial difference in the way they are used within templates.

Usage:
{function_name optional_arguments}
where optional_arguments is in the form key1=value [, key2=value2]*

Lets create a very useful function which would enable us to dynamically include javascript files into our template.
This is extremely helpful if you want to stick to the generally accepted standard of adding javascript files to the tail end of your application or site to improve the performance of the site in terms of how long it takes the site to be loaded.


If you are interested in improving the performance of your site, you can follow the Best Practices for Speeding Up Your Web Site on yahoo which is an interesting and revealing information for any serious web developer.

A practical usage would be to include our little function we are about to develop in the main template of the site and to dynamically add the javascript files depending on which template(s) needs them.

Within the plugins directory, create a file named function.javascript.php with the content below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php 
/**
 * Smarty plugin
 * @package Smarty
 * @subpackage plugins
 */
 
/**
 * Smarty {javascript} function plugin
 *
 * Type:     function<br>
 * Name:     javascript<br>
 * Purpose:  outputs javascript tags for the provided srcs
 * @author Ransford Okpoti <ranskills at yahoo dot co dot uk>
 * @version 1.0
 * @example {javascript srcs='/script location'}
 *          {javascript srcs=$scripts}
 * @param array parameters
 * @return string
 */
function smarty_function_javascript($params) {
	$retval = '';
 
	if(isset($params['srcs'])){
		$scriptTemplate = '<script type="text/javascript" src="{0}"></script>';	
 
		$srcs = $params['srcs'];
	    if(is_array($srcs)){
	        foreach($srcs as $src){
	            $retval .= str_replace('{0}', $src, $scriptTemplate);
	        }
	    }
	    else{
	        $retval = str_replace('{0}', $params['srcs'], $scriptTemplate);
	    }			
	}
 
	return $retval;;
}
 
?>

Usage:
You could have this in your php file that is responsible for rendering the template.

...
// You could have some logic here to determine if a javascript file is required on a certain page
$scripts = array(
       '/public/js/contentslider.js',
       '/public/js/flash.js'
);
 
 
$this->smarty->assign('srcs', $scripts);
$this->smarty->display('template.xhtml');

The template showing just the line where our newly created Smarty function is used.

?View Code SMARTY
{javascript srcs=$srcs}

would result in this:

?View Code HTML4STRICT
<script type="text/javascript" src="/public/js/contentslider.js"></script>
<script type="text/javascript" src="/public/js/flash.js"></script>

This is just one approach of building Smarty plugins, the other approach is to use your existing classes or functions and register them using the function register_type*(…) on a Smarty instance/object.

*
Type could be any of the following:

  1. modifier
  2. function
  3. block
  4. outputfilter
  5. etc

Go! Go!! Go!!! Let Smarty work for you by developing your own plugins to provide extra functionalities.

[SCREEN CAST IS COMING SOON...]

August 14, 2009

A hack to automatically upgrade all WordPress plugins with a single click

Filed under: Javascript,PHP,WordPress — Tags: , , — admin @ 1:45 pm

WordPress rocks!! I love wordpress as much as I love to watch Friends,one of my favourite television series courtesy ViaSat 1. You care to know who my favourite character is? Hmm, am not telling you. Lets hit the road running now. As a blogging tool, wordpress has created a niche for itself among it peers. It has great features like assigning an entry, or a post, to multiple categories, has a nice tagging system and recently, you can actually upgrade/update your WordPress Plugins automatically without the need to download the plugin and extract it into the plugins folder of your wordpress installation. The plugins upgrade indicator which displays the number of plugins that need upgrading is a pretty cool enhancement, so you don’t go looking for which plugins have latest releases you are not aware of.

Despite the fact that it is a great tool, upgrading a plugin can be a real pain in the a** of users since you need to click on the upgrade automatically link , depending on your chosen translation, for each of the plugins that need upgrading. 20 clicks for 20 different plugins that need upgrading to give you a clearer picture. So I posed to question to myself “Couldn’t this process have been made a lot easier on the user?“. And obviously, the answer was a “YES!!, it can.”

A WordPress admin console showing the need to click on upgrade automatically link for each installed plugin

A WordPress admin console showing the need to click on upgrade automatically link for each installed plugin

WHAT WE WANT TO ACHIEVE

We want to select the plugins to be upgraded, using the checkboxes provided beside each plugin, from the plugins page in the admin console, and choose Upgrade from the list of actions under the Bulk Actions menu, and click on the Apply button to upgrade all the selected plugins that need upgrading.

HACKING WORDPRESS

Since we don’t want to mess with the codes in plugins.php too much, we’ll make use of javascript and a little bit of PHP to achieve our task by doing the following:

  • Adding the Upgrade option to the list of Bulk Actions
  • Attaching a click event listener to the Apply action/button.
  • Creating a JSON (Javascript Object Notation) object to contain the plugins that requires upgrading.

Here is the code that does the trick.

<script type="text/javascript">
/*<![CDATA[*/
var json = {
	<?php
	if ( ! empty($upgrade_plugins) ){
		$url = 'update.php?action=upgrade-plugin&amp;plugin=';
		$noUpgradePlugins = count($upgrade_plugins);
		$i = 0;
		foreach($upgrade_plugins as $plugin=>$v){
			$i++;
			$actionurl = $url.$plugin;
			$action = 'upgrade-plugin_'.$plugin;
			$pluginurl=  str_replace( '&amp;', '&amp;', urldecode(wp_nonce_url($actionurl, $action)));
			$pluginId = str_replace('-','', substr($plugin,0,strpos($plugin,'/')));
	?>
			"<?php echo $pluginId ;?>": "<?php echo $pluginurl ;?>" <?php if($noUpgradePlugins>$i) echo ",\n";?>
	<?php	}
	}
	?>
}

/*
the 1 and 2 at the end of the some of the variable names represents
the top and down instances of the component respectively
*/
var btnApply1 = document.getElementsByName('doaction_active')[0];
var btnApply2 = document.getElementsByName('doaction_active')[1];

var cbo1 = document.getElementsByName('action')[0];
var cbo2 = document.getElementsByName('action2')[0];

// This adds the Upgrade option to the list of bulk actions
cbo1.options.add(new Option("Upgrade","upgrade-selected"));
cbo2.options.add(new Option("Upgrade","upgrade-selected"));

btnApply1.onclick = function(){
	if(cbo1.value!='upgrade-selected'){
		return true;
	}

	upgradePlugins();
	return false;
}

btnApply2.onclick = function(){
	if(cbo2.value!='upgrade-selected'){
		return true;
	}

	upgradePlugins();
	return false;
}

// Upgrades only the checked plugins that have upgrades/updates available
function upgradePlugins(){
	var tags = document.getElementsByName('checked[]');

	for(var i=0; i<tags.length; i++){
		if(tags[i].checked){
			p = tags[i].value;
			pluginId = p.substring(0,p.indexOf('/'));
			pluginId = pluginId.replace(/-/g,''); // replaces all instances of -

			url='';
			try{
				url = eval('json.'+pluginId);
			}
			catch(e){}

			if(typeof url=='string' &amp;&amp; url.length>0){
				var frame = document.createElement('frame');
				frame.src = url;
				document.getElementsByTagName('head')[0].appendChild(frame);
			}
		}
	}

}
/*]]>*/

</script>

All you need to do now is to copy the above codes and paste it at the bottom of the plugins.php file located in the wp-admin folder in your preferred editor. Save the changes, and refresh your plugins page, and give it a try.

HOW IT WORKS

WordPress automatic upgrade hack in action

WordPress automatic upgrade hack in action


On the plugins page, select Upgrade from the Bulk actions list, check the plugins you want to upgrade and click on the Apply button.

CONCLUSION

This demonstrates a practical application of DOM manipulation using Javascript. The downside of our little practical javascript solution to this problem is that each time you update WordPress itself, the plugins.php file will be replaced with the one from the latest version of WordPress.
I hope it was helpful.

Powered by WordPress