Syndicate

Feed

Theming the contact form in Drupal 6

The following exercise consists in theming the contact form in Drupal 6. Once we're done, it will look like we'll have created two fall-back-on 'pages' for contact forms, one page/form to 'request a quote' at Randy.com/contact/quote, and an other page/form for general inquiries at Randy.com/contact/info. The trick here — if there's one — consists in theming the contact form differently based on the requested URI.

This exercise will show you how to:

  • recognize when a module has not registered a specific theming function for a form it generates,
  • register a theming function for a Drupal form in your theme, using HOOK_theme,
  • work with template suggestions,
  • use the Devel module function dsm() to inspect complex variables, such as Drupal forms.

Using the contact module

Context: You're having a bad day. Your ex-boyfriend wrote to you that he loves going down on women, while he never went down on you ever for the entire duration of the relationship, and you're developing yet another Drupal site for Randy.com.

Randy believes he can give something back to the world. Doesn't everyone? On his new site, he wants to provide menu links to two different contact forms. One to 'request a quote', and another to ask Randy questions on whatever-else, like 'Randy, what is it you use to have such great hair?'.

You're in luck because in core there's a module to whip out a contact form — and validate it and send you its submitted content by e-mail. This module produces only one contact form, with a 'select an option' drop-down list of 'categories'. For each of these categories, you, the admin, can specify a different e-mail as the destination for the form's submitted content.

After some theming magic, it will look like you'll have created two different forms. But you won't... ah ah ah... After your magic touch, it will look like you'll have created two Drupal pages... but in truth (shhhh...) you definitely won't. Your site will behave as if, and that's all that matters.

To check if your contact module is enabled, try and access the page admin/build/contact/add, or look for 'Contact form' under 'Site building' in your Admin menu. If you land on the 'Site building' page, you have to enable the module. Head over admin/build/modules.

Enable the Contact module on your Modules page.

Now, you'll create two Contact categories, one for requesting a quote and an other for general inquiries. Head over admin/build/contact/add. Or, go to Site building → Contact form, then click on the Add category tab. Create a 'request a quote' category like so:

Adding a 'request a quote' category to your Contact form.

When you're done, you'll be redirected to admin/build/contact. Place your cursor over the 'edit' link next to your category. This link will point to admin/build/contact/edit/x. That number x is the cid of your category (contact hi-dee). Take mental note of it.

Determining the cid of a contact category.

And taking note of it.

Create a 2nd category for general inquiries, with its own e-mail address, etc. You will end up with two categories. If you had created categories before and deleted them, the 'cid' counter has never been reset (it never is), so you may add categories with, e.g., cid 32 and 33 (or 65 and 66). That's fine.

Both categories on the admin/build/contact page.

Take note of the 'cid' for general inquiries.

Taking note of the cid of the general inquiries category.

What theming function to override...?

So, now, you want to theme the contact form. That's your goal. The first question you ask yourself is What theming function must I intercept and override?

To find answers to these types of questions, 11heavens.com recommends using the module Theme Developer.

Download the Devel set of modules from Drupal.org, extract it to sites/all/modules, and enable the Devel module on your admin/build/modules page.

The devel module must be enabled.

Make sure to move the Development block to some active region on your page.

The block must be placed in some active region on the page, such as the Right sidebar.

Once you've landed on the contact page, click on the 'Enable Theme developer' link in your Development block.

The devel block should be visible to you now.

Now, enable the Themer info widget. The Themer info toggle checkbox sits on the bottom-left of your viewport. (Thought I should throw the fancy word "viewport" in there.)

The themer info toggle sits on the bottom-left of your viewport.

You want to click on the form, but you end up selecting one field or another within the form. Argh. Solution: click somewhere to the right of the Send e-mail button.

Select the contact form by clicking to the right of its submit button.

There's no specific theming function that's been registered to theme the contact form. How do you know that?

The function theme_form() is used to theme the form.

How do you know that theme_form() is used to theme the contact form? The Themer info widget tells you that. Take a look.

The all-purpose theme_form function is used to theme the contact form.

See it? Function called: theme_form().

You're not interested in overriding the theme_form() function. You want to theme the contact form. You do not want to theme all forms on Randy.com. You want to theme only that particular form. What will you do ?

First, eat something.

You will register a theming function for the contact form.

Modules and themes can both register theming functions. Modules and themes can both implement the function hook_theme.

Registering a theming function

To register a theming function for a form, you must know its Form ID.

There are at least two ways to find the Form ID.

  • Look at the <form> id attribute (using Firebug). That id happens to be the hyphenated version of your Form ID: <form action="/contact" accept-charset="UTF-8" method="post" id="contact-mail-page">. Hence, the Form ID, here, is contact_mail_page. Replace each hyphen of your id attribute by an underscore and you've got your form ID.
  • Look at some hidden input in the form markup with name "form_id". The value of that input is the Form ID: <input name="form_id" id="edit-contact-mail-page" value="contact_mail_page" type="hidden">

You take mental note of the Form ID. (You and I both have amazing storage capacities in our brains.)

The Form ID of the contact form.

Just for fun (and to learn a few things), you take a peek inside the contact module to make sure that it provides no theming function for the 'contact_mail_page' form. You're looking for the module's implementation of hook_theme(). In the modules/contact folder, you search for the string function contact_theme.

And you find nothing.

The module is registering no theming function. Most core modules register their share of theming functions. The contact module is quite 'exceptional' in that regard.

For the sake of learning something about HOOK_theme, you'll look at another module's implementation of the hook. Open the file modules/user/user.module and look at lines 30-78.

<?php
/**
* Implementation of hook_theme().
*/
function user_theme() {
  return array(
   
'user_picture' => array(
     
'arguments' => array('account' => NULL),
     
'template' => 'user-picture',
    ),
   
'user_profile' => array(
     
'arguments' => array('account' => NULL),
     
'template' => 'user-profile',
     
'file' => 'user.pages.inc',
    ),
   
'user_profile_category' => array(
     
'arguments' => array('element' => NULL),
     
'template' => 'user-profile-category',
     
'file' => 'user.pages.inc',
    ),
   
'user_profile_item' => array(
     
'arguments' => array('element' => NULL),
     
'template' => 'user-profile-item',
     
'file' => 'user.pages.inc',
    ),
   
'user_list' => array(
     
'arguments' => array('users' => NULL, 'title' => NULL),
    ),
   
'user_admin_perm' => array(
     
'arguments' => array('form' => NULL),
     
'file' => 'user.admin.inc',
    ),
   
'user_admin_new_role' => array(
     
'arguments' => array('form' => NULL),
     
'file' => 'user.admin.inc',
    ),
   
'user_admin_account' => array(
     
'arguments' => array('form' => NULL),
     
'file' => 'user.admin.inc',
    ),
   
'user_filter_form' => array(
     
'arguments' => array('form' => NULL),
     
'file' => 'user.admin.inc',
    ),
   
'user_filters' => array(
     
'arguments' => array('form' => NULL),
     
'file' => 'user.admin.inc',
    ),
   
'user_signature' => array(
     
'arguments' => array('signature' => NULL),
    ),
  );
}
?>

You make these fine observations:

  • When the module provides a theming function per se, a 'file' is specified, the file in which the function is defined — but the module does so only when the function is stored in a separate file, that is, not in user.module.
  • Whenever the module provides a *.tpl.php file, a 'template' is specified. The template name, as the convention goes for a form, is the hyphenated version of the Form ID. You take mental note of this.

In the hook_theme() function, the key to each sub-array is the internal name of the hook. And we mean hook in "themespeak" (theme parlance), not "modulespeak". For a form, the name of the hook is the Form ID. Each sub-array contains info about said hook, and that info is an associative array. Among the info, there's only one required item to provide, and that is the 'arguments'. Plural form.

So, now, you'll register a theming function for the contact_mail_page form. The contact module hasn't done so. So, you will.

Registering a theming function for a form

You open your theme's template.php file. Randy.com uses the Garland theme. (For the money he's paying you, he better not fuss.) Here's the code to register a theming function for the 'contact_mail_page' form:

<?php
/* Register some theme functions for forms, theme functions
* that have not been registered by the module that created
* these forms...
*/
function garland_theme(){
  return array(
   
'contact_mail_page' => array(
     
'arguments' => array('form' => NULL),
     
'template' => 'contact-mail-page',
    ),
  );
}
?>

You take good note of the following:

  • The hook_theme function always returns an array. It returns an array even when it registers only one single theming function.
  • The hook_theme function returns an associative array. In that array, the key(s) is(are) the hooks (in "themespeak") that need to be themed — and for a form, the hook is the Form ID.
  • The 'arguments' element (plural form, please!) is also an associative array, and it is an array even when it contains only one element. The key/value pair for that one element, in our case, is 'form' and NULL.
  • You could provide an 'arguments' element, and stop there. You could then use a function like garland_contact_mail_page($form) to theme the form. But if you prefer to use a *.tpl.php file to theme the form, you need to provide a 'template' name. The value of 'template' is the name of the file you intend on using — without the tpl.php extension. Note that the template name can be ANYTHING AT ALL, that is, 'anything-at-all', provided you create a file that's called anything-at-all.tpl.php. But to follow Drupal's coding conventions, you, my Drupal-worker friend, use the hyphenated version of the Form ID.

Providing a template file and its preprocess function

When you want to override a template provided by a module, the process is the same, always. You locate the template file and copy it to your theme folder. When you want to pass additional variables to the template, you define a preprocess function for the template in your theme. That second step, however, is optional. It's usually not needed.

In your case, the module contact has provided no default template. Heck, it has not even provided a theming function! You had to register one! So you must go through these two steps:

  • Create the template file out of thin air.
  • Define a preprocess function to pass along to the template file any variable that it needs; all of the variables that have not been passed along already through the 'arguments' defined above; all of the variables it needs except the ones passed along already; all of the variables it needs excluding those variables that are automatically made available to all template files, like $user and $logged_in. (For a list of what's available in ALL *.tpl.php file, head over here).

By the way, are you still using global $user; in your template files? Just use $user, it's a default baseline variable available in all *.tpl.php files. It's part of your free meal.

For each template file used to theme content in Drupal 6, there must exist a function to pass to it whatever variables are needed to output content. For each template file used to theme content in Drupal 6, there exists somewhere a preprocess function.

Let's move on.

Create a file called contact-mail-page.tpl.php in your theme folder. In it, place this markup:

<p>So you would like to contact us...</p>
<div class="submit-contact-form"><?php print $form_markup; ?></div>

Then, create the skeleton for the template preprocess function in your template.php file like so:

<?php
function garland_preprocess_contact_mail_page(&$vars) {
 
$vars['form_markup'] = drupal_render($vars['form']);
}
?>

The function garland_preprocess_contact_mail_page(), as defined above, creates a new variable and passes it along to the template file. That new variable is $form_markup, and it contains the markup for the form 'contact_mail_page'.

You know this already about $vars:

  • In $vars, the key $vars['form'] is set, as well as the keys for the default baseline variables available to all templates.
  • $vars['form'] is a complex nested array that contains our 'contact_mail_page' form.
  • $vars is passed to the preprocess function 'by reference'. This means you can add to it, edit it, do whatever you want to it, and your changes will 'keep'. The preprocess function is usually used to pass additional variables to the template file — by adding to $vars — but it can also be used to change the value of stuff that's being passed already. You'll use it that way.

You know this already about drupal_render():

  • The drupal_render() function is what's used by themes to whip a $form array into XHTML markup.
  • The drupal_render() function can render any part of a form, or the whole thing.
  • When used to render the entire form, drupal_render() will only render these parts of the form that have not been rendered yet. It can keep track of what has been rendered thus far, in other words.

Clear your Drupal cache. That will clear the Theme registry.

Using the devel block to clear the cache.

Does Drupal use my template?

After you've refreshed your page in your browser, you should see a 'So you would like to contact us...' greeting between the title of the page and the contact form itself. The top of the contact page should look like this:

A test to see if our new template file is used.

Satisfied and relieved, you remove the 'So you would...' paragraph from the template file.

A little planning

So you want to produce two 'fake' Drupal pages, each one displaying a different version of the contact form, a version tailored to suit the context of a quote request, and another one to suit the context of a general inquiry. You will create 2 files, one for each 'variation'. You'll name the first template file 'contact-mail-page-quote.tpl.php' and the second one 'contact-mail-page-info.tpl.php'. Make two copies of your contact-mail-page.tpl.php template, you'll work from it. Modify the names of these copies, and change their content.

You now have three 'extra' templates in your theme:

Three new template files in your theme folder.

Edit the content of contact-mail-page-quote.tpl.php to:

<p>You would like to request a quote...</p>
<div class="contact-for-quote"><?php print $form_markup; ?></div>

Edit the content of contact-mail-page-info.tpl.php to:

<p>You have an inquiry...</p>
<div class="contact-for-general-inquiry"><?php print $form_markup; ?></div>

Only contact-mail-page.tpl.php is 'seen', so far, by the theming engine. You'll change that.

Checking out my path

In the URI http://Randy.com/contact/quote, 'contact/quote' is $_GET['q']. Although it is a path that leads to nowhere, it is still something you can read. To read what's contained in the q value, you will use the Drupal function arg().This function breaks down the Drupal path into its components. Components of the path are separated by a forward-slash. For the URI http://Randy.com/contact/quote, arg(0) is the 1st component, ie: 'contact', and arg(1) is the 2nd component, ie: 'quote'. You will read the second component, and will suggest a template file based on it.

<?php
function garland_preprocess_contact_mail_page(&$vars) {
 
// If the visitor types contact/quote or contact/info
 
switch(arg(1)) {
    case
'quote' :
     
$vars['template_file'] = 'contact-mail-page-quote';
      break;
    case
'info' :
     
$vars['template_file'] = 'contact-mail-page-info';
  }
 
$vars['form_markup'] = drupal_render($vars['form']);
}
?>

You are suggesting one template file for each case by using $vars['template_file']. You assign to your 'suggestion' variable the name of the *.tpl.php file you plan on using minus the extension. Just like you did in your implementation of HOOK_theme when you told the theming engine to use 'contact-mail-page', which effectively points to the file contact-mail-page.tpl.php.

Now, you're thinking about how you want to render or display the contact form for each situation, the 'quote' situation and the 'info' one. In both situations, you do NOT want to show the drop down selection for categories. A category is picked based on the requested URI. The URI already informs us as to what category was chosen, in other words. So you'll hide that element in the form in both cases. For that you'll use CSS display:none. However, when the form is submitted, that information about the cid will be missing, so you must 'fill in' that form field behind the scenes, on behalf of the visitor. This is something that you can do in your theme.

The values you'll assign here to $vars['form']['cid']['#value'] are the Contact Hi-dee you had 'memorized' previously. So they may not be 1 and 2.

<?php
function garland_preprocess_contact_mail_page(&$vars) {
 
/* If the visitor types contact/quote or contact/info,
      otherwise the default template is used, ie: contact-mail-page */
 
switch(arg(1)) {
    case
'quote' :
     
$vars['form']['cid']['#value'] = 1;
     
$vars['form']['cid']['#prefix'] = '<div style="display:none;">';
     
$vars['form']['cid']['#suffix'] = '</div>';
     
$vars['template_file'] = 'contact-mail-page-quote';
      break;
    case
'info' :
     
$vars['form']['cid']['#value'] = 2;
     
$vars['form']['cid']['#prefix'] = '<div style="display:none;">';
     
$vars['form']['cid']['#suffix'] = '</div>';
     
$vars['template_file'] = 'contact-mail-page-info';
  }
 
$vars['form_markup'] = drupal_render($vars['form']);
}
?>

Clear your Drupal cache, to clear the Theme registry.

Using the devel block to clear the cache.

Then, head over to the 'contact/quote' page. What do you see? Test the 'contact/info' page as well.

Checking out the form

To troubleshoot any problems you may encounter while editing your form, you need to inspect it. The devel module provides a kit of 5 functions to inspect the content of variables:

Function To inspect content of Content shown Using a recursive function
dsm() or dpm() Any variable In a message Yes, perfect for all.
dvm() A complex variable, such as an object or array In a message No. Ugly print.
dpr() A complex variable, such as an object or array At the top of the page. Yes. Perfect for complex, ie: nested, objects and arrays.
dvr() Any variable At the top of a page. No. Ugly print.

To inspect complex nested arrays such as forms, you can use either dpr() or dpm()/dsm(). These functions pretty-print forms either at the top of the page, or in the 'message' area. dpm() and dsm() have the same behavior.

In the 6.x-1.8 version of the Devel modules, dsm and dpm print the content of variables at the top of the page. That's a bug. The m in dsm and dpm means 'message' — it uses the function drupal_set_message().

To make sure you set the value for cid properly in your theme preprocess function, you can check the content of the $vars['form']['cid'] field within your code, like so:

<?php
  $vars
['form']['cid']['#value'] = 2;
  ...
 
$vars['form']['cid']['#value'] = 1;
  ...
 
// Checking the content of the cid field
 
dsm($vars['form']['cid']);
  ...
?>

Changing field labels

You now want to modify the field labels in the contact form.

<?php
function garland_preprocess_contact_mail_page(&$vars) {
 
/* If the visitor types contact/quote or contact/info,
      otherwise the default template is used, ie: contact-mail-page */
 
switch(arg(1)) {
    case
'quote' :
     
$vars['form']['contact_information']['#value'] = t('We will get back to you with a quote within 48 hours.');
     
$vars['form']['message']['#title'] = t('What you need');
     
$vars['form']['subject']['#title'] = t('Name of your company');
     
$vars['form']['cid']['#value'] = 1;
     
$vars['form']['cid']['#prefix'] = '<div style="display:none;">';
     
$vars['form']['cid']['#suffix'] = '</div>';
     
$vars['template_file'] = 'contact-mail-page-quote';
      break;
    case
'info' :
     
$vars['form']['contact_information']['#value'] = t('Send us your question. A real person will get back to you very shortly.');
     
$vars['form']['message']['#title'] = t('Your question');
     
$vars['form']['cid']['#value'] = 2;
     
$vars['form']['cid']['#prefix'] = '<div style="display:none;">';
     
$vars['form']['cid']['#suffix'] = '</div>';
     
$vars['template_file'] = 'contact-mail-page-info';
  }
 
// dsm($vars['form']);
 
$vars['form_markup'] = drupal_render($vars['form']);
}
?>

Now head over to the 'contact/quote' page. (Also look at the other version of the contact form, at 'contact/info'.)

The contact form to request a quote.

Is using template files such a great idea..?

You ask yourself: Why in the hell did I create template files when all they do, essentially, is print a variable? They barely contain any HTML markup! All contact-mail-page-info.tpl.php contains, for example, is this:

<p>You have an inquiry...</p>
<div class="contact-for-general-inquiry"><?php print $form_markup; ?></div>

The paragraph that contains 'You have an inquiry...' can certainly be added to the form as a markup field. At the theme layer, one can still add additional fields to a form, even though they will not be validated, neither submitted. They will be added just for the 'show'.

You can also wrap the form within a div with a specific class name, using $vars['form']['#prefix'] and $vars['form']['#suffix']. That way, you can take care of supplying the form with a CSS class name of contact-for-general-inquiry.

So, you've changed your mind about all this. You delete the three template files. All three. (You heard that using a template is five times slower than using a theming function.)

Then, you open your template.php file. You remove from the garland_theme() function any mention of the template file 'contact-mail-page.tpl.php'. The function becomes:

<?php
function garland_theme(){
  return array(
   
'contact_mail_page' => array(
     
'arguments' => array('form' => NULL),
     
// 'template' => 'contact-mail-page',
   
),
  );
}
?>

Then, you go ahead and comment out the whole preprocess function. Preprocess functions are for template files only.

I repeat...

Preprocess functions are for template files only.

Next, you write your theming function. This consists in moving the code from the commented-out preprocess function to a new function you call garland_contact_mail_page($form). In that new function, you replace all mention of $vars['form'] with $form. A 'find and replace' tool will be quite useful here. What the theming function must do is return themed content. Hence, you delete the line of code which consisted in adding a variable to $vars, and place the following 'return' instruction in its place:

<?php
// returning the themed form
return drupal_render($form);
?>

Here's the code for the entire function:

<?php
function garland_contact_mail_page($form) {
 
/* If the visitor types contact/quote or contact/info,
      otherwise the default template is used, ie: contact-mail-page */
 
switch(arg(1)) {
    case
'quote' :
     
$form['intro']['#value'] = '<p>' . t('You would like to request a quote...') . '</p>';
     
$form['intro']['#weight'] = -40;
     
$form['contact_information']['#value'] = t('We will get back to you with a quote within 48 hours.');
     
$form['message']['#title'] = t('What you need');
     
$form['subject']['#title'] = t('Name of your company');
     
$form['cid']['#value'] = 1;
     
$form['cid']['#prefix'] = '<div style="display:none;">';
     
$form['cid']['#suffix'] = '</div>';
     
$form['#prefix'] = '<div class="contact-for-quote">';
     
$form['#suffix'] = '</div>';
      break;
    case
'info' :
     
$form['intro']['#value'] = '<p>' . t('You have an inquiry...') . '</p>';
     
$form['intro']['#weight'] = -40;
     
$form['contact_information']['#value'] = t('Send us your question. A real person will get back to you very shortly.');
     
$form['message']['#title'] = t('Your question');
     
$form['cid']['#value'] = 2;
     
$form['cid']['#prefix'] = '<div style="display:none;">';
     
$form['cid']['#suffix'] = '</div>';
     
$form['#prefix'] = '<div class="contact-for-general-inquiry">';
     
$form['#suffix'] = '</div>';
  }
 
// dsm($form);
 
return drupal_render($form);
}
?>

Even with a '#weight' of -40 applied to the added 'intro' markup field, it still sinks to the bottom of the form. You can use drupal_render() to make sure that the intro text always appears on top, like so:

<?php
function garland_contact_mail_page($form) {
 
/* If the visitor types contact/quote or contact/info,
      otherwise the default template is used, ie: contact-mail-page */
 
switch(arg(1)) {
    case
'quote' :
     
$form['intro']['#value'] = '<p>' . t('You would like to request a quote...') . '</p>';
     
$form['contact_information']['#value'] = t('We will get back to you with a quote within 48 hours.');
     
$form['message']['#title'] = t('What you need');
     
$form['subject']['#title'] = t('Name of your company');
     
$form['cid']['#value'] = 1;
     
$form['cid']['#prefix'] = '<div style="display:none;">';
     
$form['cid']['#suffix'] = '</div>';
     
$form['#prefix'] = '<div class="contact-for-quote">';
     
$form['#suffix'] = '</div>';
     
$output = drupal_render($form['intro']);
      break;
    case
'info' :
     
$form['intro']['#value'] = '<p>' . t('You have an inquiry...') . '</p>';
     
$form['contact_information']['#value'] = t('Send us your question. A real person will get back to you very shortly.');
     
$form['message']['#title'] = t('Your question');
     
$form['cid']['#value'] = 2;
     
$form['cid']['#prefix'] = '<div style="display:none;">';
     
$form['cid']['#suffix'] = '</div>';
     
$form['#prefix'] = '<div class="contact-for-general-inquiry">';
     
$form['#suffix'] = '</div>';
     
$output = drupal_render($form['intro']);
  } 
 
// dsm($form);
 
return $output . drupal_render($form);
}
?>

This is a contrived example of course. This is an exercise. You may wonder why in the hell you ought to add some 'intro' text field when the form already contains a 'contact_information' field. I am doing this just to show you how to add a field to a form.

To place text in a form is not exactly adding a field to it. But still, in the world of Drupal Form Theming, markup that just sits there to be read is a field in its own right. Strange, hein? Text that just sits there is even the default type for a form field in the Drupal form API. Hence, you need not specify a '#type' of 'markup' for the new $form['intro'] field. To be fair, this field (in Drupal form-speak) can consist of any markup.

Don't forget to clear the cache.

Now head over to your 'contact/quote' page.

The contact form to request a quote.

All you have left to accomplish now is go to admin/build/menu and add menu items that link to contact/quote and contact/info, and then add these menu items to a menu, e.g. your primary links. And you're done.

Randy is happy. He sends you two-thirds of the money he promised you, along with this photo of him. He says he's on the left.

Picture of Randy

[]

This tutorial was helpful to you? Post a comment and/or donate. Thank you.

Last edited by Caroline Schnapp about 12 years ago.

Comments

Worth Bookmarking

Sant Ritz has full and unique facilities, which includes a guard house, clubhouse, children's playground, swimming pool, Aerobic/Yoga room, piano room, pool room, indoor gym, hydrotherapy beds, hydrotherapy baths, reading room, function room, onsen, jacuzzi.

I am impressed

Twin Fountains EC has full and unique facilities, which includes a guard house, clubhouse, Function Room & Indoor Gym Tennis Court, 50m Freeform Pool Pool Deck, Wading Pool, Splash Pool & Family Pool Jacuzzi & Hydro Spa, BBQ Area Dining and Play Fountain, Fitness Alcove & Children’s Playground and Garden Trail.
Twin Fountains

The following exercise

The following exercise consists in theming the contact form in Drupal 6. Once we're done, it will look like we'll have created two fall-back-on 'pages' http://e-papierossy.com.pl/en/e-papierosy/94-e-papierosy-gambit-9812.html for contact forms, one page/form to 'request a quote' at Randy.com/contact/quote, and an other page/form for general inquiries at Randy.com/contact/info. http://e-papierossy.com.pl/en/e-papierosy/95-e-papierosy-gambit-5412.html The trick here — if there's one — consists in theming the contact form differently based on the requested URI.

excellent post

Belgravia Villas is a new and upcoming cluster housing located in the Ang Mo Kio area, nested right in the Ang Mo Kio landed area. It is within a short drive to Little India, Orchard and city area. With expected completion in mid 2016, it comprises of 118 units in total with 100 units of terrace and 18 units of Semi-D. Future residents are within a short driving distance to Ang Ko Kio Hub and Compass Point. With such a short drive to the city area as well as the orchard and bugis area, entertainment for your love ones and family will come at a stone’s throw away.
Belgravia Villas

excellent

great blog. hope to read more Hedges Park Condo, Topiary EC, Twin Fountains Woodlands

Ecopolitan EC is also near

Ecopolitan EC is also near elite schools such as Mee Toh School, Nan Chiau Primary School, Nan Chiau High School.
Ecopolitan EC

Future residents will be

Future residents will be able to access the development via Buangkok MRT which is just next to it. Also, nature awaits your family and friends at the nearby Punggol Park. Also, the ultimate nature awaits you at the Sengkang Riverside Park.
Jewel at Buangkok

Coral Edge Residences is a

Coral Edge Residences is a 99-years leasehold Punggol EC development located at Punggol Walk in District 19. With expected completion in mid 2016, it comprises of TBA towers with TBA units and stands TBA storeys tall. It is situated right beside Punggol MRT Station. Future residents will be able to access the nearby Compass Point and Rivervale Mall which is a short drive away for some family fun and gatherings.
A truly unique lifestyle awaits you.
Coral Edge Residences

The condo’s facilities

The condo’s facilities provide full family entertainment needs for your family and loved ones. Indulge in a serene and tranquil lifestyle right in the heart of Bugis.
Several buses are available near Rocher Road and Beach Road along with shopping centers and restaurants.
DUO Residences

It is a short drive away

It is a short drive away from Woodlands and Admiralty MRT Station. Future residents will be able to walk to the nearby Vista Point or a short drive to Causeway Point for some family fun and gatherings. A truly unique lifestyle awaits you.
Forestville EC

theming it

we should theme the contact forms and make it more interesting so ppl will fill it up. lush acres floor plans

Future residents will be

Future residents will be able to walk to the nearby Sun Plaza or a short drive to Causeway Point for some family fun and gatherings. A truly unique lifestyle awaits you at Skypark Residences.
Skypark Residences

The Inflora Condo is a new

The Inflora Condo is a new and upcoming Flora Road New Launch Condo located in Flora Road, within a short drive to Singapore Expo, Tampines Point, Century Square and IKEA. With expected completion in mid 2017, it comprises of TBA towers with TBA units and stands TBA storeys tall. The Inflora

Future residents will be

Future residents will be able to walk to the up and coming Tampines East MRT station from The Inflora Condo. Also, nature and recreation awaits your family and friends at the nearby Tampines Park. Also, the ultimate shopping and dining experience awaits you at the Singapore Expo as as well as Changi City Point which is just a short drive away. The Inflora

Rivertrees Residences will

Rivertrees Residences will be accessible with Layar LRT Station as well as Sengkang Bus Interchange. It is also right beside Tampines Expressway(TPE). Rivertrees Residences is also near to Greenwich V and the Upcoming Seletar Mall. Rivertrees Residences in Fernvale Sengkang

great

I just loved shopping there for all kinds of great books. I miss the Bodhi Tree just like all of it's fans. Hoping for a return one day of the might Bodhi Tree. Please come back and share your amazing books with us again. I've had issues with hackers and I'm looking at alternatives for another platform. I would be fantastic
if you could point me in the direction of a good platform obat tradisional penurun asam urat thank you