Jump to content

How do you get a frontend form to create a new page with the template fields from a specific page?


Marc
 Share

Recommended Posts

I am trying to do the following: create a frontend form that generates a new page that has the fields from a template that a specific page uses. I send the page ID to the form and get the correct template and its fields from there. The presentation part of this form works, but as soon as it is trying to save, the $form variable does not contain the fields from the specified template so it saves a new page without any fields. Here's what I've got so far, hopefully anybody can tell me what I'm doing wrong (I've got most of this code from examples found on this forum):

$page_id = htmlspecialchars($_POST['select_product']); // page ID
$page = $pages->get($page_id);
$template = $page->template; // this is the template where we will get the fields from

// make a form
$form = $modules->get('InputfieldForm');
$form->method = 'post';
$form->action = './';
$form->attr("id+name",'subscribe-form');

// add the page's fields to the form
$fields = $page->fieldgroup;
foreach($fields as $field) {
    $inputfield = $fields->get("$field->name")->getInputfield($page);
    $form->append($inputfield);
}

// add template name field to the form
$field = $modules->get("InputfieldHidden");
$field->label = "Template";
$field->attr('id+name','template_name');
$field->required = 1;
$field->value = $template;
$form->append($field); // append the field

// add a submit button to the form
$submit = $modules->get('InputfieldSubmit'); 
$submit->name = 'save_new_aanvraag';
$submit->attr("value", "Go");
$form->append($submit); 

// process the form if it was submitted
if($this->input->post->save_new_aanvraag) {
	// now we assume the form has been submitted.
    // tell the form to process input from the post vars.
    $form->processInput($this->input->post);

    // see if any errors occurred
    if( count( $form->getErrors() )) {
        // re-render the form, it will include the error messages
        echo $form->render();
    } else {
        // successful form submission
        $p = new Page(); // create new page object
   		$p->template = $input->post->template_name; // set template
    	$p->parent = $pages->get('/aanvraag/'); // set the parent

        foreach($form as $field) {
            $p->set($field->name, $field->value);
        }
    	$p->save(); //create the page

        echo "<p>Page saved.</p>";
    }
} else {
    echo $form->render();
}
Link to comment
Share on other sites

Hi Marc

Here a few things I see that need fixing:

$page_id = htmlspecialchars($_POST['select_product']); // page ID

You should use (int) instead of htmlspecialchars - that is the safest way to sanitize a page id.

You shouldn't overwrite $page, so change:

$page = $pages->get($page_id);

to:

$p = $pages->get($page_id);

I think you want:

$template = $page->template; // this is the template where we will get the fields from

to be:

$template = $page->template->name; // this is the template where we will get the fields from

That will mean that your hidden field is storing the name of the template, rather than the template object.

Also, you are using:

$form->processInput($this->input->post);

But then still using:

$p->template = $input->post->template_name; // set template

when you could be using:

$p->template = $form->get("template_name"); // set template

Hopefully that should get things working for you, although it is only:

$template = $page->template->name;

that is critical.

  • Like 4
Link to comment
Share on other sites

Hi Marc

Here a few things I see that need fixing:

First, thank you for your help, much appreciated. I did the changed you mentioned, but it is still not quite working. Here's what I've got right now:

$page_id = (int) $_POST['select_product']; // page ID
$p = $pages->get($page_id);
$template = $p->template->name; // this is the template where we will get the fields from

// make a form
$form = $modules->get('InputfieldForm');
$form->method = 'post';
$form->action = './';
$form->attr("id+name",'subscribe-form');

// add the page's fields to the form
$fields = $p->fieldgroup;
foreach($fields as $field) {
    $inputfield = $fields->get("$field->name")->getInputfield($page);
    $form->append($inputfield);
}

// add template name field to the form
$field = $modules->get("InputfieldHidden");
$field->label = "Template";
$field->attr('id+name','template_name');
$field->required = 1;
$field->value = $template;
$form->append($field); // append the field

// add a submit button to the form
$submit = $modules->get('InputfieldSubmit'); 
$submit->name = 'save_new_aanvraag';
$submit->attr("value", "Go");
$form->append($submit); 

// process the form if it was submitted
if($this->input->post->save_new_aanvraag) {
	// now we assume the form has been submitted.
    // tell the form to process input from the post vars.
    $form->processInput($this->input->post);

    // see if any errors occurred
    if( count( $form->getErrors() )) {
        // re-render the form, it will include the error messages
        echo $form->render();
    } else {
        // successful form submission
        $p = new Page(); // create new page object
   		$p->template = $form->get("template_name")->value; // set template
    	$p->parent = $pages->get('/aanvraag/'); // set the parent

        foreach($form as $field) {
            $p->set($field->name, $field->value);
        }
    	$p->save(); //create the page

        echo "<p>Page saved.</p>";
    }
} else {
    echo $form->render();
}

I renamed $page to $p, and as an addition to your suggestions I also changed this line:

// add the page's fields to the form
$fields = $p->fieldgroup;

That is because I need the fields from $p, not $page. However, the fields are not added to $form and so they are not saved. So I'm guessing this part needs to change:

 
// add the page's fields to the form
$fields = $p->fieldgroup;
foreach($fields as $field) {
    $inputfield = $fields->get("$field->name")->getInputfield($p);
    $form->append($inputfield);
}
Link to comment
Share on other sites

I think the building of the form the way you are doing should work, and I think it is, correct? But just for something a little cleaner, this is how I always do it:

$p = $pages->get($page_id);

// make a form
$form = $modules->get('InputfieldForm');
$form->method = 'post';
$form->action = './';
$form->attr("id+name",'subscribe-form');

$fields = $p->getInputfields();
foreach($fields as $field){
    $form->append($field);
}
echo $form->render();

Now to the issue of the fields not being added to the new page:

It shouldn't matter, but to be more obvious, I would call your new page: $np

This should do what you need - you need to iterate through the fields of the new page.

$np = new Page();
$np->template = $form->get("template_name")->value; // set template
$np->parent = $pages->get('/aanvraag/'); // set the parent
$np->of(false); // turn off output formatting before setting values

foreach($np->fields as $f) {
$np->set($f->name, $form->get($f->name)->value);
}
$np->save();
  • Like 4
Link to comment
Share on other sites

I think the building of the form the way you are doing should work, and I think it is, correct? 

Well it is saving a new page, but it's empty still, no fields. I made the edits you suggested:

$page_id = (int) $_POST['select_product']; // page ID
$p = $pages->get($page_id);
$template = $p->template->name; // this is the template where we will get the fields from

// make a form
$form = $modules->get('InputfieldForm');
$form->method = 'post';
$form->action = './';
$form->attr("id+name",'subscribe-form');

// add the page's fields to the form
$fields = $p->getInputfields();
foreach($fields as $field) {
    $form->append($field);
}

// add template name field to the form
$field = $modules->get("InputfieldHidden");
$field->label = "Template";
$field->attr('id+name','template_name');
$field->required = 1;
$field->value = $template;
$form->append($field); // append the field

// add a submit button to the form
$submit = $modules->get('InputfieldSubmit'); 
$submit->name = 'save_new_aanvraag';
$submit->attr("value", "Go");
$form->append($submit); 

// process the form if it was submitted
if($this->input->post->save_new_aanvraag) {
	// now we assume the form has been submitted.
    // tell the form to process input from the post vars.
    $form->processInput($this->input->post);

    // see if any errors occurred
    if( count( $form->getErrors() )) {
        // re-render the form, it will include the error messages
        echo $form->render();
    } else {
        // successful form submission
        $np = new Page(); // create new page object
   		$np->template = $form->get("template_name")->value; // set template
    	$np->parent = $pages->get('/aanvraag/'); // set the parent
        $np->of(false); // turn off output formatting before setting values

        foreach($np->fields as $f) {
            $np->set($f->name, $form->get($f->name)->value);
        }
    	$np->save(); //create the page

        echo "<p>Page saved.</p>";
    }
} else {
    echo $form->render();
}

When saving the page, I get this error: "Trying to get property of non-object". That refers to line 49. Also, the way you suggested doing this part:

// add the page's fields to the form
$fields = $p->getInputfields();
foreach($fields as $field) {
    $form->append($field);
}

it's filling out the fields with the values of the $page_id that I'm requesting, but I don't want its values, just its empty fields?

Link to comment
Share on other sites

Sorry about all that - shouldn't try offering advise with browser written code. This works fine for me:

$page_id = (int) $input->post->select_product; // page ID
$p = $pages->get($page_id);
$template = $p->template->name; // this is the template where we will get the fields from

// make a form
$form = $modules->get('InputfieldForm');
$form->method = 'post';
$form->action = './';
$form->attr("id+name",'subscribe-form');

// add the page's fields to the form
$fields = $p->fieldgroup;
foreach($fields as $field) {
    $inputfield = $fields->{$field->name}->getInputfield($p);
    $form->append($inputfield);
}

// add template name field to the form
$field = $modules->get("InputfieldHidden");
$field->attr('id', 'Inputfield_template_name');
$field->attr('name', 'template_name');
$field->value = $template;
$form->append($field); // append the field

// add a submit button to the form
$submit = $modules->get('InputfieldSubmit');
$submit->name = 'save_new_aanvraag';
$submit->attr("value", "Go");
$form->append($submit);

// process the form if it was submitted
if($this->input->post->save_new_aanvraag) {
    // now we assume the form has been submitted.
    // tell the form to process input from the post vars.
    $form->processInput($this->input->post);

    // see if any errors occurred
    if( count( $form->getErrors() )) {
        // re-render the form, it will include the error messages
        echo $form->render();
    } else {
        // successful form submission
        $np = new Page(); // create new page object
        $np->template = $form->get("template_name")->value; // set template
        $np->parent = $pages->get('/aanvraag/'); // set the parent
        $np->of(false); // turn off output formatting before setting values
        $np->save();

        foreach($np->fields as $f) {
            $np->set($f->name, $form->get($f->name)->value);
        }
        $np->save(); //create the page

        echo "<p>Page saved.</p>";
    }
} else {
    echo $form->render();
}
The one thing missing is sanitizing of user input. You should read through: http://processwire.com/api/variables/sanitizer/
 
Link to comment
Share on other sites

Sorry about all that - shouldn't try offering advise with browser written code. This works fine for me:

Are you sure? I copy-pasted your code and I get the same error: "trying to get property of non-object", referring to $np->set($f->name, $form->get($f->name)->value);

I noticed you added an extra $np->save, which makes sense, I reckon you are supposed to save the new page before added the field values to it. Strange how it is still not working for me, a new page is created with the correct parent and template, but the fields are empty and the page title is a date/time...

Link to comment
Share on other sites

Definitely working for me, but it sounds like you problem might be that the template from the page that is being used to create the form doesn't have a title field. Is that right?

You need to give a page a title or at least a name - name will be created from the title if it is provided, but the name isn't. How are you planning on setting the name/title for the created pages?

Have you tried debugging what part of that line is causing the error? Is it $f->name or $form->get($f->name)->value - try replacing each one with fixed values to see where the problem actually is.

Yes you are right - you need to save the page before adding fields to it. Are you making use of the automatic page name option? Is that why it is being given a title of date/time?

Link to comment
Share on other sites

Yes my template has a title field, in fact it only has 2 fields, 'title' and 'email'. I tried with the basic page template as well, same error. I also tried your suggestion about debugging the line that the error refers to, and it's $form->get($f->name)->value that seems to be the problem. If I replace it with a simple string, the page title is set to the string value instead of the current date/time.

I did not know about the automatic page name option before now, but I think that's not it. 

I really do appreciate your help and patience by the way, what a helpful community this is  :)

Link to comment
Share on other sites

Well I am trying - wish I wasn't failing you though :)

One thing I just noticed is that you can remove all occurrences of $this - with this code in a template, you just need $input->post......

I have no idea why this would make a difference, but have you tried:

$np->set($f->name, $input->post->{$f->name});

Both work for me, and the $form way is better, but thought this might help us debug.

  • Like 1
Link to comment
Share on other sites

So I restructured the code a bit and also added some validation and sanitising, and the part that did not work before ($np->set($f->name, $form->get($f->name)->value);) started working  ^-^

Did I do the validation and sanitising parts correctly? Or are there more efficient/better ways of doing this? Here's the fully working code:

$page_id = (int) $input->post->select_product; // page ID

if ($page_id) {
    $p = $pages->get($page_id);
    $template = $p->template->name; // this is the template where we will get the fields from

    // make a form
    $form = $modules->get('InputfieldForm');
    $form->method = 'post';
    $form->action = './';
    $form->attr("id+name",'subscribe-form');

    // add the page's fields to the form
    $fields = $p->fieldgroup;
    foreach ($fields as $field) {
        $inputfield = $fields->{$field->name}->getInputfield($p);
        $form->append($inputfield);
    }

    // add template name field to the form
    $field = $modules->get("InputfieldHidden");
    $field->attr('id', 'Inputfield_template_name');
    $field->attr('name', 'template_name');
    $field->value = $template;
    $form->append($field); // append the field

    // add select_product to the form
    $field = $modules->get("InputfieldHidden");
    $field->attr('id', 'select_product');
    $field->attr('name', 'select_product');
    $field->value = 1156;
    $form->append($field); // append the field

    // add a submit button to the form
    $submit = $modules->get('InputfieldSubmit');
    $submit->name = 'save_new_aanvraag';
    $submit->attr("value", "Go");
    $form->append($submit);

    // only show the form if it was not just submitted/processed
    if (!$input->post->save_new_aanvraag)
        echo $form->render();
}

// process the form if it was submitted
if ($input->post->save_new_aanvraag) {
    // now we assume the form has been submitted.
    // tell the form to process input from the post vars.
    $form->processInput($input->post);

    // validation
    $email = $form->get("email");
    if ($email && (strpos($email->value,'@hotmail') !== FALSE)) { 
        // attach an error and it will get displayed along the field
        $email->error("Sorry we don't accept hotmail addresses for now.");
    }

    // see if any errors occurred
    if (count( $form->getErrors() )) {
        // re-render the form, it will include the error messages
        echo $form->render();
    } else {
        // successful form submission
        $np = new Page(); // create new page object
        $np->template = $form->get("template_name")->value; // set template
        $np->parent = $pages->get('/aanvraag/'); // set the parent
        $np->of(false); // turn off output formatting before setting values
        $np->save();

        foreach ($np->fields as $f) {
            $inputval = $form->get($f->name)->value;
            // sanitize fields
            if ($f->type == 'FieldtypePageTitle') {
                $sanitizer->text($inputval);
                // also set page name based on title
                $np->set('name', $sanitizer->pageName($inputval));
            }
            if ($f->type == 'Email') $sanitizer->email($inputval);
            if ($f->type == 'Text') $sanitizer->text($inputval);
            if ($f->type == 'Textarea') $sanitizer->textarea($inputval);
            if ($f->type == 'Integer') $inputval = (int) $inputval;

            // attach fields to page
            $np->set($f->name, $inputval);
        }

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

        echo "<p>Page saved.</p>";
    }
} else {
    //echo $form->render();
}
  • Like 2
Link to comment
Share on other sites

Looks pretty good to me. A couple of things though:

  1.  if ($f->type == 'Email') etc should be  if ($f->type == 'FieldtypeEmail') - at the moment those won't be triggered at all.
  2. I think you should change though is to add "true" as the second argument for the pageName. This might not be necessary depending on the input, but I don't think it hurts.

Glad you got it all working in the end!

  • Like 1
Link to comment
Share on other sites

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

×
×
  • Create New...