How to make jQuery / Prototype / MooTools & others play nicely with Smarty

Smarty is the first template engine I have learned and used in my projects. Smarty makes your PHP code cleaner and promotes the V in MVC. Here is an example of Smarty template:

<html>
<head>
<title>User</title>
</head>
<body>
    User Information:<br />
    Name: {$name}
</body>
</html>

Smarty will replace the {$name} with the variable that you set in your PHP code. Anyway, do you see the problem that might arise when you try to embed your jQuery code or any other javascript library (like Prototype, MooTools, Extjs, etc.) that uses $ as a function name in the <head>?

Smarty parses the file and whenever it encounters the {$ it would try to parse it and replace with the PHP variable like in this example here:

<html>
<head>
<title>User</title>
<script type="text/javascript">
    $(document).ready(function(){
        $(".clazz").css("color", "red");
    });
</script>
</head>
<body>
    User Information:<br />
    Name: {$name}
</body>
</html>

The problem:

Smarty would not care that { and $ are on different lines and would see it like {$(".clazz.... The code above would cause this Smarty error:

Fatal error: Smarty error: [in templateFile.tpl line 5]: syntax error: unrecognized tag: $(".clazz").css("color", "red"); (Smarty_Compiler.class.php, line 455) in C:\PHP\smarty\libs\Smarty.class.php on line 1092

The solution:

There are couple of things you can do about this problem:

  1. Move your javascript (jQuery, Prototype, etc.) code into the external .js file.
  2. Use jQuery() instead of $().
  3. Use Smarty’s {literal}...{/literal} directives to tell Smarty parsing engine that it should not interpret the code within the block.

Example:

Here is how we can rewrite our javascript code above using the 3rd tip:

<html>
<head>
<title>User</title>
<script type="text/javascript">
{literal}
    $(document).ready(function(){
        $(".clazz").css("color", "red");
    });
{/literal}
</script>
</head>
<body>
    User Information:<br />
    Name: {$name}
</body>
</html>