function hook_form

You are here

7 node.api.php hook_form($node, &$form_state)
4.6 node.php hook_form(&$node, &$param)
4.7 node.php hook_form(&$node)
5 node.php hook_form(&$node, $form_values)
6 node.php hook_form(&$node, $form_state)

Display a node editing form.

This hook, implemented by node modules, is called to retrieve the form that is displayed to create or edit a node. This form is displayed at path node/add/[node type] or node/[node ID]/edit.

The submit and preview buttons, administrative and display controls, and sections added by other modules (such as path settings, menu settings, comment settings, and fields managed by the Field UI module) are displayed automatically by the node module. This hook just needs to return the node title and form editing fields specific to the node type.

Parameters

$node: The node being added or edited.

$form_state: The form state array.

Return value

An array containing the title and any custom form elements to be displayed in the node editing form.

Related topics

195 functions implement hook_form()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

aggregator_admin_form in modules/aggregator/aggregator.admin.inc
Form constructor for the aggregator system settings.
aggregator_page_category_form in modules/aggregator/aggregator.pages.inc
Page callback: Displays a form containing items aggregated in a category.
aggregator_page_source_form in modules/aggregator/aggregator.pages.inc
Page callback: Displays a form with all items captured from a feed.
ajax_forms_test_ajax_commands_form in modules/simpletest/tests/ajax_forms_test.module
Form to display the Ajax Commands.
ajax_forms_test_lazy_load_form in modules/simpletest/tests/ajax_forms_test.module
Form builder: Builds a form that triggers a simple AJAX callback.

... See full list

1 invocation of hook_form()
field_attach_form in modules/field/field.attach.inc
Add form elements for all fields for an entity to a form structure.

File

modules/node/node.api.php, line 1113
Hooks provided by the Node module.

Code

function hook_form($node, &$form_state) {
  $type = node_type_get_type($node);

  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => check_plain($type->title_label),
    '#default_value' => !empty($node->title) ? $node->title : '',
    '#required' => TRUE,
    '#weight' => -5,
  );

  $form['field1'] = array(
    '#type' => 'textfield',
    '#title' => t('Custom field'),
    '#default_value' => $node->field1,
    '#maxlength' => 127,
  );
  $form['selectbox'] = array(
    '#type' => 'select',
    '#title' => t('Select box'),
    '#default_value' => $node->selectbox,
    '#options' => array(
      1 => 'Option A',
      2 => 'Option B',
      3 => 'Option C',
    ),
    '#description' => t('Choose an option.'),
  );

  return $form;
}

Comments

The page above implies that you need to add form elements to see the title and the body but that's not quite right. You need to add the form elements to get a title field but body is inserted automatically by the Field API.

What it neglects to tell you is that if you want a body with your custom node type, you need to add a body field to it in your modules install file with an implementation of hook_install like the following:

<?php
function mynodetype_install() {
 
// Ensure the node type is available.
 
node_types_rebuild();
 
$types = node_type_get_types();
 
node_add_body_field($types['mynodetype'], 'Body input label');
}
?>

With that in your install, the body field will be put in your node's edit / add form automatically.

For Drupal 6 the function equivalent to
node_type_get_type($node)
is
node_get_types('type', $node)

I don't think that node_example.module uses this in Drupal 7. I think that this is because all form elements are supplied by the attached fields, so this hook is not needed.

I'm quite sure you're right.
Remember to file an issue instead of commenting here if you think you've found something wrong with the documentation.(I've done it for this case)

Cheers

It has taken me a very long time to figure out how to get this to work, but thanks to jhodgdon, I managed to figure it out. It seemed appropriate for me to post a small example module here, FYI:

contenttypetest.info:

name = Contenttype test
description = Test - how can I create a new content type with hook form?
core = 7.x
files[] = contenttypetest.module;
files[] = contenttypetest.install;

contenttypetest.module:

<?php
   
// hook_form implementation
   
function contenttypetest_form($node, &$form_state) {
       
$form = array();

       

$form['contenttypetest_pass'] = array(
           
'#type' => 'password',
           
'#title' => t('Type a password'),
           
'#description' => t('You can type anything you like.'),
        );
       
$form['contenttypetest_veld'] = array(
           
'#type' => 'file',
           
'#description' => 'You might wanna upload a file!',
           
'#title' => 'Bestand',
        );
        return
$form;
    }

   

// hook_node_info() implementation
   
function contenttypetest_node_info() {
        return array(
           
'contenttypetest' => array(
               
'name' => t('Content type test node'),
               
'base' => 'contenttypetest',
               
'module' => 'contenttypetest',
               
'description' => t("This nodetype is a test how to create nodetypes."),
               
'help' => 'So this is how your new contenttype looks!',
               
'title_label' => t('Test'),
               
'has_body' => FALSE,
            ),
        );
    }

   

// hook_validate() implementation
   
function contenttypetest_validate(){
       
    }
?>

contenttypetest.install:

<?php
   
// hook_uninstall() implementation
   
function contenttypetest_uninstall(){
       
node_type_delete('contenttypetest_node');
    }
?>

Thanks for that example. Exactly what I was looking for!

Thanks for this example.

I found that you should pass the content type name exactly as it appears in your hook_node_info to the node_type_delte function.

Correction:

<?php
   
// hook_uninstall() implementation
   
function contenttypetest_uninstall(){
       
node_type_delete('contenttypetest');
    }
?>

This should work fine

That is awesome.

Plz let me knw how to implement hook_form in custom modules

The most braindead way of doing it is the way blog.module does it:

function blog_form($node, $form_state) {
  return node_content_form($node, $form_state);
}

This is useful because at the moment the node system demands that you implement hook_form().

i want form for my node ? i create form in drupal 6 not problem but in drupal 7 i can't how to?

this code form in drupal 6

<?php
function adv_form(){
 
$form_state = array();
 
$nodeType = 'adv';
// create a string of the $form_id
 
$form_id = $nodeType.'_node_form';
// create a basic $node array
  
if ( (is_numeric( arg(1) )) && (arg(2) == 'edit')) {
   
$node = node_load(arg(1));
   }else{
      
$node = array('type' => $nodeType, 'uid' => $GLOBALS['user']->uid, 'name' => $GLOBALS['user']->name);
    }
 
// load the $form
  
$form = drupal_retrieve_form($form_id, $form_state, $node);
  
// prepare the $form
  
drupal_prepare_form($form_id, $form, $form_state);
 
//modify submit button for redirection after save node
   
$form['buttons']['submit'] = array(
       
'#type' => 'submit',
       
'#value' => t('Save'),
       
'#weight' => 5,
       
'#submit' => array('public_form_submit'),
    );
  
$form['#theme'] = 'adv_form';
  
$form['#redirect'] = 'control_panel';
  return
$form;
}
?>

... where you'll find complete lists of available #types of element etc etc, along with all the appropriate attributes for each: forms_api_reference.html

It's interesting to note that you need to implement this function for the custom 'content/node type' to show up for editing under 'admin/structure/types'. Discovered this while implementing a custom node type step by step.

I've been trying to figure out how to override the behaviour from clicking save or preview on a form rendered via the hook_form method.

So far I have this:
mc.module

<?php
function mc_form() {
...
   
$form['#submit'] = array('_mc_form_submit');
...
}

function

_mc_form_submit($form,&$form_state) {
   
$node = ...;
   
/* do some stuff with node */
   
node_save($node);
}
?>

mc.install

<?php
function mc_install() {
    ...
   
// disable the preview button for mc
   
variable_set('node_preview_mc', '0');
    ...
}
?>

But I have the following problem: Some other submit handler is triggered, still no idea which one, no idea how to stop this. This causes the node to be saved twice.

For preview the #submit handler also gets triggered, that's why I disabled the preview possibility in hook_install().

So the real question: Am I doing this right? If so, how do I prevent the second submission. If not, is there a better approach (I need form access, so hook_node_save() and the likes aren't applicable)

As a possible solution to prevent second submission,
I used drupal_goto() statement in _mc_form_submit(), after saving it.
This in combination with no possibility to preview seems to be ok.

<?php
function mc_form_submit($form,&$form_state) {
  
$node = new stdClass;
  
$node->type = 'mc';
  
//more assignments
  
node_save($node);
  
drupal_goto(l('node/'.$node->nid));
}
?>