Watu PRO Version 1.1

Posted by admin on May 9th, 2012

Of course we listed to feedback and I hear you. So here’s the first upgrade to WatuPRO:

1. The questions are now numbered and you’ll see “Question 2 of 15″ etc so you know better how much is left to take the exam.

2. You can configure what to display when every exam is taken – the result text only or to include the questions along with the answers and marks for correct/incorrect one.

3. Logged in users can continue taking the exam even if closing the browser, on another day, or even year. This feature is disabled for time-limited exams to avoid cheating.

Old customers bought WatuPRO this year are eligible for free upgrade. Please just mail me and let me know to send you the zip. Please do read this before upgrading.

3 Smart PHP-Generated Drop Down Menus (Tutorial)

Posted by admin on April 5th, 2012

In our software we often use drop-down menus. To make things easier I have coded functions for the most commonly used ones – date drop down, drop down to list database entries, and drop down to be populated from simple non numerated PHP array. All these drop downs are for example used in our autoresponder software. They just generate HTML code which is then output in your HTML forms.

Just recently I decided to encapsulate them in a class and share with the community. So if you are lazy to read, go right to the code at PHP Classes. The class is called QuickDD.

For the more curious people who want to learn, here is this tutorial explaining the stuff.

The Class

Using class isn’t that important in our case because there is almost no shared data between the 3 drop down generating functions (except the errors array). But we’ll create a class so we can keep it encapsulated at least:

class QuickDD
{
    // this variable will be filled with errors.
    // You can print it out with print_r so you can see errors
    public static $errors=array();

    // used by the date drop down. Feel free to change start/end year
    public static $start_year=1900;
    public static $end_year=2100;

You can very well just use three procedural functions. But from now on, let’s stick with the OO example.

The Date Drop-Down

This is the most complex one. I know there are many cool scripts like jQuery calendar but sometimes they are a bit painful to work with. Simple drop-down date selection is easy to understand, works in all browser, and takes no javascript to implement. So, let’s build one:

    // Outputs date drop down for selecting month, day, year
    // Arguments:
    // @param $name - string, the base name of the "select" form tag.
    // Quick DD will add suffix to each of the 3 tags:
    // "year" for year, "month" for month, and "day" for day
    // @param $date - string in MySQL format, optional pre-selected date
    // @param $format - string in the type YYYY-MM-DD showing how to output the
    // drop-downs. If $format has anything insane (like 5 Y or single-digit month)
    // we'll quietly switch to something sane instead of raising exception.
    // but we may log an error
    // @param $markup - if presented it should contain any markups that will be added
    // to each dropdown, in the same order that the parts are displayed.

And the function starts this way:

static function date($name, $date=NULL, $format=NULL, $markup=NULL)
    {

It’s static because we wan to call it anywhere without creating object. When you just want to encapsulate methods in a class for organization reasons, and there is no class instance data, it’s better to use static methods.

At the beginning of the function we want to make sure the params passed are so-so sane:

        // normalize params
        if(empty($date) or !preg_match("/\d\d\d\d\-\d\d-\d\d/",$date)) $date=date("Y-m-d");
        if(empty($format)) $format="YYYY-MM-DD";
        if(empty($markup)) $markup=array();

Now let’s explode the optionally passed pre-selected date, and start to buffer the output of the method:

$parts=explode("-",$date);
$html="";

// read the format
$format_parts=explode("-",$format);

And in $format_parts now we have the format as requested when calling the method. Now the most important part starts:

        // let's output
        foreach($format_parts as $cnt=>$f)
        {
            if(preg_match("/[^YMD]/",$f))
            {
                self::$errors[]="Unrecognized format part: '$f'. Skipped.";
                continue;
            }

As you see we go through each parts of the format string and check whether it contains anything else than the allowed symbols Y, M, and D. If yes, we add to errors array and skip that part. Errors array can be output with print_r when you use the method to see whether there are errors (this will become more clear in the usage example that will come after the code.

Now let’s add the year drop-down:

            // year
            if(strstr($f,"Y"))
            {
                $extra_html="";
                if(isset($markup[$cnt]) and !empty($markup[$cnt])) $extra_html=" ".$markup[$cnt];
                $html.=" <select name=\"".$name."year\"".$extra_html.">\n";

                for($i=self::$start_year;$i<=self::$end_year;$i++)
                {
                    $selected="";
                    if(!empty($parts[0]) and $parts[0]==$i) $selected=" selected";

                    $val=$i;
                    // in case only two digits are passed we have to strip $val for displaying
                    // it's either 4 or 2, everything else is ignored
                    if(strlen($f)<=2) $val=substr($val,2);        

                    $html.="<option value='$i'".$selected.">$val</option>\n";
                }

                $html.="</select>";
            }

Few things to note: $extra_html is populated by the element of the $markup argument which corresponds to the position of where YYYY (or YY) is in the format. So if you pass format like "DD-MM-YY" the third element of the array argument $markup will be used. If empty, nothing is used.

Then see how we prepend "year" to the $name argument to create the name of the drop-down. So each drop-down has its own name. For example if you call the method with $name equal to "date" your 3 drop downs will have names "dateyear", "datemonth", and "dateday" and can be accessed in $_POST or $_GET with these names.

Next we go through start and end year in a loop and output the option tags. In case $date argument is passed, the $parts value will contain year in $parts[0] (Because $date argument should always be passed in the MySQL YYYY-MM-DD format). So we check if such value is passed and when it matches $i we set the var $selected so the option tag can have selected attribute.

Finally see how we check if the format should be YYYY or YY and substring the output to meet that.

Then comes month drop down which is nearly the same:

            // month
            if(strstr($f,"M"))
            {
                $extra_html="";
                if(isset($markup[$cnt]) and !empty($markup[$cnt])) $extra_html=" ".$markup[$cnt];
                $html.=" <select name=\"".$name."month\"".$extra_html.">\n";

                for($i=1;$i<=12;$i++)
                {
                    $selected="";
                    if(!empty($parts[1]) and intval($parts[1])==$i) $selected=" selected";

                    $val=sprintf("%02d",$i);

                    $html.="<option value='$val'".$selected.">$val</option>\n";
                }

                $html.="</select>";
            }

The thing to notice here is the usage of sprintf which makes sure leading zero is always shown.

And now, day:

          // day - we simply display 1-31 here, no extra intelligence depending on month
            if(strstr($f,"D"))
            {
                $extra_html="";
                if(isset($markup[$cnt]) and !empty($markup[$cnt])) $extra_html=" ".$markup[$cnt];
                $html.=" <select name=\"".$name."day\"".$extra_html.">\n";

                for($i=1;$i<=31;$i++)
                {
                    $selected="";
                    if(!empty($parts[2]) and intval($parts[2])==$i) $selected=" selected";

                    if(strlen($f)>1) $val=sprintf("%02d",$i);
                    else $val=$i;

                    $html.="<option value='$val'".$selected.">$val</option>\n";
                }

                $html.="</select>";
            }

Hopefully you noticed how looping through format parts first let's us position the dropdown in the same order as given in the $format parameter.

So essentially that's it, we can now output the $html:

       // that's it, return dropdowns:
        return $html;
    }

Again, the full source code is available at PHP Classes so you can see it there as a whole.

Using the Date Drop Down:

Here is how to call this now:

    QuickDD::$start_year=2009;
    QuickDD::$end_year=date("Y")+10;

    // see how we pass the base name for the dropdowns, values, and markup array which will
    // set DOM ID, CSS class, and Javascript callback to every drop-down.
    // Of course all this is optional
    echo QuickDD::date("final", "2012-12-21", "DD-MM-YYYY", array(" id='selectDay' class='some_class' onchange='doSomething(this.value);' "," id='selectMonth' class='some_class' onchange='doSomething(this.value);' ", " id='selectYear' class='some_class' onchange='doSomething(this.value);' "));    

    if(!empty(QuickDD::$errors)) print_r(QuickDD::$errors);

This way you can add all kind of javascript and CSS markup, pre-selected values etc. But of course it can be called also in much simpler way using the defaults:

QuickDD::date("date");

Really simple.

Drop-down With Associative Arrays

These are very often used in DB driven apps. In our example we'll have a simple DB table with students where each student has an ID, email, and name. And we want to display a drop down menu to display a student. Visually the student name will be shown, but the value attribute will show the student ID so we can process it further in the app.

Here's the beginning:

// Outputs drop-down populated from associative array (usually coming from database)
    // @param $rows - the associative array
    // @param $value_field - the name of the key from the array whose value will be placed into
    // the option tag "value" attribue
    // @param $display_field - the name of the array key that will be used for display text
    // @param $sel - optionally a pre-selected value (for example when editing DB record)
    public static function hash($rows, $value_field, $display_field, $sel=NULL)
    {

Now the main function code is just few lines:

$html="";
        foreach($rows as $cnt=>$row)
        {
            if(is_array($sel))
            {
                // multiple-select drop-down
                if(@in_array($row[$value_field],$sel)) $selected=' selected';
                else $selected='';
            }
            else
            {
                // single-select drop-down
                if($sel==$row[$value_field]) $selected=' selected';
                else $selected='';
            }
            $html.="<option value=\"$row[$value_field]\"".$selected.">$row[$display_field]</option>\n";
        }
        return $html;

What we do here:
1. We start with $html buffer
2. Then loop through the DB records
3. Check if pre-selected value is passed, whether it's array of values (useful in multiselect drop downs), and check if it matches the current row.
4. Output the display field and value fields appropriately.

That's it. And here's how to use this method:

<select name="student_id">
    <option value="">- Please select -</option>
    <?php echo QuickDD::hash($students, "id", "name", 2);?>
    </select>

Drop-down With Simple Arrays

Simple arrays means ones that are not associative although you can use associative too. The function will not look for keys though, it will work only with values. So it's good for list of colors (like in this example), numbers, names, currencies etc. The function accepts one array for displays, and one for value attributes of option tags. But more often you'd probably call it with the same array in both places so what you see is what you get as option value. Here's the function, then the example will help you understand better:

 // outputs dropdowns using simple arrays for value attribute and for display
    // @param $values - the array of values that goes to "value" attribute
    // @param $displays - the array of texts that will be displayed in the options
    // @param $sel - pre-selected value
    public static function arrays($values, $displays, $sel=NULL)
    {
        $html="";
        foreach($values as $cnt=>$value)
        {
            if(is_array($sel))
            {
                // for multiple-select drop-down
                if(in_array($value,$sel)) $selected=' selected';
                else $selected='';
            }
            else
            {
                // single-select drop-down
                if($sel==$value) $selected=' selected';
                else $selected='';
            }
            $html.="<option value=\"$value\"".$selected.">$displays[$cnt]</option>\n";
        }

        return $html;
    }

It's very similar to the previous one. But instead of getting values by keys, we browse through each array.

Here's example usage with colors:

<p>Select color: <?php
    // here's the color array
    $colors=array("black","white","blue","green","red","orange","yellow");
    ?>
    <select name="color">
    <option value="">- Please select -</option>
    <?php echo QuickDD::arrays($colors, $colors);?>
    </select></p>

That's it. You can improve the class by adding more error checking and some friendlier way to display the errors (for example in HTML comments).

Do you have ideas for other often used drop-downs that can be added to the class?

Autoresponder updates: Basic 2.9 and PRO 1.1

Posted by admin on March 29th, 2012

Here are the latest BroadFast Autoresponder updates:

Basic Autoresponder, version 2.9:

  • Improved “read” tracking. I added bgsound tag for better tracking of who read your emails (this works only when switched on by yourself). These stats can never be 100% reliable because some email services don’t show the tag, but now the correct percentage should be higher.
  • External signup script that you can place anywhere and hide the registration. More info in this pictorial.

PRO Autoresponder, version 1.1:

In addition to the same new features as in Basic, we have added segmentation. It allows you to target segments of any of your mailing list, thus improve results and at the same time sending lower number of emails. This pictorial will  explain  the filters and segmentation in greater details.

Upgrade terms for existing customers are as usual – free upgrades if you have bought less than 1 year ago, and 50% discount otherwise.

Improved Grocery List on Pyrostia

Posted by admin on March 13th, 2012

Our free weekly menu planner now has improved automated grocery list. You can mark various items as bought and know what you really need to buy for the week.

The source code will be released soon so you’ll be able to host Pyrostia on your site as well.

WatuPRO WordPress Plugin To Create Exams

Posted by admin on March 6th, 2012

A lot of people expressed interest to have our web based exam software as a wordpress plugin. So, here we go, the premium WordPress plugin for creating and managing exams is online – WatuPRO WordPress Plugin.

While the WordPress plugin is similar in functionality to the standalone PHP based Watu Exam/Watu Plus, it also have some extra features and cleaner user interface. The best thing in it is that you can install it and manage it entirely from your WordPress admin panel.

Have a look at WatuPRO.

WatuPRO Demo Exam 2

Posted by admin on March 6th, 2012

This is a demo of WatuPRO.

This exam reuqires registration to be completed. While the questions/answers are the same as in “Open exam”, they will be displayed all, each time, so the maximum point number is 15. On top of that you have only 3 minutes to complete it – it’s exam with a timer. Questions and answers are randomized each time. Once logged in, you can take the quiz many times. This is also configurable, as the admin may decide to disallow second taking of the same exam.

Upon completion and receiving “Passed” grade (if you receive at least 8 points), you will be able to print customized “certificate”. It’s a simple one here, but you can use as complex and rich HTML as you wish.

You need to be registered and logged in to take this exam. Log in or Register

WatuPRO Demo Exam

Posted by admin on March 6th, 2012

This is a demo of WatuPRO.

This demo exam is open for everyone, no registration required. Three random questions are pulled each time, out of a pool of 5 questions.

1. Test question one. This is a single-answer question. This means, only one answer can be selected.

You can of course add some rich HTML content to the question.

And this is done simply by using the Wordpress rich text editor.


 
 

(Question 1 of 3)

2. Select all that are correct:


 
 
 
 
 

(Question 2 of 3)

3. A picture based question. Yes, you can upload pictures without any issues. What's this:

Red-eyed Treefrog, Agalychnis callidryas

 

(I used Flickr embed code here but you can also upload local photos)


 
 
 

(Question 3 of 3)



Watu Plus 1.2

Posted by admin on February 24th, 2012

What’s new in Watu Plus 1.2:

  • Select random questions from a pool. This feature allows you to create many questions in one exam and then have each student see only a small number of them, randomly selected and server. Makes the exam unique for every sitting.
  • Import/Export students in user groups as CSV file. This will make your life easier if you want to mass edit student records in Excel or to import users from existing database.

As usual old customers can purchase upgrade with 50% discount, and upgrades are free if you have purchased Watu Plus less than one year ago.

Period and Fertility Calendar

Posted by admin on January 11th, 2012

This is our latest free application for women – period and fertility calendar. Here is what it does:

  • Figure out your most fertile dates
  • Find out expected due date
  • See the approximate date of your next period
  • Store history of your periods so you never forget them and be prepared on time

Some technical background (because many developers read this blog):

It’s HTML 5 Ajax app with localStorage support. I’m not yet ready with the pluggable open source version, but you can see the front-end javacsript with View Source.

Contact Us Pages That Work: How To Get The Most Of Yours

Posted by admin on December 21st, 2011

There are several elements that make contact pages work. Of course you’d rarely have all them combined into your contact page. Some contact pages contain only one of these elements while other implement more. See them and figure out which will work best for you.

Contact Info + Address And Map

Screenshot of PHD Consulting

These contact pages usually contain your picture, a link to social profiles, street address and a map. It’s a good way to build a contact us page if you are willing to share your location. It shows you are a real person or company, and builds trust.

Here is this example with only the person’s picture missing.

Impressive Design

Design might not be the first you think about when building your contact form. Too bad! It’s one of the most important pages on your site. A “contact us” page that looks amazing does few amazing things:

  • Keeps the visitor on the page. So they hopefully will really fill that great looking form rather than closing it!
  • Builds trust (again). If your contact form looks great perhaps you are offering great services or products too
  • Goes viral. There’s no need to give you  links to posts that link to amazing contact forms. In fact, this is a such post too. Here is one amazing contact form. And below is another:
Indofolio screenshot

 

Headset Hottie

EARTHQUAKE Office!!!

There is no joke. A “headset hottie” can draw some attention and give the feeling there will be someone to answer. People know they are fake but they still like them. There is even a whole site dedicated to headset hotties.

It’s better however if you put your own picture or a picture of your real staff (if you have any).

More Than One Contact Method

Please don’t leave us hanging on a contact form or email only. You must have at least one social network profile where I can reach you. Twitter, Skype, and/or phone number are also highly positive. The more options you give to connect, the more likely your visitors are to do it.

Call To Action

The reason you build a contact page is that you want people to contact you. You know how bigger are your chances to make business with someone who already contacted you than with a stranger.

So, make it clear where the contact form is (you do have a contact form, right?) and make that button big and appealing. Make people crave to click it so badly that they won’t get bored by the rest of the fields they have to fill.

Contact Form Autoresponder

BFT Pro Screenshot

I’m not talking about the “thanks for contacting us” auto-reply. Sometimes it’s useful to confirm that the message has been delivered and to keep your address in the prospect’s mailbox. Don’t rely too much on this however as people barely check their read mail again. It’s a lot more important to reply to their inquiry.

But why not go further than this? You could also subscribe everyone who contacts you to a mailing list or autoresponder. Of course you’d better let them know in advance and request email confirmation before doing this. This can be implemented with the PRO version of BroadFast Autoresponder for example.

Because these people already made the effort to contact you they are likely to be interested in what you offer. So your autoresponder may work well on them. Just don’t look at hard selling – better include them in informative newsletters or autoresponders and build trust over time.

List Your Other Websites

If you have more than one site (and they are related to each other), your “contact us” page is a great place to share them. Here is why:

  • Lets people check what else you do. Again this builds trust.
  • Helps you get some traffic on the other sites. And maybe a customer too?
  • If they didn’t find exactly what they were searching for maybe they’d find it on the other sites?

List the other sites gently under the main contact info and make sure they open in new tab.

Give Your Other Channels

Having Flickr account, Youtube or Vmeo channel, shared Delicious list, or Behance profile? Your contact page is a good place to share them too.

Keep The Contact Form Easy And Simple

Don’t forget that people have to actually fill that form to get in touch with you. Although some will use the other contact options most will fill the form. So make it easy and simple:

  • Keep fields to the minimum. Name, Email, Message and (maybe) subject/reason. (Don’t call it “department” please, I don’t give a dime about how you structure your company internally)
  • Make gentle validation. Something like jQuery validator will do the work. Or see a bunch of other validation plugins.
  • Avoid captchas if possible and use other ways to stop spam.
  • Make tab order work correctly. Don’t make us click every field with the mouse.

Follow these practices and let me know the outcome. If we can help you with autoresponder software or designing your contact page, contact me via my contact page. I know it badly needs rework! (Goes in my to-do list)


Copyright © 2010 Software and Small Business.