How to use honey pots in Zen Cart Forms.

Some ideas on coding spam traps in Zen Cart forms.

I get that not everyone is able to code or come up with something that works with your site layout. We can only help so far and then it becomes a job… If you can not figure something out, don’t be afraid to ask how much or hire someone.

This is for folks that want to learn or do it them self and not a drop and run set of code.

I’ll concentrate on the ‘Contact Us’ form, but this can and should be used on any from. The words ‘CHANGE_THIS’ means just that! Change the word to something that makes sense to the form its in. The idea of a good honey pot is that theres no noticeable difference between it and the rest of the form.

The three type of honey pots I’ll use are:

1) hidden input, radio, and textarea form field traps.
2) visible questions.
3) confirmation of information.

1) hidden input, radio, and textarea form field traps.

Step 1. Setup the ZC template pages.
The contact us page has four parts,
1) the template page YOUR_TEMPLATE/template/tpl_contact_us_default.php,
2) the header page modules/pages/contact_us/header_php.php,
3) the language page languages/english/YOUR_TEMPLATE/contact_us.php,
4) the css page YOUR_TEMPLATE/css/contact_us.css.

Two things that affects all ZC, the template override pages and the non-override pages. The three pages here, template, language, and css should be in your template override folder and only affect your template. The header page does not have a override and will affect all templates!

I use a common css file for all my css for the template I’m using and not the contact_us one.

Step 2. Using the hidden field.
No matter what you do, you can’t prevent users from having full access to every bit of data on your website. Additionally, there’s no way to disable the ability of any user to simply “view source” or “view page info” for your site. You CAN make it super-confusing to read it… Simple input fields are easy to understand, complex checkbox or radio fields can confuse anyone. Input or textarea fields are normally empty, but what if that wasn’t true! Check boxes can be checked or not, 50% chance of getting that right.. Two radio’s connected, click one or the other, but both can be unselected or false at startup!! Text areas, what system wouldn’t pass up a chance to advertise in that! Option fields, pick any one and your wrong! In short, any form field can be used to trap a bot hidden or not!

This is a normal email field for my site:

<div class="js-float-label-wrapper">
<label for="email-address"><?php echo ENTRY_EMAIL; ?></label>
<?php echo zen_draw_input_field('email', ($email_address), ' id="email" spellcheck="false" title="Please enter a E-Mail address (" pattern="^(([-\w\d]+)(\.[-\w\d]+)*@([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$" required="required" aria-required="true"', 'email'); ?>

This would be my spam catch:

<div class="js-float-label-wrapper email-pot">
<label for="email-us"></label>
<?php echo zen_draw_input_field('CHANGE_THIS', '', ' id="email-us" title="do not fill in!" placeholder="do not fill in!" autocomplete="off"', ‘email’); ?>

Do you see the difference? I use a script to float labels, if I used a label for this field, the default would not be empty, but the label! So testing for the label would be correct and not empty. Basically, the reverse of normal honey pots. Normal behavior is that this field would be empty. To test, one would comment out the css hide and fill in the line during form submit.

Based on the hidden idea, the radio field would be like this:

<div class="js-float-label-wrapper email-pot">
<p>To prevent Spam we ask if you are a human or a computer. If for some reassign you are reading this line.<b>Do not Answer!</b></p>
<?php echo zen_draw_radio_field('user', 'H1', false, 'id="user-1"') . '<span class="input-group-addon"><i class="fa fa-male fa-2x"></i></span>' . zen_draw_radio_field('user', 'C2', false, 'id="user-2"') . '<span class="input-group-addon"><i class="fa fa-laptop fa-2x"></i></span>'; ?>

Both are set to false, if ether is set during submit, then its a bot.

Step 3. Hide the field.
Using contact_us.css or stylesheet.css add the email-pot class.

.email-pot {position:absolute; visibility:hidden; display:none;}

Step 4. Test for bot answers.
In this test we want the bot to think it succeeded in submitting and leave. So we need to use the success page and not an error message which is why adding comments for humans not to fill out if for some reason the css fails is just as impotent.

In modules/pages/contact_us/header_php.php when the form is submitted, it starts an action called SEND so we need to look for the beginning of the submit action then under it add our post lines.

if (isset($_GET['action']) && ($_GET['action'] == 'send')) {

$antiSpam = isset($_POST['CHANGE_THIS']) ? zen_db_prepare_input($_POST['CHANGE_THIS']) : '';
  $userspam = zen_db_prepare_input($_POST['user']);

You can omit which ever one your not using or do both.
The test can be after all others or before:

if (($antiSpam != '') || ($userspam != '')) {
zen_redirect(zen_href_link(FILENAME_CONTACT_US, 'action=success', 'SSL')); 

If ether are not empty, stop sending and get to the success page to fake out the bot.

2) visible questions.

CAPTCHA is basically a visible question a human would answer. The issues with any is how the user can interact with the question! CAPTCHA code can be internal (Your code on site) or external (third party code off site). With ZC plugins, you have both options. Personally, I would keep my customers on site and not allow for off site tracking or down servers. If captcha is done so the bots can not read the answer, then nether can humans and even worse if sight in-pared! Which is one reason for 508 complacency.

If not CAPTCHA then what? Well, build a better question and answer system! We have one hidden that use radio buttons, unhidden and test for the correct answer!!

The bot has a 50% chance of guessing right with radios and checkboxes!

Input field, 2+2= type the number 4! How about some other question like yellow+blue= type the word green!

What about sliders? The variables are grate, the answer can be any number, lets see the bots guess right here…

The harder one to code is the slider so I’ll cover it.

Step 1. Add the code for the slider at the bottom of the form.

<div class="slidecontainer">
<p>Are you Human? Slide to Human..</p>
  <?php echo zen_draw_input_field('iqTest', '', ' min="0" max="50" value="0" class="slider" id="id1"', 'range'); ?>
<br /><br />
<span>Value:</span> <span id="f" style="font-weight:bold;color:red"></span>

Step 2. Add css to format the slider.

/******** slider ********/
.slidecontainer {
    width: 100%; /* Width of the outside container */

/* The slider itself */
.slider {
    -webkit-appearance: none;
    width: 100%;
    height: 1px;
    border-radius: 5px;  
    background: #d3d3d3;  
    outline: none;
    opacity: 0.7;
    -webkit-transition: .2s;
    transition: opacity .2s;

.slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 25px;
    height: 25px;
    border-radius: 50%; 
    background: #cc0000;
    cursor: pointer;   

.slider::-moz-range-thumb {
    width: 25px;
    height: 25px;
    border-radius: 50%;
    background: #4CAF50;
    cursor: pointer;

Step 3. Add script to modules/pages/contact_us/jscript_main.php
The code is used to display feed-back to the user so they know when to stop or the question was answered. Some day the browsers will support this without script, a html5 issue!

Enter within the script tags are create another set.

$(document).ready(function () {
var slideCol = document.getElementById("id1");
var y = document.getElementById("f");
y.innerHTML = slideCol.value; // Display the default slider value

// Update the current slider value (each time you drag the slider handle)
 slideCol.oninput = function() {
    y.innerHTML = this.value;
    if (this.value >= 50) {
      y.innerHTML = 'Human';

Step 4. Set the trap. modules/pages/contact_us/header_php.php
Set the field get and check under the other spam tests.

  $humanTest = zen_db_prepare_input($_POST['iqTest']);
     if ($humanTest != '50') {
     $messageStack->add('contact', 'You don\'t seem to be Human yet!', 'error');
     $error = true; 

We don’t want to reload the page and delete all the user inputs here, they need to fix there answer and resubmit the form.

You can use any number, script can change any number to a word, the possibilities are limitless.

3) confirmation of information.

Simply, the user fills out the form. The submit button verifies the form and takes the user back to the page with all fields full. The page asks the user to verify the information before sending. Basically two clicks to send the page. Most bots will see the first send as finished and leave. The second click would be a human and final send.

Users normally don’t have a problem with verifying what they entered before sending.. Its like previewing before submitting to a forum!

In closing,  I see no reason to eye test customers with an off site CAPTCHA that may not work or be available to use.

Write Review Star Using Font Awesome Round 2

I’ve gone down another rabbit hoe with reviews. I’ve looked at some other sites, Amazon used graphs, another had words with the stars as css sprites, another kept you on the product page to add reviews, one had separated the review score from the review comment.. which I thought would be grate if I did books..

So I added graphs, cleaned up the layout, added voting for helpful or not.. added an abuse link which fires up the contact us popup with the subject field in with the review id…

Now the form expends down to allow writing and submitting a review, all while still on the product page… still thinking about separating the review score and comment… folks always have time to click a rating but don’t have allot of time to think out a comment! unless its to say how much you disliked it…

I think I’m on to something better then the standard reviews or not! Look at the shoots, ask.. if I get enough votes, maybe I’ll convert it to a mod… I also had to redo the amin side to make it work there too..

Some screen shoots..

review review2 review3review4

Write Review Star Using Font Awesome

This is more of a tip, too small to me a mod.. while modifying my tpl_product_reviews_write_default.php for responsive form design, I solved two issues I had and thought why not pass them along!

This tip is for anyone using Font Awesome on there site or wish to install it.

First of all, I have a testing server setup so I can create and test than upload to my live site. One of the pain was Font Awesome would not always work if I loaded locally form my site so I had to have the link to Font Awesome when live and link to my local copy when working off-line on design. Got the idea off the net and modified it to work for me.

Replace or add the script below the link to Font Awesome as below on your YOUR_TEMPLATE/common/html_header.php page just above the closing head tag;

<link rel="stylesheet" href="">  
        var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if ($span.css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append(<?php echo '\'<link rel="stylesheet" type="text/css" href="' . $template->get_template_dir('.css',DIR_WS_TEMPLATE, $current_page_base,'css') . '/' . 'font-awesome.css' . '" />\''; ?>);

Now that you have it installed, now what! Why I’ve started down this patch… I finally got around to redesigning the layout of my Add Review page. It was the standard mess and not responsive at all. In making it responsive as with my other forms, I hated the old radio button rating of 1 – 5 input buttons with a 5 star image. Really an antic method that I was stuck with… But wait! looking at other sites, like Amazon, they was using a cool 5 star set of stars, not a old style radio input button! must be something I could do!

Was looking at coding something in jQuary to do it. Then looking at Font Awesome, they was displaying the same set of star’s as amazon was using… turns out the coding wasn’t a jQuary answer after all…

Turns out adding cool star’s was as easy as adding font awesome to your site. And to top it off, stars are not the only thing you can use.. like jets, apples, bells, cars…. get the idea, any icon within the font can be used..

First you need some CSS to handle the stars create or add to YOUR_TEMPLATE/css/product_reviews_write.css page;

.masterdog {position:relative;} 
.rating { float:left;} 
.rating:not(:checked) > input {position:absolute;top:-9999px;clip:rect(0,0,0,0);} 
.rating:not(:checked) > label {float:right;width:1em;padding:0 .1em;overflow:hidden;white-space:nowrap;cursor:pointer;font-size:4em;line-height:1.2;color:#e0e0e0;} 
.rating:not(:checked) > label:before {font-family: FontAwesome;content: "\f005";} 
.rating > input:checked ~ label {color: #ef2929;} 
.rating:not(:checked) > label:hover, .rating:not(:checked) > label:hover ~ label { color: #f57900;} 
.rating > input:checked + label:hover, .rating > input:checked + label:hover ~ label, .rating > input:checked ~ label:hover, .rating > input:checked ~ label:hover ~ label, .rating > label:hover ~ input:checked ~ label {color: #729fcf;} 
[id^="tooltip-"] {-webkit-transition: .4s;transition: .4s;} 
[id^="show_me-"] {opacity: 0;} 
#remove_me {opacity: 1;} 
#tooltip-1:hover ~ #show_me-1 {opacity: 1;} 
#tooltip-1:hover ~ #remove_me {opacity: 0;} 
#tooltip-2:hover ~ #show_me-2 {opacity: 1;} 
#tooltip-2:hover ~ #remove_me {opacity: 0;} 
#tooltip-3:hover ~ #show_me-3 {opacity: 1;} 
#tooltip-3:hover ~ #remove_me {opacity: 0;} 
#tooltip-4:hover ~ #show_me-4 {opacity: 1;} 
#tooltip-4:hover ~ #remove_me {opacity: 0;} 
#tooltip-5:hover ~ #show_me-5 {opacity: 1;}  
#tooltip-5:hover ~ #remove_me {opacity: 0;} 
.rating span {transition: opacity 1s;position:absolute;top:50px;left:10px;width:300px;height:20px;font-size:3.5em;line-height:1;color:black;}  
@media (max-width:480px){.rating span {font-size:2.5em;}.rating:not(:checked) > label {font-size:3.5em;}}

Now all that’s left is to replace the old input with the new, in YOUR_TEMPLATE/template/tpl_product_reviews_write_default.php page;


<div class="ratingRow"> 
<?php echo zen_draw_radio_field('rating', '1', '', 'id="rating-1"'); ?> 
<?php echo '<label class="" for="rating-1">' . zen_image($template->get_template_dir(OTHER_IMAGE_REVIEWS_RATING_STARS_ONE, DIR_WS_TEMPLATE, $current_page_base,'images'). '/' . OTHER_IMAGE_REVIEWS_RATING_STARS_ONE, OTHER_REVIEWS_RATING_STARS_ONE_ALT) . '</label> '; ?> 
<?php echo zen_draw_radio_field('rating', '2', '', 'id="rating-2"'); ?> 
<?php echo '<label class="" for="rating-2">' . zen_image($template->get_template_dir(OTHER_IMAGE_REVIEWS_RATING_STARS_TWO, DIR_WS_TEMPLATE, $current_page_base,'images'). '/' . OTHER_IMAGE_REVIEWS_RATING_STARS_TWO, OTHER_REVIEWS_RATING_STARS_TWO_ALT) . '</label>'; ?> 
<?php echo zen_draw_radio_field('rating', '3', '', 'id="rating-3"'); ?> 
<?php echo '<label class="" for="rating-3">' . zen_image($template->get_template_dir(OTHER_IMAGE_REVIEWS_RATING_STARS_THREE, DIR_WS_TEMPLATE, $current_page_base,'images'). '/' . OTHER_IMAGE_REVIEWS_RATING_STARS_THREE, OTHER_REVIEWS_RATING_STARS_THREE_ALT) . '</label>'; ?> 
<?php echo zen_draw_radio_field('rating', '4', '', 'id="rating-4"'); ?> 
<?php echo '<label class="" for="rating-4">' . zen_image($template->get_template_dir(OTHER_IMAGE_REVIEWS_RATING_STARS_FOUR, DIR_WS_TEMPLATE, $current_page_base,'images'). '/' . OTHER_IMAGE_REVIEWS_RATING_STARS_FOUR, OTHER_REVIEWS_RATING_STARS_FOUR_ALT) . '</label>'; ?> 
<?php echo zen_draw_radio_field('rating', '5', '', 'id="rating-5"'); ?> 
<?php echo '<label class="" for="rating-5">' . zen_image($template->get_template_dir(OTHER_IMAGE_REVIEWS_RATING_STARS_FIVE, DIR_WS_TEMPLATE, $current_page_base,'images'). '/' . OTHER_IMAGE_REVIEWS_RATING_STARS_FIVE, OTHER_REVIEWS_RATING_STARS_FIVE_ALT) . '</label>'; ?> 

And replace all of it with the following;

<div class="masterdog">
<div class="rating">
<?php echo zen_draw_radio_field('rating', '5', '', 'id="tooltip-5" '); ?><label for="tooltip-5"> 5 stars</label>
<?php echo zen_draw_radio_field('rating', '4', '', 'id="tooltip-4" '); ?><label for="tooltip-4"> 4 stars</label>
<?php echo zen_draw_radio_field('rating', '3', '', 'id="tooltip-3" '); ?><label for="tooltip-3"> 3 stars</label>
<?php echo zen_draw_radio_field('rating', '2', '', 'id="tooltip-2" '); ?><label for="tooltip-2"> 2 stars</label>
<?php echo zen_draw_radio_field('rating', '1', '', 'id="tooltip-1" '); ?><label for="tooltip-1"> 1 stars</label>
<span id="show_me-5">Very Best</span><span id="show_me-4">Best</span><span id="show_me-3">Good</span><span id="show_me-2">Bad</span><span id="show_me-1">Pretty Bad</span><span id="remove_me"></span>

FontAwesome Stars
The stars are radio inputs so the back end code stays the same, the only thing changing is the input radio buttons. The change in order and labels are needed for text readers and touch which makes things work for touch screens like phones..

Now all you need to do is redesign that boring review page, you have lots of space now! You can checkout how I did my page, I have guest checkouts so guest reviews are allowed.


I found that just having stars was a bit boring… I added words too. On hover the words change to match the star, on selection, the 1 of 5 Stars is displayed! The whole thing is responsive too…

rating3 rating4

You need a bit of script to get the 1 of 5 to respond to the star clicks..

in includes/modules/pages/produst_reviews_write/jscript_main.php add this bit of jQuary code somewhere.

var radVal = $("input[name='rating']:checked").val();
$('#remove_me').html(radVal + ' of 5 Stars!');

If your like me and try different things, maybe 1 of 5 is not what you want and what was selected stays visible. Then the code below would work for you too.

    var radVal = $("input[name='rating']:checked").val();
    switch (radVal) {
    case '1':
        $('#remove_me').html('<?php echo STAR_1;?>');
    case '2':
        $('#remove_me').html('<?php echo STAR_2;?>');
    case '3':
        $('#remove_me').html('<?php echo STAR_3;?>');
    case '4':
        $('#remove_me').html('<?php echo STAR_4;?>');
    case '5':
        $('#remove_me').html('<?php echo STAR_5;?>');