Jump to content

Service order form


tinacious
 Share

Recommended Posts

Hello everyone and thanks in advance for your help.

I am looking to create an order form with a list of services where clients can choose which services they would like to pay for.

I require some to have a text field to specify the quantity, others will be multiple choice with checkboxes, and others will be yes/no radio buttons.

I wanted to elect a price to each item so when the item is selected a corresponding price that is associated is added to the total, which ideally would be displayed somewhere in a sidebar/always in view so that the users can see the price change as they add/remove services. This part I'm assuming would need to use jQuery/Javascript.

I also want it to support file upload and to email the form to me.

I was looking at a variety of modules:

  1. I have worked with the FormTemplateProcessor module before for sending basic contact forms via email.

    1. I like it and was considering using it to build this form.
    2. I'm still unsure about integrating payment processing and price updating features I was looking at incorporating.

[*]I was also looking into the premium ProcessWire Form Builder.

  1. This looks like the easiest way to build a complex form. The only down side I can see is having to choose a jQuery UI theme, though I read I could create my own using ThemeRoller, though I generally prefer to have full control over form element styles in my stylesheet.
  2. Also for this one I'm unsure about how to integrate payment and price updating

[*]Shop-for-Processwire module also looks great for a shopping cart and check-out scenario

  1. This looks like a great base to work with for the payment processing, as well as displaying an accurate price (though it seems like it would require a page load)
  2. I'm not sure how to go about translating a product/shopping cart scenario into an order form scenario.
  3. Also I'm not sure how well it would play with a file upload, though I haven't tested it.

Can I add some hidden value to each of these items somehow, and with jQuery have these values add up and display a price, and with ProcessWire/PHP have it do the same and send a tallied price to my email, with a list of services, etc.? Does this price tallying need to be done twice, once in each language?

With all of this research I still can't figure out what is the best approach to take to accomplish this task. Am I on the right track? Can anyone guide me in the right direction?

Hopefully this question is clear. If not, please let me know and I'll add more details.

Thank you for your help.

Link to comment
Share on other sites

The Form builder is great for building forms easily and quickly, but for a one time form it's not that difficult to make a customized one that plays along pw fields with great flexibility. It's really just a matter of building the form as you want in html, and selectively save the submited information in each field with the pw API:

$page->of(false)

$page->product_id = (int) $input->post->id;
$page->quantity = (int) $input->post->quantity;
$page->client_address = $sanitizer->text($input->post->address);
...
$page->save()

The price update you can do with jQuery. I prepared something very simple to show how :)http://codepen.io/anon/pen/apBmI

The thing that can be more difficult is the payment, but all depends on what system or systems you will choose. If you choose paypal for instance, it can be as simple as having a submit with the address that they supply to you, and receive a confirmation of payment done.

It's not my intention to make it look very easy (it's not), but it's not as difficult as it might seem.

edit: corrected from $page->of(true) to $page->of(false), thanks to onjegolders.

  • Like 2
Link to comment
Share on other sites

Hi Diogo, thanks for including some code. I think I can figure out the jQuery part with what you supplied but the ProcessWire part still seems a bit complicated.

Here's an example of a form I've started in my order.php template which will be accessible from domain.com/order

<div class="section">
<div class="container">
<?php echo $page->body; ?>
<form id="orderForm">
<label for="customer_name">Full Name</label>
<input type="text" id="customer_name" name="customer_name">
<label for="email">E-Mail</label>
<input type="email" id="email" name="email">
<label for="quantity">Quantity of Product</label>
<input type="text" size="5" name="quantity">
<h2>Add-Ons</h2>
<input type="checkbox" name="addons" value="firstoption"><span>Add-on 1</span>
<input type="checkbox" name="addons" value="secondoption"><span>Add-on 2</span>
<input type="checkbox" name="addons" value="thirdoption"><span>Add-on 3</span>
<h2>Do you want this premium service too?</h2>
<input type="radio" name="premium" value="YES"><span>Yes</span>
<input type="radio" name="premium" value="NO" checked><span>No</span>
<input type="submit" value="Submit Your Order">
</form>
</div>
</div>

pw-order-form-help.png

Would my PHP code look something like this?


$page->of(true);
$page->customer_name = $sanitizer->text($input->post->customer_name);
$page->customer_email = $sanitizer->text($input->post->email);
$page->quantity = $input->post->quantity;
$page->add_ons = $input->post->addons;
$page->premium = $input->post->premium;
$page->save();

The form action would be domain.com/order and the method post? I want to email the values to myself. I'm not 100% sure how to do that with the ProcessWire API outside of the FormTemplateProcessor module.

EDIT: I tried the above and it definitely didn't work. I guess I'm not sure how to go about doing this.

Link to comment
Share on other sites

Yes, method should be post.

Since you will be submitting to the same page, all the code will go on the same template. You might want to do this as the action:

<form id="orderForm" action="<?php echo $page->url ?>">

Now we have to test for the submission of the form. This test can be used also inside the form to output errors.

I will use the radio button for this, since it will have a value for sure

if ($input->post->premium) {
   // form was submited. Here is where we will collect all the information
}else{
  // you don't have to use the else, but here is the place to output something for when the form wasn't submited
}
// form should go outside the if statement

To collect the information we will have to know where to send it to. I don't know if you decided on those things but, are you going to create a page for each transaction? Or a page for each client? Here I will assume you will want to save a page for each transaction. For this you will have already prepared, a template "transactions" with all those fields (customer_name, email, quantity, addons, premium), and I will assume that you will have all the transaction as children of the page "/order/".

if ($input->post->premium) {

   // create a new transaction page
   $tr = new Page();
   $tr->template    = $templates->get("transaction");
   $tr->parent      = $pages->get("/order/");

   // fill the fields with the collected and sanitized info. See here about sanitation in pw [url="http://processwire.com/api/variables/sanitizer/"]http://processwire.com/api/variables/sanitizer/[/url]

   $name = $sanitizer->text($input->post->customer_name);
   $email = $sanitizer->email($input->post->email);
   $quantity = (int) $input->post->quantity; // (int) makes sure that the input is a number
   $add_ons = $sanitizer->text($input->post->addons);
   $premium = $sanitizer->text($input->post->premium);

   $tr>of(false); // this was wrong on my fist post. must be false
   $tr->customer_name = $name;
   $tr->customer_email = $email;
   $tr->quantity = $quantity;
   $tr->add_ons = $add_ons;
   $tr->premium = $premium;

   //save the page
   $tr->save();

   // send the email to you
   $subject = "new buy";

   $message = "{$name} bought {$quantity}. His email is {$email}";
   mail('youremail@example.com', $subject, $message);

   // here you can redirect to a confirmation page, or to the same page for another buy

}

// code for the form

This was only the basic. You should also perform some validation in the php code, and check if everything is ok before creating the page. The most common way is to use a errors array.

  • Like 3
Link to comment
Share on other sites

  • 2 weeks later...

WOW diogo, thank you! After a really long time trying my hand at this I was finally able to get it to work! That's amazing, thanks!

One more thing... Just to complicate things EVEN more... I wanted to upload files and have them emailed through this form as well. How would I handle files for this? I'd also like to restrict it to images and zip files.

<input type="file" id="screenshot" name="screenshot"/>

I'm guessing something like this:

$screenshotfile =  ; // not sure what to do here to grab the file
$tr->screenshot = $screenshotfile; // then create a file field for the template in PW

Thanks for your help!

Link to comment
Share on other sites

File uploads through public forms is where things can get dangerous if not handled really carefully. Adding email to the mix makes it even more so. When a client brings up this need, I always see if the need can be solved in some other fashion, like asking the user to email the file, or specify a URL, etc. I consider public file uploads kind of a last resort if nothing else will work, so generally avoid them when possible. Recognize that you will get viruses and exploit scripts sent to you through your public upload form (even if limiting it to images). Given that, it's important to make sure those files could never end up in a spot on the server where the user could access them by direct URL. It's also important to make sure that the client is prepared to deal with this sort of stuff. In terms of actual implementation, I think this may be outside the scope of what we can safely cover in full, but there are a lot of articles that include details of how to do this (search google for "file upload php email attachments"), such as this one at Sitepoint. Another option is to use Form Builder, which has page creation and safe file upload capabilities built-in. It doesn't email files, but it does email secured links to them (which is a more complex, but potentailly safer way to go vs. emailing the actual file).

  • Like 1
Link to comment
Share on other sites

Ryan, thanks for that info on security. Using Diogo's example, would it be safer to get users to upload a file and have the download link available on the page created as opposed to emailing the file? I would like to use the ProcessWire file upload functionality to have users upload a file (and limit the file format). I'm just wondering how to handle that and pass it through ProcessWire and have it post to the new page that is created. In the email that sends I was thinking of just supplying basic information and a link to the new transaction page. That would avoid the need (and security issues) with emailing a file.

Assuming I have a file field with the name and id of snapshot_file, I'm guessing I would create a file field and limit its types and then do something like:

$snapshot = $input->post->snapshot_file;

// and in the new page creation section
$tr->snapshot_field = $snapshot;

I'm just wondering the specifics of passing a file through ProcessWire into a field, e.g. file sanitizer, etc.

The Form Builder looks like a great option. It sounds like you've already thought of everything for it. As someone who loves to have control over my markup and CSS, I was avoiding this option because of the need to use a jQuery UI theme and the extra work required to workaround the way it outputs the HTML, assuming that it renders the form similar to FormTemplateProcessor in that it outputs the HTML in an unordered list. One of the plus sides to this is there are lots of classes to work with in the CSS! For this project I'd like to continue on this path but as Form Builder is a quick way to make forms, I can definitely see myself choosing it for quicker development in the future, especially for larger forms.

For this form I needed to add some data attributes for use with jQuery. As a somewhat off-topic question related to Form Builder, is the ability to add attributes (specifically data attributes) to inputs an option with the Form Builder?

Link to comment
Share on other sites

Ryan, thanks for that info on security. Using Diogo's example, would it be safer to get users to upload a file and have the download link available on the page created as opposed to emailing the file?

It depends. If the file is placed in a non-web accessible quarantine area and the download link runs through a passthrough script that eliminates possibility of file execution or unsafe mime type, then yes, it would be more secure. If that's not an option, then emailing may be more secure so long as the file size is kept small, and the file never exists in a publicly accessible URL on the server. Keep in mind anything sent through email is going to have to be base64 encoded, so the file will suddenly become a lot larger once it's encoded for email. Have the file send to gmail or some other service that has a strong filter for malicious stuff.

I would like to use the ProcessWire file upload functionality to have users upload a file (and limit the file format).

Keep in mind that it's limiting the file extension, not necessarily the file format. One thing I see through my public upload forms is a lot of files like c99.php.jpg where the person uploading is hoping that there's a bug somewhere down the line.

I'm just wondering how to handle that and pass it through ProcessWire and have it post to the new page that is created.

If there are any files involved, there are additional dangers in having it create a page at form submission time. Not saying it can't be done safely, but just saying it starts getting more scary to a security paranoid person like myself. :) If the files involved are images, I would only add images to the page that were confirmed to be actual images. One way to do this would be to use PW's ImageSizer() class to create another size variation of the image, and add that one instead of the original. This is what just about any social network does when you upload photos to it. Here's a stab at some validation. Not suggesting this is everything you'd need to do, but just attempting to cover most bases while thinking here in the browser:

// $filename = the file that was uploaded
$pathinfo = pathinfo($filename);
if(!in_array(strtolower($pathinfo['extension']), array('jpg', 'jpeg', 'gif', 'png')))
 throw new WireException("Invalid"); 
$info = getimagesize($filename);
if($info === false) throw new WireException("Invalid"); 
list($width, $height, $type) = $info;
if(!in_array($type, array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG)) 
 throw new WireException("Invalid"); 
$targetWidth = 200;
if($width == $targetWidth) $targetWidth++; // forced resize
$sizer = new ImageSizer($filename); 
if(!$sizer->resize($targetWidth)) throw new WireException("Invalid"); 
The Form Builder looks like a great option. It sounds like you've already thought of everything for it. As someone who loves to have control over my markup and CSS, I was avoiding this option because of the need to use a jQuery UI theme and the extra work required to workaround the way it outputs the HTML, assuming that it renders the form similar to FormTemplateProcessor in that it outputs the HTML in an unordered list.

Everything that FormBuilder does is meant to save you time. The default embed methods isolate the form from the rest of your site so that [unlike FormTemplateProcessor] you don't have to get involved with the CSS part at all if you don't want to. Meaning, it'll exist in your site without any effect or requirements on your site's stylesheets. That's assuming you utilize the default embed methods. But if you love having control over your own markup (even if it's isolated from that of your site's) then Form Builder will not be as much of a time saver just because writing markup takes time... especially form markup. Half the benefit of a form builder is that it takes care of the output for you. The other half of the benefit is that it takes care of the processing for you. The most time savings come when you let it take care of both for you. Though it'll do just one or the other if you want it to.

For this form I needed to add some data attributes for use with jQuery. As a somewhat off-topic question related to Form Builder, is the ability to add attributes (specifically data attributes) to inputs an option with the Form Builder?

There isn't currently a means by which to inject custom attributes into the actual markup. You'd have to do this with jQuery. Though this would be a fine way to go given that the data attributes are intended for javascript use in the first place. Each Form Builder theme has the ability to specify a custom JS file (like you can with a custom CSS file). So you'd do it like this:

$(document).ready(function() {
 $("#your-input-id").attr('data-something', 'Something'); 
}); 
  • Like 2
Link to comment
Share on other sites

Thanks Ryan for this information. The ImageSizer thing sounds great. I will do this for images and have users later email me non-image files normally.

Knowing that there is a solution for working with data attributes with the Form Builder, this will definitely be top of my list next time around. You seem to have taken lots of security issues into account. For form uploads and file handling, Form Builder seems like a great options for future projects.

For this one, I will take the current path and use your ImageSizer recommendations. Thanks.

Link to comment
Share on other sites

ImageSizer won't do anything to do the original image if it thinks it's already at the target dimensions, so be sure to give it a size that the image isn't already at. A few lines of the code in the previous example was specific to that.

Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...