Jump to content
MatthewSchenker

Create Pages (with File-Upload Field) via API

Recommended Posts

Greetings Everyone,

*************************************************
*************************************************
EDIT NOTE: This post started as a work-in-progress discussion as I was working out the elements of a successful form. After contributions from participants in this discussion, the code below has been tested and works well.

You can use the code as shown below in your ProcessWire templates!

Feel free to follow up with additional quesations/comments!
*************************************************
*************************************************

I have successfully built front-end forms with ProcessWire to add pages via the API. It works great -- until I had to include image uploads along with the "regular" form fields.  Then it temporarily got a bit complicated.

In this discussion, I show how to handle front-end submissions in ProcessWire with the goal of allowing us to create pages from custom forms.  I then go a step further and show how to use the same form to upload files (images and other files).

I'm hoping this discussion can illustrate the whole process. I know a lot of people are interested in using ProcessWire to do front-end submissions, and my goal for this discussion is to benefit others as well as myself!

First, here's my original contact form (no file uploads):

<form action="/customer-service/contact/contact-success/" method="post">
<p><label for="contactname">Name:</label></p>
<p><input type="text" name="contactname"></p>
<p><label for="email">E-Mail:</label></p>
<p><input type="email" name="email"></p>
<p><label for="comments">Comments:</label></p>
<p><textarea name="comments" cols="25" rows="6"></textarea></p>
<button type="submit">Submit</button></form>

And here's the "contact-success" page that picks up the form entry to create ProcessWire pages:

<?php // First, confirm that a submission has been made
if ($input->post->contactname) {

// Save in the ProcessWire page tree; map submission to the template fields
$np = new Page(); // create new page object
$np->template = $templates->get("contact_submission"); 
$np->parent = $pages->get("/customer-service/contact-us/contact-submission-listing/");

// Send all form submissions through ProcessWire sanitization
$title = $sanitizer->text($input->post->contactname);
$name = $sanitizer->text($input->post->contactname);
$contactname = $sanitizer->text($input->post->contactname);
$email = $sanitizer->email($input->post->email);
$comments = $sanitizer->textarea($input->post->comments);

// Match up the sanitized inputs we just got with the template fields
$np->of(false);
$np->title = $contactname;
$np->name = $contactname;
$np->contactname = $contactname;
$np->email = $email;
$np->comments = $comments;

// Save/create the page
$np->save();							    										    		

} ?>

This works great! After submitting the form, we go to the "Success" page, and new submissions show up in the ProcessWire page tree right away. Excellent!

Now I need to add a photo field. I altered the above form so it looks like this:

<form action="/customer-service/contact/contact-success/" method="post" enctype="multipart/form-data">
<p><label for="contactname">Name:</label></p>
<p><input type="text" name="contactname"></p>
<p><label for="email">E-Mail:</label></p>
<p><input type="email" name="email"></p>
<p><label for="comments">Comments:</label></p>
<p><textarea name="comments" cols="25" rows="6"></textarea></p>
<p>Click the "Select Files" button below to upload your photo.</p>
<input type="file" name="contact_photo" />
<button type="submit">Submit</button>
</form>

And here's the updated "contact-success" page:

<?php // First, confirm that a submission has been made
if($input->post->contactname) {

// Set a temporary upload location where the submitted files are stored during form processing
$upload_path = $config->paths->assets . "files/contact_files/";

// New wire upload
$contact_photo = new WireUpload('contact_photo'); // References the name of the field in the HTML form that uploads the photo
$contact_photo->setMaxFiles(5);
$contact_photo->setOverwrite(false);
$contact_photo->setDestinationPath($upload_path);
$contact_photo->setValidExtensions(array('jpg', 'jpeg', 'png', 'gif'));

// execute upload and check for errors
$files = $contact_photo->execute();

// Run a count($files) test to make sure there are actually files; if so, proceed; if not, generate getErrors()
if(!count($files)) {
$contact_photo->error("Sorry, but you need to add a photo!");
return false;
}

// Do an initial save in the ProcessWire page tree; set the necessary information (template, parent, title, and name)
$np = new Page(); // create new page object
$np->template = $templates->get("contact_submission"); // set the template that applies to pages created from form submissions
$np->parent = $pages->get("/customer-service/contact-us/contact-submission-listing/"); // set the parent for the page being created here

// Send all the form's $_POST submissions through ProcessWire's sanitization and/or map to a variable with the same name as the template fields we'll be populating
$np->title = $sanitizer->text($input->post->contactname);
$np->name = $np->title;
$np->contactname = $sanitizer->text($input->post->contactname);
$np->email = $sanitizer->email($input->post->email);
$np->comments = $sanitizer->textarea($input->post->comments);
$np->save();

// Run photo upload
foreach($files as $filename) {
$pathname = $upload_path . $filename;
$np->contact_photo->add($pathname);
$np->message("Added file: $filename");
unlink($pathname);
}

// Save page again
$np->save(); ?>

<p>Thank you for your contact information.</p>

<?php return true;
}

else { ?>
<p> Sorry, your photo upload was not successful...</P>
<?php } ?>


Replace the field references with your own field names, make sure to change the various paths to match yours, and change the various messages to be what you need for your project.

Read the entire discussion to see how we worked through getting to the solution shown above.

Thanks,
Matthew

  • Like 9

Share this post


Link to post
Share on other sites

You have written contest_photo instead of contact_photo at the beginning. Not sure if this solves your issue. Sorry on mobile...

  • Like 2

Share this post


Link to post
Share on other sites

Hey Wanze,

Yes, that shows you have a good eye for sure!

Unfortunately, that was just an error from me transferring the text to the forum... I edited the forms in my first post and fixed that word.

In other words, it still doesn't work.

Any other ideas?

Thanks,

Matthew

Share this post


Link to post
Share on other sites

$contact_photo->setDestinationPath($upload_path);

I could be overlooking it (late here), but I don't see $upload_path defined anywhere.

Share this post


Link to post
Share on other sites

Hey renobird,

Late here too, but difficult to sleep when working on a ProcessWire site!

You are correct... I was missing that piece!  Definitely, that should be there.

I added it, and holding my breath I tried the form again.  But it still doesn't work.  Same result: no errors, and we see the "success" page, but the new page does not appear in the page tree.

Other suggestions or ideas?

Thanks,

Matthew

PS: I've edited my post above to keep track of changes.  That way, when this discussion is done, there will be a complete example for others to reference.

  • Like 1

Share this post


Link to post
Share on other sites
$upload_path = "/site/assets/files/temp/";

I think the path is not correct, it's more an "url".

The complete path usually starts with the folder your site's in (public_html/www).

Try this:

$upload_path = $config->paths->assets . 'files/temp/';

And have you debug mode turned on to see any errors?

Cheers

Share this post


Link to post
Share on other sites

Greetings,

To renobird: Yes, I am basing my work on Soma's code.  But because I have more fields than just a file upload, I have to re-work the original code.  In my code above, you can see that what I have looks like Soma's code, but with the other fields included.

$upload_path = "/site/assets/files/temp/";

I think the path is not correct, it's more an "url".

The complete path usually starts with the folder your site's in (public_html/www).

Try this:

$upload_path = $config->paths->assets . 'files/temp/';

And have you debug mode turned on to see any errors?

I fixed the path reference (updated my post above).  But still no luck.  The page is not being created.  And no errors are being reported.

Based on a comment from Ryan in a related discussion, I wonder if I am simply saving the page at the wrong stage?

Here's the related discussion: http://processwire.com/talk/topic/2997-uploading-a-new-photo-to-a-member-profile-avatar-field/#entry30621

I really want to have a full, public example of how to put file uploads in a form with other fields, so I am hoping this discussion can become a live working out of the details.

Thanks,

Matthew

Share this post


Link to post
Share on other sites

I have a working example - doing essentially what you are after. I'll compare to yours when I get back to the office (on mobile now) and see if can spot the issue.

Share this post


Link to post
Share on other sites

Not the ideal way to debug like this code in a forum. Nothing against anyone personally. Now the code lost intendation and no way to go through it.

Please post code to some snippet site like Gist or bitbucket.

In general, we should provide some more practice and best ways HOW TO DEBUG YOUR CODE. Good coding is learning how to debug. There's simple steps you can go through to test all vars and parts of code to see where the problem lays. Sometimes it's simple sometimes it can get hard, as you when you don't have errors.

Ok.

What I spotted too is the last bit, where is the $u->getErrors() coming from?

Also as you say the page isn't created at all? I would start there and get that right first and work you way up.

Thanks,

Soma

  • Like 2

Share this post


Link to post
Share on other sites

Hey Soma,

I know what you're saying, but I wanted to use the forum as a way to work out what the general idea should be.  Ideally, it would be great to have things like this all in Github, but I think we often need to use a forum this way.  It's a more direct way -- in the end -- to have code that everyone here can use for their sites.

I think having a full working example of a form with various fields as well as file-uploads would be great for the forum.

Good catch on the $u->getErrors()... Yes, that should be $contest_photo->getErrors()

However... It still doesn't work.

I'm sure we'll solve this!

Thanks,

Matthew

Share this post


Link to post
Share on other sites

Matthew,

have you debug mode enabled to see PHP errors/warnings?

Also can you do a print_r($_FILES); to check if the PHP $_FILES array isn't empty?

Maybe the file isn't sent at all to the server.

Share this post


Link to post
Share on other sites

I also know what you're saying, but I have to strongly disagree. I could've write this in any other similar thread.

The problem is the code posted in a wysiwyg is "horrible" to read and even copy it.

Then after this is working (as with 1000 other code here in the forum), there comes the next who takes this code but need another feature.. then the game start again with same story same code but different bugs issues.

What I would like to do is helping how to code and debug, not have 1 million snippets that are sometimes very bad coded and not complete best practice or not even working spooking around the forum. It already happened many times and it will get worse by time. I know what you're wanting to do and I understand, but in the long run what we are practicing here since 2 years is very bad for newcomers. We better this energy and time to help with little tutorials and snippets that are good to start with in a dedicated site/place.

  • Like 3

Share this post


Link to post
Share on other sites

Hey Soma,

I get you!  I really do...  As someone who is attempting to document how to do things, it is difficult when there are pieces here and there for larger routines.  For example, with file-uploads and front-end forms in general, there are isolated chunks throughout the forum, and putting it all together as a single file can be difficult.  My goal with this discussion is to consolidate a whole routine in one coherent file.

For sure, your points about better ways to discuss such code is worthy of a larger discussion!  And yet, forums like this often have bits of code (many times, they are more than just "bits").  In fact, if you remove the code from a forum like this, what's left to discuss?

If I were to move this to GitHub, would it be as valuable to the ProcessWire community?

Thanks,

Matthew

Share this post


Link to post
Share on other sites

I didn't say move this discussion to github, but the snippet maybe?

Share this post


Link to post
Share on other sites

Im saying gist.github.com not github itself :-)

Share this post


Link to post
Share on other sites

Greetings,

OK, Soma, here's my gist for this subject: https://gist.github.com/MatthewSchenker/5205927

I hope this can make it easier and more productive to work this out -- and better for everyone to use.

Also, maybe this can be a spark that gets more of us to Github to work out our code?

Thanks,

Matthew

  • Like 1

Share this post


Link to post
Share on other sites

Much better... and just now I spoted (starting from top)  an error

if ($input->get->contactname){

Your form is method post and not get!

So you would have easily spoted this already if you add an pseudo echo "Hello" after the if() to see it gets to after the check. As I said it's really simple if you go step by step and output vars to test and see if it really get's there. 

Share this post


Link to post
Share on other sites

Hi Soma,

I used "GET" for the original form (the one with no file uploads).  I then switched to "POST" for the one with file uploads.  But to make it easier, I will switch all of them to the "POST" method.

Thanks,

Matthew

Share this post


Link to post
Share on other sites

Dont want to be mean but have to say that I already built multiple working front end form examples that work. The one Reno linked would be what you do. So this is not so much about making a working example but to help you debug your code you messed up. :-P #hides behind stone#

Of course yours has some more fields, but there's no validation happen on those, which I think should be the lesson here. To make it easy on this subject I would suggest looking at my other front end forms using PW forms and field that will make it more streamlined and easy. Its also in my gists examples.

Share this post


Link to post
Share on other sites

Hey Soma,

Yes, I admit the code I posted has problems.  I just can't seem to pinpoint the problem because building these kinds of forms gets into a lot of PW-specific steps.  I haven't seen any examples to follow for forms with image-upload fields along with "regular" fields.

I actually based my code above on your very helpful gist for uploading images to newly created pages (https://gist.github.com/somatonic/4150974).  But somewhere in the process of mixing in "regular" fields with the image upload requirements, something is off.

I realize I must be doing something wrong, but I can't tell what.

I'm hoping in the end we'll have a working example of how to do this that can be beneficial to others, since I know other need (or will need) to do this.

Thanks,

Matthew

Share this post


Link to post
Share on other sites

Hi Matthew,

have you tried my debugging steps? =)

Matthew,


have you debug mode enabled to see PHP errors/warnings?


Also can you do a print_r($_FILES); to check if the PHP $_FILES array isn't empty?


Maybe the file isn't sent at all to the server at all.

Share this post


Link to post
Share on other sites

Greetings Wanze,

Sorry, I meant to respond to that earlier.

Yes, I am seeing a result from that.  For example, I uploaded a photo called "cloudphoto.jpg.  Here's the message I'm seeing:

Array ( [contact_photo] => Array ( [name] => cloudphoto.jpg [type] => image/jpeg [tmp_name] => /tmp/phpdRhJLN [error] => 0 [size] => 1864092 ) ) 

Thanks,

Matthew

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By louisstephens
      So I reread my first draft, and it made absolutely no sense (I deleted it to hopefully better explain myself).  I am trying to make a system (that to me is a bit complicated) utilizing jquery and processwire together. My whole goal is to put a url like https://domain.com/launch?first_name=jim&occupation=builder in a script tag on another site(just a localhost .php page) to then pull out the data for that person and append to divs etc. Basically, the initial script tag would point to "launch" which has a content-type of "application/javascript". Using jquery, I would pull out the persons name and occupation and then make a specific ajax get request to "domain.com/api" (in json format) for a look up of the person. Essentially then I could pull that particular person's information from the json data, and do with it how I please in the "launch" page.  In processwire, I have a page structure like:
      People -Jim Bob (template: person ) --Occupations (template: basic-page) ---Builder (template: occupation) ---Greeter (template: occupation) It is really just a bunch of people with their occupations and a few fields to the occupation template. With the "api" (template: api) url, I was hoping to return all the data (of people) in json format like:
      Example Format:
      { "id": 1, "title": "Jim Bob", "occupations": { "builder": { "id": 44, "title": "Builder", "years_worked": 1, "etc": "ect", }, "Greeter": { "id": 44, "title": "Greeter", "years_worked": 1, "etc": "ect", }, } } Where I get lost is really outputting the page names and nesting in the occupations into json. I have used Pages2JSON before, but I was a bit lost on how to implement what i was thinking.
       
      I have access to all the local host files, but I was hoping to kind of build out a "system" where I could place the script tag/parameters in any project, and be able to interact with the data without doing an ajax call on the actual site. In a way, this would keep processwire handling all the data and requests, and my other "projects" just with a simple script tag. This might all be way too much/over complicated, but I couldn't quite wrap my head around how to achieve it. 
    • By pwFoo
      How to enable urlSegments runtime instead of persistent in template settings? And where to be loaded before the current page returns a 404 error?
      https://processwire.com/docs/front-end/how-to-use-url-segments/#how-do-you-enable-url-segments
       
    • By Ivo
      Hi Folks,
      This PW site https://ancientlakesmagnesium.com.au/ currently runs Snipcart. Products are built in PW pages but the cart and checkout is managed by Snipcart. Snipcart adds new products to its inventory when first added to the cart, thus a copy of the product catalog is on the Snipcart account. My Client manages all the sales/transactions on Snipcart. The problem is Snipcart is limited, my client wishes to connect to smile.io which is much cheaper to do with a pre-built Shopify app and to have PayPal Subscriptions. Snipcart is showing to be limited in several things now that their business has grown.  
       
      My question is, has anyone had success plugging in products from PW pages into Shopify via the Shopify API? I spoke to Shopify support and they pointed me to the one post in this forum, but it doesn't give any detailed instructions and it quite old now. My other option is to build a Shopify system as a sub domain and somehow build an app that mirrors the menu structure on the PW site so that the user doesn't have to maintain 2 menus. 
       
      If anyone has any suggestions that would be most appreciated.
       
      cheers,
      Ivo
    • By VeiJari
      Hello forum! 
      I started to write my first hook for Processwire but I'm pretty confused how you should write these. My idea is to hook after publishing in init.php (called before templates)  for a certain template. 
       
      Here's the code: 

      Trying to reset the checkbox (ajasta) and then saving it so it shows unchecked in the admin page when publishing "article" page. 
      But the code isn't doing anything. Not even dumping anything
      What seems to be the problem? And have you made a similar hook for this usage or am I doing it totally wrong? 😄
      Thanks for the support in advance!
    • By EyeDentify
      Hello Gentlemen and Ladies.

      I have not posted for a while but now i need your help figuring out some things.
      The Documentation has come a long way and i love it.
      Though on the page:
      https://processwire.com/api/ref/pageimages/

      I am trying to figure out if when i want to add an image to an existing image field with multiple images alldready in it and using the method $page->images->add()
      <?PHP /* get the images object array for the Page */ $myPageImg = $page->images; /* define the image to add */ $newImg = 'http://www.somesite.com/image.jpg'; /* Thanks Autofahrn, forgot about the output formating */ $page->of(false); /* create a new Pageimage object with the given URL and add to the Pageimages array */ $myPageImg->add($newImg); /* save the page */ $page->save(); ?> I am pretty sure i missed a few steps in the code above?
      Is that string suppose to be an URL like "http://www.somesite.com/image.jpg" and the method will automaticly download the image and create an Pageimage Object and add it to Pageimages array or does it have to exist on the host first and i supply a file path to that image?

      I guess im confused about that, hope you guys could clarify that for me.

      And if it needs to be allready downloaded to my host before adding the image, what would be the best API methods for that task?
      Just point me in the right direction and i will figure it out.
      Sorry for the bad explaination but i could not figure out a better way of asking.

      Thanks in advance.
      /EyeDentify
×
×
  • Create New...