Tina MVC Contact Form Tutorial
This tutorial is based on code in the sample_apps/tina-mvc-for-wordpress folder. It builds upon the Tina MVC Install and Quick Start Tutorial, so if you haven’t read it, I urge you to do so now.
The objective is to introduce the form helper class and the use of view files.
Getting Started
We will place our page controller and view file in the apps folder, so it will be accessible from any Tina MVC front end page controller. You can place it in a sub folder of apps (for example apps/my-custom-front-end-page-controller in which case you will need a Tina MVC front end page controller called `my-custom-front-end-page-controller` in your tina_mvc_app_settings.php file.
The Page Controller
We want to access the contact form using the URL http://www.example.com/tina-mvc-for-wordpress/contact-us so the page controller is called contact_us_page.php.
Important: because this is a simple example and there are no special permissions required to view this page, we are putting all the code into the constructor. You should learn to use the dispatcher method – see the Tina MVC Dispatcher Method Tutorial for more information.
<?php class contact_us_page extends tina_mvc_base_page_class { /** * Note we are using a PHP5 constructor here. */ function __construct( $request ) { /** * Override the $role_to_view so anyone can access this page controller. */ $this->role_to_view = FALSE; /** * Call the parent constructor. This is where permissions checks are carried out. */ parent::__construct( $request ); /** * Create a new form object. */ $f = new tina_mvc_form_helper_class( 'contact-us' ); /** * Add a your_name field */ $f->add_field( 'your_name', 'text', FALSE, $db_table='default', $db_field=false, FALSE, $extraAttrib='' ); $_rules = array( 'required'=>NULL ); $f->add_validation_rules( 'your_name', $_rules ); /** * Add a your_email field */ $f->add_field( 'your_email', 'text', FALSE, $db_table='default', $db_field=false, FALSE, $extraAttrib='' ); $_rules = array( 'required'=>NULL, 'email'=>NULL ); $f->add_validation_rules('your_email', $_rules ); /** * Add a your_email_again field */ $f->add_field( 'your_email_again', 'text', FALSE, $db_table='not_needed', $db_field=false, FALSE, $extraAttrib='' ); $_rules = array( 'required'=>NULL, 'email'=>NULL, 'equaltofield'=>'your_email' ); $f->add_validation_rules('your_email_again', $_rules ); /** * Add a your_message field */ $f->add_field( 'your_message', 'textarea', FALSE, $db_table='default', $db_field=false, FALSE, $extraAttrib='' ); $_rules = array( 'required'=>NULL ); $f->add_validation_rules( 'your_message', $_rules ); /** * Add a reCaptcha field */ if( get_option('tina_mvc_recaptcha_pub_key') AND get_option('tina_mvc_recaptcha_pri_key') ) { $f->add_field( 'prove-you-are-human', 'recaptcha' ); } /** * Add a Submit button */ $f->add_field( 'submit-button', 'submit', '', 'not_needed', false, 'Send Message' ); /** * Add a Cancel button */ $f->add_field( 'cancel-button', 'submit', '', 'not_needed', false, 'Clear Form' ); /** * Check if the cancel-button was submitted and redirect */ if( $f->get_posted_field_value('cancel-button') ) { wp_redirect( $_SERVER['REQUEST_URI'] ); exit(); } /** * Build the form, checking for POSTed values and for validation errors */ $f->build_form(); /** * Look for table data. FALSE if not POSTed or validation errors. Default table is 'NONE' */ if( $tbl = $f->get_table_data( 'default' ) ) { /** * Grab the POSTed variables for emailing. */ $form_data['subject'] = 'Contact Us form submission'; $form_data['body'] = print_r( $tbl, 1 ); /** * Send an email */ tina_mvc_mail( 'tina-mvc-for-wordpress@mailinator.com' , 'blank' , $form_data ); } /** * Initialise a variable for view data. Array, object, you decide. */ $view_data = new stdClass; /** * Grab the HTML for the form. Includes any validation messages. */ $view_data->the_form = $f->get_form_html(); /** * Any POSTed data? */ if( isset($form_data) ) { /** * Use the tina helper function to make sure any data we send to the view file is escaped. */ $view_data->form_data = tina_mvc_esc_html_recursive( print_r($form_data, 1) ); } else { $view_data->form_data = FALSE; } /** * Trivial example, but escaping is a good habit to get into */ $post_title = tina_mvc_esc_html_recursive( 'Contact Us' ); /** * Load the view file, and pass view data to it */ $post_content = $this->load_view( 'contact_us', $view_data ); /** * Finally assign the title and content and we are done. */ $this->set_post_title( $post_title ); $this->set_post_content( $post_content ); } } ?>
Let’s have a look at what is going on. I refer to the comments in the above code
Override the $role_to_view so anyone can access this page controller
Tina page controllers have default permissions set according to the value of $tina_mvc_default_role_to_view in the tina_mvc_app_settings.php or tina_mvc_app_settings_sample.php file. In this case we want to be sure visitors can view our contact form.
You must always do this before calling the parent constructor. That is where the permissions checks take place.
Create a new form object
You must at least provide a unique name for the form. This is used to construct unique field names in case you have two forms on one Wordpress page. Usage:
$f = new tina_mvc_form_helper_class( $formname, $checkGet=false, $doXML=false, $formaction=FALSE )
- $formname: a unique name for the form (required)
- $checkGet: do we check $_GET for posted values? (default: FALSE)
- $doXML: use XML self closing tags (<br />) (default: FALSE)
- $formaction: where to submit the form. (default: the same page the form appears on)
When you create the form object, two hidden fields are automatically added to the form:
- a Wordpress nonce field. See http://codex.wordpress.org/Function_Reference/wp_nonce_field
- a hidden field to detect if the form was POSTed
Add a your_name field
Usage:
$f->add_field( $field_name=false, $field_type='', $field_caption=false, $db_table='NONE', $db_field=false, $default=false, $extra_html_attributes='' )
- $field_name: a unique name for the field. The HTML label, id and name are constructed from this. (required)
- $field_type: see the tina_mvc_form_helper_class->valid_field_types class property in tina_mvc/tina_mvc_form_helper_class.php (required)
- $field_caption: Specify text for form field’s label (default is constructed from $field_name)
- $db_table: a table name. Use this to group fields (default ‘NONE’) so you can retrieve them in groups with the get_table_data() method
- $db_field: the database field name, if different from the $field_name.
- $default: a default value to use (overridden by $_POST and $_GET variables)
- $extra_html_attributes: added to the INPUT element. Use this for in-line styles, javascript, whatever.
Validation rules are added next. It is easiest to construct an array of rules and then assign them in one go (as we have done here.) You can also add rules individually using the add_validation_rule($fname,$rule,$args) method.
Validation rules are listed in the $valid_validation_rules class property. Many (like the `REQUIRED` rule require) no parameters, but some do. To add multiple validation rules at one, we construct an array of required rules. See the `your_email_again` for a good example of how this works. In that case 3 rules are added in one go, and one of them (the `EQUALTOFIELD` rule) requires a parameter.
The validation rules are run against any default and POSTed values when you access the build_form() class method.
Add a Submit button / Add a Cancel button / Check if the cancel-button was submitted and redirect
All buttons added by the form helper are of type SUBMIT. Therefore whenever a button is pressed the form is submitted.
The get_posted_field_value( $field_name ) class method is used to check which SUBMIT button was pressed. It checks:
- if the form has been POSTed
- if the $field_name INPUT was POSTed.
Build the form, checking for POSTed values and for validation errors
This is where the bulk of the heavy lifting is done. This method will:
- check if the form has been posted and load any POSTed (or GETed) variables
- run check validation rules against field values and add validation errors if necessary. Also sets the class property
$validation_errors - generate the HTML for the form
If there are no validation errors your table data is available using the get_table_data($table_name) method.
The form HTML is always available using get_form_html() – even if there were NO validation errors.
Look for table data. FALSE if not POSTed or validation errors. Default table is ‘NONE’
You can group data together when you use the add_field() method by passing the $db_table parameter. If you do not, then all field data will be assigned to a table called `NONE`. The get_table_data() method uses that table name by default.
In this case we have used two table names, `default` (which contains the field values we want) and `not_needed` (which includes redundant field values required for processing the form) to illustrate the use of table names with add_field() and get_table_data().
Send an email
Uses the Tina MVC helper function to send an email. This wraps around the Wordpress wp_mail() function:
Usage:
tina_mvc_mail($to, $message_template=FALSE, $message_variables=FALSE )
- $to: The recipients address
- $message_template Template to use (looks in `
app_emails` and then `emails` folder) - $message_variables: Data to be merged into the message. The it is in the global scope when the message template is included by PHP
In this case we are using the `blank` email template. This is shipped with Tina and allows you to quickly (and dirtily) send emails. It expects the $message_variables to be an array, and it requires the array keys `subject` and `body` to be defined.
This function is likely to change in the future as it is pretty quick and dirty now.
Initialise a variable for view data. Array, object, you decide.
You can also send a string, but that would be a trivial example. This variable is available as $V within the scope of your view file.
Grab the HTML for the form. Includes any validation messages.
You will note that this is NOT escaped.
Use the tina helper function to make sure any data we send to the view file is escaped.
Another helper function, this will recursively escape data destined for the visitors browser. This is particularly important whenever you are sending user submitted data to a browser.
Load the view file, and pass view data to it
Usage:
load_view($view=false, $V=false)
This function include and parses a HTML/PHP file and returns a string.
The view file is autoloaded in the same way as the page controllers – first from the `app` or `tina_mvc` folders. It must be named {$view}_view.php.
It is a good idea to base your view file name on the name of your page controller. In this case the view file is called `contact_us_view.php`.
$V is a variable of data you want to pass to the view file. It is usually an array of an object.
The View File
View files are autoloaded in the same way as page controllers. Tina MVC will look for them in the same locations as for page controllers.
Create the file contact_us_view.php as follows:
<?php /** * You should include this check in every view file you write. The constant is defined in * tina_mvc_base_page->load_view() */ if( ! defined('TINA_MVC_LOAD_VIEW') ) exit(); ?> <h3>Fill in all fields to get in touch with us.</h3> <?= $V->the_form ?> <?php if( !empty($V->form_data) ): ?> <h3>Your form was sent. Thank you.</h3> <p>Here is what you posted:</p> <?= $V->form_data ?> <?php endif; ?>
You should include this check in every view file you write.
The constant `TINA_MVC_LOAD_VIEW` is defined in the load_view() method, so use it. It prevents visitors from loading a template file directly from your `wp-content/plugins/tina-mvc/app/` folder.
This is a pretty trivial example of a view file, but if you are used to using Smarty, or similar templating libraries, the principles are familiar to you.
Any variables you pass to the view file (via the load_view() method) are available in your view in the local scope, allowing the use of <?= $V->whatever ?> (or <php? echo $V->whatever; ?>) and <?= $V['array'][0] ?> (or <?php echo $V['array'][0]; ?>) template constructs.
You can use any mixed HTML/PHP templating constructs such as:
<? foreach($array as $element): ?> (do something) <? endforeach; ?>
{$view}_view.php is intended to be a HTML file with embedded PHP.
Note, I am using shorthand PHP tags, which violates the Wordpress coding standards. If you are writing a view file for general usage by other Wordpress users, you should use full <?php and ?> tags.
Further Reading
The source code for Tina MVC is well commented and there are other files in the sample_apps folder. In particular you should look at the `tina-mvc/sample_apps/tina-mvc-for-wordpress/test_form_page.php` which gives a more complex example of the use of the forms helper.
For another example of Tina view files in use, look at `tina-mvc/sample_apps/tina/example_mvc_page.php` and `tina-mvc/sample_apps/tina/example_mvc_view.php`.
Enjoy,
Fran.