0

Creating your first LemonStand Widget

Posted August 22nd, 2012 (Updated 1 Sep 2012) in Lemonstand

Creating custom widgets with the Widgets module for Lemonstand is a quick and painless process. Below, I’ll describe how to build a widget for Lemonstands Contact module. I’ll call this module Simple Contact Widget.

Download the completed module from my GitHub repo.

While this tutorial will go over everything you need to do to build a complete and working module, it would be very beneficial to also know the basics of module development, naming conventions and so on. Take a look at the documentation Developing LemonStand Modules if you haven’t already done so.

Step 1: Create a new module

First thing to do is create a basic module skeleton. I’m using the prefix flynsarmycontactwidget for this module. Create the following folders and files in your /modules directory:

Skeleton for Simple Contact Widget module

Skeleton for Simple Contact Widget module

There are two boilerplate files that need to be filled in. Firstly, /classes/flynsarmycontactwidget_module.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
 
	class FlynsarmyContactWidget_Module extends Core_ModuleBase
	{
		/**
		 * Creates the module information object
		 * @return Core_ModuleInfo
		 */
		protected function createModuleInfo()
		{
			return new Core_ModuleInfo(
				"Simple Contact Widget",
				"Provides a widget for LemonStands Contact module",
				"Flynsarmy" );
		}
	}
?>

and /updates/version.dat:

#1 Module initialization

This should be enough to get the module installing. Log out and back into the admin area and you should now see it under System – Modules & Updates.

 

Step 2: Add the Widget Code

We have an empty module. Now we need to make it provide a widget.

Each widget has a class that determines how it will load, save and render (on front and backend). The name of the class doesn’t matter, however following a consistent naming scheme is advised. I’m naming mine FlynsarmyContactWidget_Widget_SimpleContact and placing it in the file /classes/flynsarmycontactwidget_widget_simplecontact.php. This class commonly has the following methods:

  • before_save(): Validates widget settings, moves settings from POST into the widget settings array for later processing by the save() method (which you probably won’t need to worry about)
  • render_backend(): Determines how the backend customisation settings will look. The easiest way to handle this is to create a model and render it. Details on how to do that below.
  • render_frontend($options = array()): Determines how the widget will look on the frontend. Accepts an optional array of settings that can be used to override the current widget settings.

The only other common piece you’ll see in a widget is the optional $settings array. This can be used to provide default settings for your widget.

Let’s get started. Here’s the code for the widget class  (/classes/flynsarmycontactwidget_widget_simplecontact.php):

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
42
43
44
45
<?php
	class FlynsarmyContactWidget_Widget_SimpleContact extends FlynsarmyWidgets_WidgetBase
	{
		/*
		 * The settings array isn't required, but it can be used for default settings for options
		 */
		public $settings = array(
			'show_phone' => false,
			'redirect_url' => '',
			'success_message' => 'Thank you! We will get back to you shortly.',
		);
 
		/*
		 * Move any fields I want to save into $this->settings. Also a good place to do validation
		 */
		public function update( $context = null )
		{
			if ( !post_array_item('FlynsarmyContactWidget_SimpleContactWidget', 'redirect_url') )
				throw new Phpr_ApplicationException('You must enter a redirect URL.');
 
			$this->settings = array_merge(
				$this->settings,
				post('FlynsarmyContactWidget_SimpleContactWidget')
			);
		}
 
		public function render_backend()
		{
			echo '<div class="form600">';
			$model = new FlynsarmyContactWidget_SimpleContactWidget();
			$model->define_form_fields();
			$model->fill_external($this->settings);
			FlynsarmyWidgets_ModelHelper::render_model( $model );
			echo '</div>';
		}
 
		public function render_frontend($options = array())
		{
			FlynsarmyWidgets_RenderHelper::render_file(
				dirname(__FILE__).'/../partials/widgets/frontend/simplecontact.php',
				$this->settings
			);
		}
	}
?>

Our widget needs to be registered to become available in the widget list so open /init/init.php and add the following:

1
2
3
4
5
6
7
8
<?php
	if ( class_exists('FlynsarmyWidgets') )
		FlynsarmyWidgets::register_widget(array(
			'name' => 'Simple Contact Form',
			'description' => "Provides a simple contact form. Requires LemonStands 'Contact' module",
			'class' => 'FlynsarmyContactWidget_Widget_SimpleContact',
		));
?>

With this file in place you should now see your widget in the Add Widget list:

Add Widget

Simple Contact Form is now visible in the widget list

Backend UI

We want to provide a backend UI for customisation options for the administrator. The limited contact module doesn’t provide us many opportunities, but we can decide whether or not to show the phone field, as well as the redirection URL and message.

Take a look at the render_backend() method above. Outside of the styling div I’m rendering a model FlynsarmyContactWidget_SimpleContactWidget. You’re able to output any HTML you like here however rendering a model form keeps the look and field of your widget consistent with the rest of LemonStand and provides a bunch of functionality for free.

Here’s the code for the FlynsarmyContactWidget_SimpleContactWidget model (/models/flynsarmycontactwidget_simplecontactwidget.php).

1
2
3
4
5
6
7
8
9
10
11
<?
 
	class FlynsarmyContactWidget_SimpleContactWidget extends Core_Configuration_Model
	{
		protected function build_form()
		{
			$this->add_field('show_phone', 'Show Phone field?', 'full', db_bool);
			$this->add_field('success_message', 'Success Message', 'full', db_varchar)->comment("A message to display on successful submit.");
			$this->add_field('redirect_url', 'Redirection URL', 'full', db_varchar)->comment("Redirect to given URL on submit. eg http://yoursite.com/contact/success")->validation()->required();
		}
	}

Very simple stuff – I’ve added a checkbox and two text fields. This should render a model form looking like this (Title field is automatically added for you but not as a required field):

Contact widget model form

How the backend settings UI will look

Notice the default Success message value is present thanks to the $settings array added in the widget class. You should now be able to update the settings at will. Try leaving a blank redirection URL and see the validation at work.

Frontend UI

The frontend UI is generated with the render_frontend() method of the widget class. We’re loading the file partials/widgets/frontend/simplecontact.php (as specified in the widget class) so open that up and add the following:

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
<?
	/*
	 * Initially taken from http://lemonstand.com/marketplace/module/contact/
	 * A few modifications to make the UI more friendly and support our widget options
	 */
 
	$name = post('name', '');
	$email = post('email', '');
	$message = post('message', '');
	$phone = post('phone', 'Phone');
?>
<?= open_form(array('onsubmit' => "return $(this).sendRequest('contact:on_submit')")) ?>
	<?= flash_message() ?>
 
	<?php if ( !empty($redirect_url) ): ?>
		<input type="hidden" name="redirect" value="<?= $redirect_url ?>" />
	<?php endif; ?>
	<input type="hidden" name="flash" value="<?= h($success_message) ?>" />
 
	<ul>
		<li>
			<input type="text" name="name" value="<?= $name ?>" placeholder="Your name" />
		</li>
		<li>
			<input type="text" name="email" value="<?= $email ?>" placeholder="[email protected]" />
		</li>
		<?php if ( $show_phone ): ?>
			<li>
				<input type="text" name="phone" value="<?= $phone ?>" placeholder="Your mobile number" />
			</li>
		<?php endif; ?>
		<li>
			<textarea name="message" cols="32" rows="12" placeholder="Enter your message here"><?= $message ?></textarea>
		</li>
	</ul>
 
	<input type="submit" value="Submit" />
<?= close_form() ?>

How you want the frontend UI to look is completely up to you; I took mine from the contact module page and added a few tweaks.

Notice the use of $redirect_url$success_message and $show_phone variables. Those are the settings made available by the model we created earlier.

 

Conclusion

Widgets only consist of two main files – the widget class and a model for rendering the backend settings modal. They can provide alot of functionality and customisability with very little effort and allow developers to rapidly add features to a site.

If you write your own widgets I’d highly recommend submitting them to the Lemonstand marketplace – the more widgets available to everyone, the easier all our jobs become!