Hands on plugin writing: Notify by mail

Well after writing a couple of plugins for Nucleus I thought it would be a good idea to write a hands on. Yesterday (24 january 2003) I started with the plugin Notify by email. This document will describe first the design process of the plugin, and later on how to code this in PHP. Basic knowledge can be found in the plugins documentation by WouterDemuynck

Notify by email: the design

First things first, when you want to write a plugin for nucleus a good design will help you through the process. In fact it's not possible to write good code without a good design, the other way around is unfortunately not always the case. It is possible to write bad code with a good design. So we start to identify which tasks should be performed by this plugin:

  • Display a form where people can leave their email address and a button
  • After (un)subscribing, add the email address to the database or remove it.
  • After adding an item to the blog send an update email to subscribers

That is what the plugin should do, but the design isn't finished yet. As you will notice while writing the code, there will always be issues that need to be resolved. With these rough guidelines I started writing.

Setup

You'll need your code to be a nucleus plugin, and all plugins start with the same code:

(php)
<?
class NP_<pluginname> extends NucleusPlugin {

The form

Well, this was the first part that needed writing, the form. This form should be displayed somewhere on the site so this will be a function that should be called from the skin. Lets create a function doSkinVar. This function will be performed on the moment when your skin will have <%PluginName()%>.

(php)
function doSkinVar($skinType) {
        $this->doForm($ButtonCaption);
} 

I've left this simple, and created a new function that will handle the html for me. But I realised this wasn't enough, because I would like to give users the ability to edit an optional label and the button caption. I choose to add these two as options for the plugin. This would need two changes, first I would have to write an Install function which would take care of the creation of these options, and I would have to get their values when needed. So the function ended up like this:

(php)
function doSkinVar($skinType) {
	global $manager, $blog, $CONF, $DIR_PLUGINS;
	$ButtonCaption = $this->getOption('SubscribeButtonText');
	$Label = this->getOption('Formlabel');
	$this->doForm($ButtonCaption);
} 
Installation (1)

And the install function looked like this

(php)
function install() {
	$this->createOption('SubscribeButtonText','The caption on the button (label)','text','[Un-] Subscribe');
	$this->createOption('Formlabel','The label displayed on the form','text','Subscribe for updates');
}

Well, what is inside this doForm function? Because this will display the form on your page and will call the action.php when submitted. Here is the code:

(php)
function doForm($Label) {
	global $CONF;
	echo '<div class=\"NotifyMe\">\n'
	. '<form name=\"notifyme\" method=\"POST\" action=\"action.php\">\n'
	. '<input type=\"hidden\" name=\"action\" value=\"plugin\" />\n'
	. '<input type=\"hidden\" name=\"name\" value=\"NotifyMe\" /> \n'
	. '<input type=\"hidden\" name=\"type\" value=\"subscribe\" /> \n'
	. '<input type=\"text\" id=\"xp\" name=\"emailaddress\" width=\"40\">\n'
	. '<input type=\"hidden\" name=\"indexurl\" value=\"' .$CONF['Self'] . '\">'
	. '<input type=\"submit\" value=\"Label\">'
	. '</form> <!-- notifyme -->\n'
	. '</div>\n';
}

Well as promissed, mostly html. Adding the hidden fields action, name and type takes care of what action.php will do when the form is submitted. action will always need a value of plugin, the field name will contain the name of the plugin you are creating in this case NotifyMe.

Well that part is taken care of, and now we are able to show a subscribe form on our website, the next step is to handle the submission of the form. We've already established that action.php will handle the submit. And this will call our plugin again. Isn't that sweet.

Handling the submission (action.php and doAction)

Now it's time to consider what we will to with the addresses that get submitted by users. Of course, we will store them in the database. So we need a table that hold the addresses. We will add the following line to the install function so our table get's created with the installation of the plugin.

(php) sql_query('CREATE TABLE IF NOT EXISTS nucleus_plugin_notifyaddress (email varchar(100) not null, PRIMARY KEY (email))'); 

Now we'll focus on the function doAction that will get called by action.php. Let's look at it.

(php)
function doAction($type) {
	global $CONF;
	$email = requestVar('emailaddress');
	$pluginquery = "SELECT email FROM nucleus_plugin_notifyaddress WHERE email = '" .$email. "'";
	$check = mysql_query($pluginquery); 
	if (mysql_num_rows($check) ""=="" 0) {
		$ok = isValidMailAddress($email);
		if ($ok) {
			$actionquery = "INSERT INTO nucleus_plugin_notifyaddress (email) VALUES ('" . $email . "')";
			$type = "subscribe";
		} else {return ("This is not a valid email address!");}
	}
	else {
		$actionquery = "DELETE FROM nucleus_plugin_notifyaddress WHERE email = '" .$email . "'";
		$type = "unsubscribe";
	}
	switch ($type) {
		case "subscribe":
			mysql_query($actionquery);
			break;
		case "unsubscribe":
			mysql_query($actionquery);
			break;
	}
	global $HTTP_REFERER;
	header('Location: ' . $HTTP_REFERER);
}

So this function will check the database and looks to see if this “emailaddress” was already submitted. If not, we will add the address to the list, if we find a match we will remove the user. When we've done that, we will go back to the original page. Maybe later I will add some more fancy things here like a 'thank you' or sadly we see you go message… But this is not essential for the plugin to work.

Now let's try to achieve our third goal: sending the email message. This should be done after an item is added to the blogNucleus knows an event called PostAddItem, which is called after an item is added to the blog. This is exactly what we need, so we will let our plugin subscribe to this event. When this event is called by nucleus, our plugin will be notified and a special function called event_PostAddItem will get called by nucleus. So first let's subscribe.

function getEventList() {
	return array('PostAddItem');
}

And also write the function that will handle the sending of the emails

function event_PostAddItem($data) {
	global $manager, $CONF;
	""// if this event occurs, send an email to all subscribers""
	""// See if the plugin is enabled !""
	$on = $this->getOption('SendEnabled');
	if ($on ""=="" "yes") {
		echo "<h3>Sending subscribers an email</h3>";
		""// get a handle to notify object, use nucleus functions where possible !""
		""// add all email adress to a semicolon seperated list .. ""
		$emailquery = "SELECT email FROM nucleus_plugin_notifyaddress";
		$address = mysql_query($emailquery);
		$list = '';
		while ($row = mysql_fetch_object($address)){
			$list .= ";" .$row->email;
		}
		echo "<h4>".substr($list,1)."</h4>";
		$itemid = $data['itemid'];
		$item =& $manager->getItem($itemid, 0, 0);
		$notify = new NOTIFICATION($list);
		$title = stripslashes($item['title']);
		$body  = stripslashes($item['body']);
		""// a little hack to get a working permanent URL for the item""
		$url = createItemLink($itemid);
		$body .= "\n\nURL: ".$url;
		$notify->notify($title, $body, "todo@xiffy.nl");
	}
} 

With this function we do basically the same as what nucleus does when the 'notify on new item' mail is sent out. So we make a text message containing the title, body and more text from the item and create a permalink to the item. We feed the notify class of nucleus with this email message and the list of subscribed users. (In the next version this list will be put in the BCC field of the message, we should be careful with this valuable data!)

At this point we have achieved our initial design goals.

We have a form that can be called from within our skin which show a simple form where users can leave your emailaddress.
We handle the submission of this emailaddress by subscribing or unsubscribing them from our update mail
We send out a notification email when a new [[item]] is added. 

But this is not finegrained. An author should have the ability to check or uncheck the sendnotification when adding a new item. Well version 2 of nucleus comes with some extra plugin events which we can use to do just that! The AddItemFormExtras event gives us the ability to add one or more fields to the 'Add item' form. Nice! First we let our plugin subscribe to this event.

function getEventList() {
	return array('PostAddItem','AddItemFormExtras');
}

And write the function that will add our checkbox to the 'add item form'.

function event_AddItemFormExtras($data) {
	$on = $this->getOption('[[SendEnabled]]');
	?>
		<h3>Send notification to subscribers</h3>
		<p>
			<label for="plug_send_email">Send notifiction:</label>
			<input type="checkbox" <? if ($on == "yes") { echo "Checked";} ?> id="plug_send_email" name="send_email" />
		</p>
	<?
}

to be continued Famous last words. Here's the soo unexpected but intriguing part II While I was doing my daytime job, I thought this plugin was over. It wasn't what I was looking for. Maybe somebody was wanting this thing, but the better part of me thought this concept was rubbish. Not as finegrained and intuitive as somebody who is really publishing a weekly magazine could use. So it needed some good refinements.

Sending messages should not occur along a simple true false setting site wide!
You should have a collect batch mode, and when you think it's time to send the message, it should recollect the messages marked as 'include in mailinglist' and publish them. Message should either be sent as an email or as an rss-message which could be converted to an html file. The old message should be renamed by a date(//userparamsetting//) -php datevariable ... yet to be decided/designed!

This way you can create a weekly / monthly magazine and post messages any time you want, people would get your magazine the way you want it to look in the mailbox, and you can have your archive already online. You could staticly index your site with the collected rss messages/files it creates as well. :-) After indulging with these thoughts So i've decided to write the notifybymail plugin the way it was intended. This means work is almost done for this baby … The thoughts in the intrigiung part II will be in the complete new plugin NP_Magazine. Why not use nucleus to publish something that updates weekly, or monthly? (Or by fortnight).. So that is what I will do …

:: Plugins ::

notifymail.txt · Last modified: 2006/07/05 13:03 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki