I have a content type "mystory" which I want to invite visitors to create in several different ways.
To do this, I want to print the mystory submission form on several different pages, and then theme that form differently on each page.
For example, on one page I want the submission form to be green, have an intro that says "Submit a Green myStory," and I want it to have a dropdown selection field that allows uses to choose from "lime, emerald, or olive." It also needs to have a hidden field set to mark it as a "green" mystory. On another page I'll want to invite users to "Submit a Red myStory" with the appropriate fields.
I'm trying to do this within page-node.tpl.php files: page-node-6.tpl.php will print the green mystory submission form and page-node-7.tpl.php will print the red. I don't want to create separate content types.
This is the code I've got so far:
<?php
global $user;
$node = array(
'uid' => $user->uid,
'name' => $user->name,
'type' => 'mystory',
);
/* I may want to use drupal_render instead, but it doens't seem to work the same... */
$myform = drupal_get_form('mystory_node_form', $node);
print $myform;
?>
Right off the bat it gives me several problems, for example the collapsible form fields no longer work (they print out as plain text rather than as an expandable field.)
When I search for solutions and tutorials I get a lot of instructions that indicate that I should theme forms with either a theme_function or with a module. If possible, I'd like to just put my code in the page-node.tpl.php files. Is there a reason why I shouldn't do that?
And if I do use a module or a theme function, how will I control how the content submission form looks on different pages?
Comments
Two Separate Issues
You are trying to solve two separate issues and each must be handled differently.
Issue 1: Form values
You mention wanting the "green" form to have a certain list of items in the drop down, which is different than the "red" form. You can't just modify the form in your TPL file, since it will no longer match the back-end form that Drupal is expecting to work with.
To do this properly, you must adjust the form using hook_form_alter, or otherwise use a module that does that for you (such as adding fields via CCK).
Forms are a HUGE component of Drupal site-building and a lot of attention is paid to creating and managing them in a proper architecture. It may seem a bit complicated or "heavy" at first, but the Form API is there for a reason - it provides security, stability, reusability and maintainability to your site.
Issue 2: Theming Forms
Changing the form's displayed colors is something handled via CSS. Basically, you need a way to provide a CSS selector path that will identify which form context you are working with. Then, the CSS can apply whatever styles you want.
The description you provided doesn't really give enough detail to understand the best approach for your situation. But the main options for this are:
- Use hook_form_alter to dynamically add class attributes to the form object.
- Use wrapper DIVs (or other HTML elements) to add a class or id that can be used in CSS to apply color dynamically. These would be placed in TPL files like page.tpl.php.
- Use hard-coded CSS selectors. For example, if the forms only ever appear in certain nodes, you -could- use the node as a selector. This isn't the best approach, but it is technically feasible.
- Use JavaScript to apply CSS dynamically at the client level. This relies on users having JS enabled and it doesn't really solve any of the other problems because the JS needs to know the context as well, but it is also technically feasible.
Since you are also changing the form's structure (because of the different drop-down list values) the first approach is really the best. You can change the values AND add a selector at the same time, which solves both problems.
---------------------------------
Steven Wright
Slalom
manipulating default values
On Green form I want a hiddenfield that sets color=green and on Red form I want that hiddenfield to set color=red
hook_form_alter will alter the entire form, right? What I want to do is manipulate the form based on context.
hook_forms
You can use hook_forms to define separate call back functions or arguments.
Reference:
http://api.drupal.org/api/function/hook_forms/6
So, you can define an argument for the color and then the callback function can inspect the argument and modify the form value(s) as desired.
Search Forms uses this hook in this manor:
http://api.drupal.org/api/function/search_forms/6
Note that the callback function is the same, but the argument is different.
---------------------------------
Steven Wright
Slalom
To do this properly, you must adjust the form using hook_form_al
"To do this properly, you must adjust the form using hook_form_alter"
I think this is the concept I'm fighting against. I want to be able to manipulate the form inside page-node-7.tpl.php
What is the something to manipulate the form on the fly? Am I forced to create a module that will manipulate the form if nid=7?
Thanks so much!
Maybe color was a bad example...
The problem I'm having is I want to use to one custom content type to submit content of slightly different flavors.
So I want to use a "Food" content type to submit both vegetables and fruits. I'm going to print the food_node_form on a page called Veggies (nid 6) and on page called Fruits (nid 7).
When I print the food_node_form on the Veggie page I want to set a hidden field to indicate the submission is a veggie, and the likewise for Fruits (as well as some other form manipulations).
diftween drupal_get_form and drupal_retrieve_form?
What is the difference between drupal_get_form and drupal_retrieve_form?
drupal_get_form - Retrieves a form from a builder function, passes it on for processing, and renders the form or redirects to its destination as appropriate. In multi-step form scenarios, it handles properly processing the values using the previous step's form definition, then rendering the requested step for display.
drupal_retrieve_form - Retrieves the structured array that defines a given form.
So drupal_get_form seems to be doing a lot more, but I'm still not really sure what the difference is, and how they should be used in conjunction with drupal_prepare_form and drupal_render_form.
drupal_prepare_form - Prepares a structured form array by adding required elements, executing any hook_form_alter functions, and optionally inserting a validation token to prevent tampering.
drupal_render_form - Renders a structured form array into themed HTML.
drupal_get_form
According to http://api.drupal.org/api/drupal/developer--topics--forms_api.html/5
drupal_get_form does the following:
* Starts the entire form-building process by getting the $form from the builder function
* Translates the $form['name'] items into actual form elements
* Performs any validation and "clean-up" that needs to be done, and calls custom validation functions if declared
* Submits the form if a submit function is declared, and the form has been submitted
* Calls any custom theming functions that have been declared
* Returns an HTML string which contains the actual form.
drupal_get_form actually allows my rendered form to submit, whereas drupal_render_form is currently displaying the form just fine, but does nothing upon submission...
Another way to ask the question
I want to be able to print a single content submission form with fields pre-populated - so I'd like to print a page_node_from where title is preset as "foo" and another page_node_form where title is preset as "bar."
This code works (to edit the title):
However I'm unable to make the leap to setting a CCK field. I don't know how to match the array structure in a way that Drupal understands and can submit.
This code doesn't work:
finally lucked into a solution
This code seems to work:
Another (potential) solution
There may be hints to another type of solution here: http://www.lullabot.com/articles/photo-galleries-views-attach using node_reference. But the video is for Drupal 6, not 5
don't need to use css to hide form elements
how to redirect now?
Now I'm stuck trying to figure out how to set the redirect...
Either the $form['#action'] or the drupal_render_form trumps what I set $form['#redirect'] as. The dsm function print out shows [#redirect] set the same as it would if I used a module to set the #redirect, but with the module it works and with my php snippet it don't...
Is there anyway I can set a redirect inside the snippet I have above? Can I pass it inside the drupal_render_form function?
$form['#action'] and $form['#redirect']
yeah the problem is that
$form['#action'] = '/node/add/'.$type;
trumps the $form['#redirect']
Which means that I can set one redirect for all forms that submit that content $type - but I don't know how to make one form that redirects to /foo and another to /bar
solution is &destination
Solution $form['#action'] = '/node/add/'.$type.'&destination=mystory/thankyou';
Note that the Drupal community thinks that creating forms in nodes or tpls is really bad form and probably not a good idea. But here's how I did it.
Some general thoughts
1. tpl.php files are useful for customizing how a node is *viewed*. Use hook_theme and hook_form_alter to modify how node looks during *add/edit* operations. These latter two functions are passed the underlying $form as a parameter. See http://www.lullabot.com/articles/modifying-forms-5-and-6 for good examples.
2. Consider using a page preprocessor to add a body class whose value is the same as the hidden story type and then use CSS to handle background colors.
3. Use hook_form_alter to set title, intro text and to replace a cck text field with a dropdown whose options are based on the value in the hidden field.
4. Use hook_menu to define /node/add/mystory/% where the % can be red, green, etc. Consider using the http://drupal.org/project/prepopulate for this.
thanks for help
I want to use php inside a node or tpl - if at all possible I do not want to have to use a module to do this.
I know that I can use a module, but I really, really, really don't want to. Surprised at the nearly universal insistence that this be done with a module.
Insistence = Correct
We are all advising you to use a module because it's the correct solution based on Drupal architecture.
Modifying a form in a tpl is, fundamentally, a hack. Sure, you can do it and accomplish some results, but you're accepting serious trade-offs and handicapping the power of a framework that you're investing your time and energy into.
If you want a Drupal-agnostic argument: modifying the form in the TPL file breaks the separation between your controlling logic and your display logic. You're now mixing back-end functional architecture code with your user interface code. Typically, you want to avoid such overlap as much as possible - this is near-universal and well-tested development theory.
Again, I strongly urge you to read up on the Form API and understand how it really works - everything you're asking for can be done, if it's done the right way.
---------------------------------
Steven Wright
Slalom
Drupal 5 Form Rendered in Node
hello all, I've stumbled
hello all,
I've stumbled onto this post trying to do something similar.
In this case I need to build a form with dynamic input fields (i.e. fields based on CCK field numbers/values).
To do so, I need access to variables contained in the $node object...which makes me want to code the whole form in the node.tpl.php file.
However as per stevenc's post, I know this is not proper dev form. However, I am at a loss for what direction to take and how to make node-specific variables available to add fields to my custom form.
any insight appreciated