summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-09-09 23:01:48 +0000
committerDries Buytaert <dries@buytaert.net>2010-09-09 23:01:48 +0000
commiteaee909a00a516d864da65e44f8abe5446914c7e (patch)
treef3c52d3b9041e93a8e7000446016cc73b9413f2d
parenta16c46bf8a99745d7fa31cc6f2c34e0b17e7bed6 (diff)
downloadbrdo-eaee909a00a516d864da65e44f8abe5446914c7e.tar.gz
brdo-eaee909a00a516d864da65e44f8abe5446914c7e.tar.bz2
- Patch #757154 by sun, effulgentsia: base form_id() via hook_forms() not taken into account for #validate, #submit, hook_form_FORMID_alter().
-rw-r--r--includes/form.inc62
-rw-r--r--modules/book/book.module46
-rw-r--r--modules/comment/comment.module146
-rw-r--r--modules/comment/comment.pages.inc4
-rw-r--r--modules/locale/locale.module48
-rw-r--r--modules/menu/menu.module157
-rw-r--r--modules/node/node.pages.inc18
-rw-r--r--modules/path/path.module90
-rw-r--r--modules/poll/poll.module11
-rw-r--r--modules/system/system.api.php42
-rw-r--r--modules/translation/translation.module4
11 files changed, 375 insertions, 253 deletions
diff --git a/includes/form.inc b/includes/form.inc
index e5d1b1b81..f7ce97393 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -387,13 +387,39 @@ function drupal_build_form($form_id, &$form_state) {
}
}
- // Don't override #theme if someone already set it.
- if (!isset($form['#theme'])) {
- drupal_theme_initialize();
- $registry = theme_get_registry();
+ // Check theme functions for this form.
+ // theme_form() itself is in #theme_wrappers and not #theme. Therefore, the
+ // #theme function only has to care for rendering the inner form elements,
+ // not the form itself.
+ drupal_theme_initialize();
+ $registry = theme_get_registry();
+ // If #theme has been set, check whether the theme function(s) exist, or
+ // remove the suggestion(s), so drupal_render() renders the children.
+ if (isset($form['#theme'])) {
+ if (is_array($form['#theme'])) {
+ foreach ($form['#theme'] as $key => $suggestion) {
+ if (!isset($registry[$suggestion])) {
+ unset($form['#theme'][$key]);
+ }
+ }
+ if (empty($form['#theme'])) {
+ unset($form['#theme']);
+ }
+ }
+ else {
+ if (!isset($registry[$form['#theme']])) {
+ unset($form['#theme']);
+ }
+ }
+ }
+ // Only try to auto-suggest theme functions, if #theme has not been set.
+ else {
if (isset($registry[$form_id])) {
$form['#theme'] = $form_id;
}
+ elseif (isset($form_state['build_info']['base_form_id']) && isset($registry[$form_state['build_info']['base_form_id']])) {
+ $form['#theme'] = $form_state['build_info']['base_form_id'];
+ }
}
return $form;
@@ -693,6 +719,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
}
if (isset($form_definition['callback'])) {
$callback = $form_definition['callback'];
+ $form_state['build_info']['base_form_id'] = $callback;
}
// In case $form_state['wrapper_callback'] is not defined already, we also
// allow hook_forms() to define one.
@@ -892,20 +919,37 @@ function drupal_prepare_form($form_id, &$form, &$form_state) {
$form += array('#tree' => FALSE, '#parents' => array());
if (!isset($form['#validate'])) {
+ // Check for a handler specific to $form_id.
if (function_exists($form_id . '_validate')) {
- $form['#validate'] = array($form_id . '_validate');
+ $form['#validate'][] = $form_id . '_validate';
+ }
+ // Otherwise check whether this is a shared form and whether there is a
+ // handler for the shared $form_id.
+ elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_validate')) {
+ $form['#validate'][] = $form_state['build_info']['base_form_id'] . '_validate';
}
}
if (!isset($form['#submit'])) {
+ // Check for a handler specific to $form_id.
if (function_exists($form_id . '_submit')) {
- // We set submit here so that it can be altered.
- $form['#submit'] = array($form_id . '_submit');
+ $form['#submit'][] = $form_id . '_submit';
+ }
+ // Otherwise check whether this is a shared form and whether there is a
+ // handler for the shared $form_id.
+ elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_submit')) {
+ $form['#submit'][] = $form_state['build_info']['base_form_id'] . '_submit';
}
}
- // Invoke hook_form_alter() and hook_form_FORM_ID_alter() implementations.
- drupal_alter(array('form', 'form_' . $form_id), $form, $form_state, $form_id);
+ // Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and
+ // hook_form_FORM_ID_alter() implementations.
+ $hooks = array('form');
+ if (isset($form_state['build_info']['base_form_id'])) {
+ $hooks[] = 'form_' . $form_state['build_info']['base_form_id'];
+ }
+ $hooks[] = 'form_' . $form_id;
+ drupal_alter($hooks, $form, $form_state, $form_id);
}
diff --git a/modules/book/book.module b/modules/book/book.module
index ef2d83998..053a14a06 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -376,35 +376,33 @@ function book_get_books() {
}
/**
- * Implements hook_form_alter().
+ * Implements hook_form_BASE_FORM_ID_alter().
*
* Adds the book fieldset to the node form.
+ *
+ * @see book_pick_book_nojs_submit()
*/
-function book_form_alter(&$form, &$form_state, $form_id) {
- if (!empty($form['#node_edit_form'])) {
- // Add elements to the node form.
- $node = $form['#node'];
-
- $access = user_access('administer book outlines');
- if (!$access) {
- if (user_access('add content to books') && ((!empty($node->book['mlid']) && !empty($node->nid)) || book_type_is_allowed($node->type))) {
- // Already in the book hierarchy, or this node type is allowed.
- $access = TRUE;
- }
+function book_form_node_form_alter(&$form, &$form_state, $form_id) {
+ $node = $form['#node'];
+ $access = user_access('administer book outlines');
+ if (!$access) {
+ if (user_access('add content to books') && ((!empty($node->book['mlid']) && !empty($node->nid)) || book_type_is_allowed($node->type))) {
+ // Already in the book hierarchy, or this node type is allowed.
+ $access = TRUE;
}
+ }
- if ($access) {
- _book_add_form_elements($form, $form_state, $node);
- // Since the "Book" dropdown can't trigger a form submission when
- // JavaScript is disabled, add a submit button to do that. book.css hides
- // this button when JavaScript is enabled.
- $form['book']['pick-book'] = array(
- '#type' => 'submit',
- '#value' => t('Change book (update list of parents)'),
- '#submit' => array('book_pick_book_nojs_submit'),
- '#weight' => 20,
- );
- }
+ if ($access) {
+ _book_add_form_elements($form, $form_state, $node);
+ // Since the "Book" dropdown can't trigger a form submission when
+ // JavaScript is disabled, add a submit button to do that. book.css hides
+ // this button when JavaScript is enabled.
+ $form['book']['pick-book'] = array(
+ '#type' => 'submit',
+ '#value' => t('Change book (update list of parents)'),
+ '#submit' => array('book_pick_book_nojs_submit'),
+ '#weight' => 20,
+ );
}
}
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index a05c1f0c7..dc211b424 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -719,13 +719,13 @@ function comment_node_page_additions($node) {
// Append comment form if needed.
if (user_access('post comments') && $node->comment == COMMENT_NODE_OPEN && (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_BELOW)) {
- $build = drupal_get_form('comment_form', (object) array('nid' => $node->nid));
+ $build = drupal_get_form("comment_node_{$node->type}_form", (object) array('nid' => $node->nid));
$additions['comment_form'] = $build;
}
if ($additions) {
$additions += array(
- '#theme' => 'comment_wrapper',
+ '#theme' => 'comment_wrapper__node_' . $node->type,
'#node' => $node,
'comments' => array(),
'comment_form' => array(),
@@ -902,7 +902,7 @@ function comment_view($comment, $node, $view_mode = 'full') {
unset($comment->content);
$build += array(
- '#theme' => 'comment',
+ '#theme' => 'comment__node_' . $node->type,
'#comment' => $comment,
'#node' => $node,
'#view_mode' => $view_mode,
@@ -1134,69 +1134,67 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
}
/**
- * Implements hook_form_alter().
+ * Implements hook_form_BASE_FORM_ID_alter().
*/
-function comment_form_alter(&$form, $form_state, $form_id) {
- if (!empty($form['#node_edit_form'])) {
- $node = $form['#node'];
- $form['comment_settings'] = array(
- '#type' => 'fieldset',
- '#access' => user_access('administer comments'),
- '#title' => t('Comment settings'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#group' => 'additional_settings',
- '#attached' => array(
- 'js' => array(drupal_get_path('module', 'comment') . '/comment-node-form.js'),
- ),
- '#weight' => 30,
- );
- $comment_count = isset($node->nid) ? db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() : 0;
- $comment_settings = ($node->comment == COMMENT_NODE_HIDDEN && empty($comment_count)) ? COMMENT_NODE_CLOSED : $node->comment;
- $form['comment_settings']['comment'] = array(
- '#type' => 'radios',
+function comment_form_node_form_alter(&$form, $form_state) {
+ $node = $form['#node'];
+ $form['comment_settings'] = array(
+ '#type' => 'fieldset',
+ '#access' => user_access('administer comments'),
+ '#title' => t('Comment settings'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#group' => 'additional_settings',
+ '#attached' => array(
+ 'js' => array(drupal_get_path('module', 'comment') . '/comment-node-form.js'),
+ ),
+ '#weight' => 30,
+ );
+ $comment_count = isset($node->nid) ? db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() : 0;
+ $comment_settings = ($node->comment == COMMENT_NODE_HIDDEN && empty($comment_count)) ? COMMENT_NODE_CLOSED : $node->comment;
+ $form['comment_settings']['comment'] = array(
+ '#type' => 'radios',
+ '#parents' => array('comment'),
+ '#default_value' => $comment_settings,
+ '#options' => array(
+ COMMENT_NODE_OPEN => t('Open'),
+ COMMENT_NODE_CLOSED => t('Closed'),
+ COMMENT_NODE_HIDDEN => t('Hidden'),
+ ),
+ COMMENT_NODE_OPEN => array(
+ '#type' => 'radio',
+ '#title' => t('Open'),
+ '#description' => t('Users with the "Post comments" permission can post comments.'),
+ '#return_value' => COMMENT_NODE_OPEN,
+ '#default_value' => $comment_settings,
+ '#id' => 'edit-comment-2',
'#parents' => array('comment'),
+ ),
+ COMMENT_NODE_CLOSED => array(
+ '#type' => 'radio',
+ '#title' => t('Closed'),
+ '#description' => t('Users cannot post comments, but existing comments will be displayed.'),
+ '#return_value' => COMMENT_NODE_CLOSED,
'#default_value' => $comment_settings,
- '#options' => array(
- COMMENT_NODE_OPEN => t('Open'),
- COMMENT_NODE_CLOSED => t('Closed'),
- COMMENT_NODE_HIDDEN => t('Hidden'),
- ),
- COMMENT_NODE_OPEN => array(
- '#type' => 'radio',
- '#title' => t('Open'),
- '#description' => t('Users with the "Post comments" permission can post comments.'),
- '#return_value' => COMMENT_NODE_OPEN,
- '#default_value' => $comment_settings,
- '#id' => 'edit-comment-2',
- '#parents' => array('comment'),
- ),
- COMMENT_NODE_CLOSED => array(
- '#type' => 'radio',
- '#title' => t('Closed'),
- '#description' => t('Users cannot post comments, but existing comments will be displayed.'),
- '#return_value' => COMMENT_NODE_CLOSED,
- '#default_value' => $comment_settings,
- '#id' => 'edit-comment-1',
- '#parents' => array('comment'),
- ),
- COMMENT_NODE_HIDDEN => array(
- '#type' => 'radio',
- '#title' => t('Hidden'),
- '#description' => t('Comments are hidden from view.'),
- '#return_value' => COMMENT_NODE_HIDDEN,
- '#default_value' => $comment_settings,
- '#id' => 'edit-comment-0',
- '#parents' => array('comment'),
- ),
- );
- // If the node doesn't have any comments, the "hidden" option makes no
- // sense, so don't even bother presenting it to the user.
- if (empty($comment_count)) {
- unset($form['comment_settings']['comment']['#options'][COMMENT_NODE_HIDDEN]);
- unset($form['comment_settings']['comment'][COMMENT_NODE_HIDDEN]);
- $form['comment_settings']['comment'][COMMENT_NODE_CLOSED]['#description'] = t('Users cannot post comments.');
- }
+ '#id' => 'edit-comment-1',
+ '#parents' => array('comment'),
+ ),
+ COMMENT_NODE_HIDDEN => array(
+ '#type' => 'radio',
+ '#title' => t('Hidden'),
+ '#description' => t('Comments are hidden from view.'),
+ '#return_value' => COMMENT_NODE_HIDDEN,
+ '#default_value' => $comment_settings,
+ '#id' => 'edit-comment-0',
+ '#parents' => array('comment'),
+ ),
+ );
+ // If the node doesn't have any comments, the "hidden" option makes no
+ // sense, so don't even bother presenting it to the user.
+ if (empty($comment_count)) {
+ unset($form['comment_settings']['comment']['#options'][COMMENT_NODE_HIDDEN]);
+ unset($form['comment_settings']['comment'][COMMENT_NODE_HIDDEN]);
+ $form['comment_settings']['comment'][COMMENT_NODE_CLOSED]['#description'] = t('Users cannot post comments.');
}
}
@@ -1744,7 +1742,19 @@ function comment_get_display_page($cid, $node_type) {
*/
function comment_edit_page($comment) {
drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject)), PASS_THROUGH);
- return drupal_get_form('comment_form', $comment);
+ $node = node_load($comment->nid);
+ return drupal_get_form("comment_node_{$node->type}_form", $comment);
+}
+
+/**
+ * Implements hook_forms().
+ */
+function comment_forms() {
+ $forms = array();
+ foreach (node_type_get_types() as $type) {
+ $forms["comment_node_{$type->type}_form"]['callback'] = 'comment_form';
+ }
+ return $forms;
}
/**
@@ -1787,6 +1797,11 @@ function comment_form($form, &$form_state, $comment) {
$node = node_load($comment->nid);
$form['#node'] = $node;
+ // Use #comment-form as unique jump target, regardless of node type.
+ $form['#id'] = drupal_html_id('comment_form');
+ $form['#attributes']['class'][] = 'comment-form';
+ $form['#theme'] = array('comment_form__node_' . $node->type, 'comment_form');
+
$anonymous_contact = variable_get('comment_anonymous_' . $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT);
$is_admin = (!empty($comment->cid) && user_access('administer comments'));
@@ -2194,8 +2209,6 @@ function template_preprocess_comment(&$variables) {
// Preprocess fields.
field_attach_preprocess('comment', $comment, $variables['elements'], $variables);
- $variables['theme_hook_suggestions'][] = 'comment__' . $variables['node']->type;
-
// Helpful $content variable for templates.
foreach (element_children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
@@ -2285,7 +2298,6 @@ function template_preprocess_comment_wrapper(&$variables) {
// Provide contextual information.
$variables['node'] = $variables['content']['#node'];
$variables['display_mode'] = variable_get('comment_default_mode_' . $variables['node']->type, COMMENT_MODE_THREADED);
- $variables['theme_hook_suggestions'][] = 'comment_wrapper__' . $variables['node']->type;
}
/**
diff --git a/modules/comment/comment.pages.inc b/modules/comment/comment.pages.inc
index 8e39ea387..03722e6dc 100644
--- a/modules/comment/comment.pages.inc
+++ b/modules/comment/comment.pages.inc
@@ -37,7 +37,7 @@ function comment_reply($node, $pid = NULL) {
// The user is previewing a comment prior to submitting it.
if ($op == t('Preview')) {
if (user_access('post comments')) {
- $build['comment_form'] = drupal_get_form('comment_form', (object) array('pid' => $pid, 'nid' => $node->nid));
+ $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", (object) array('pid' => $pid, 'nid' => $node->nid));
}
else {
drupal_set_message(t('You are not authorized to post comments.'), 'error');
@@ -83,7 +83,7 @@ function comment_reply($node, $pid = NULL) {
}
elseif (user_access('post comments')) {
$edit = array('nid' => $node->nid, 'pid' => $pid);
- $build['comment_form'] = drupal_get_form('comment_form', (object) $edit);
+ $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", (object) $edit);
}
else {
drupal_set_message(t('You are not authorized to post comments.'), 'error');
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index f7606a0f3..1f42abc6c 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -377,7 +377,7 @@ function locale_multilingual_node_type($type_name) {
/**
* Implements hook_form_alter().
*
- * Adds language fields to forms.
+ * Adds language fields to user forms.
*/
function locale_form_alter(&$form, &$form_state, $form_id) {
// Only alter user forms if there is more than one language.
@@ -388,25 +388,29 @@ function locale_form_alter(&$form, &$form_state, $form_id) {
locale_language_selector_form($form, $form_state, $form['#user']);
}
}
- if (!empty($form['#node_edit_form'])) {
- if (isset($form['#node']->type) && locale_multilingual_node_type($form['#node']->type)) {
- $form['language'] = array(
- '#type' => 'select',
- '#title' => t('Language'),
- '#default_value' => (isset($form['#node']->language) ? $form['#node']->language : ''),
- '#options' => array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name'),
- );
- }
- // Node type without language selector: assign the default for new nodes
- elseif (!isset($form['#node']->nid)) {
- $default = language_default();
- $form['language'] = array(
- '#type' => 'value',
- '#value' => $default->language
- );
- }
- $form['#submit'][] = 'locale_field_node_form_submit';
+}
+
+/**
+ * Implements hook_form_BASE_FORM_ID_alter().
+ */
+function locale_form_node_form_alter(&$form, &$form_state) {
+ if (isset($form['#node']->type) && locale_multilingual_node_type($form['#node']->type)) {
+ $form['language'] = array(
+ '#type' => 'select',
+ '#title' => t('Language'),
+ '#default_value' => (isset($form['#node']->language) ? $form['#node']->language : ''),
+ '#options' => array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name'),
+ );
+ }
+ // Node type without language selector: assign the default for new nodes
+ elseif (!isset($form['#node']->nid)) {
+ $default = language_default();
+ $form['language'] = array(
+ '#type' => 'value',
+ '#value' => $default->language
+ );
}
+ $form['#submit'][] = 'locale_field_node_form_submit';
}
/**
@@ -414,6 +418,10 @@ function locale_form_alter(&$form, &$form_state, $form_id) {
*
* Checks if Locale is registered as a translation handler and handle possible
* node language changes.
+ *
+ * This submit handler needs to run before entity_form_submit_build_entity()
+ * is invoked by node_form_submit_build_node(), because it alters the values of
+ * attached fields. Therefore, it cannot be a hook_node_submit() implementation.
*/
function locale_field_node_form_submit($form, &$form_state) {
if (field_has_translation_handler('node', 'locale')) {
@@ -993,7 +1001,7 @@ function locale_url_outbound_alter(&$path, &$options, $original_path) {
}
}
-/*
+/**
* Implements hook_form_FORM_ID_alter().
*/
function locale_form_comment_form_alter(&$form, &$form_state, $form_id) {
diff --git a/modules/menu/menu.module b/modules/menu/menu.module
index 57db01229..fc7a655b8 100644
--- a/modules/menu/menu.module
+++ b/modules/menu/menu.module
@@ -587,92 +587,96 @@ function _menu_parent_depth_limit($item) {
}
/**
- * Implements hook_form_alter(). Adds menu item fields to the node form.
+ * Implements hook_form_BASE_FORM_ID_alter().
+ *
+ * Adds menu item fields to the node form.
+ *
+ * @see menu_node_submit()
*/
-function menu_form_alter(&$form, $form_state, $form_id) {
- if (!empty($form['#node_edit_form'])) {
- // Generate a list of possible parents.
- // @todo This must be handled in a #process handler.
- $type = $form['#node']->type;
- $options = menu_parent_options(menu_get_menus(), $type);
- // If no possible parent menu items were found, there is nothing to display.
- if (empty($options)) {
- return;
- }
- $link = $form['#node']->menu;
-
- $form['menu'] = array(
- '#type' => 'fieldset',
- '#title' => t('Menu settings'),
- '#access' => user_access('administer menu'),
- '#collapsible' => TRUE,
- '#collapsed' => !$link['link_title'],
- '#group' => 'additional_settings',
- '#attached' => array(
- 'js' => array(drupal_get_path('module', 'menu') . '/menu.js'),
- ),
- '#tree' => TRUE,
- '#weight' => -2,
- '#attributes' => array('class' => array('menu-link-form')),
- );
- $form['menu']['enabled'] = array(
- '#type' => 'checkbox',
- '#title' => t('Provide a menu link'),
- '#default_value' => (int) (bool) $link['mlid'],
- );
- $form['menu']['link'] = array(
- '#type' => 'container',
- '#parents' => array('menu'),
- '#states' => array(
- 'invisible' => array(
- 'input[name="menu[enabled]"]' => array('checked' => FALSE),
- ),
+function menu_form_node_form_alter(&$form, $form_state) {
+ // Generate a list of possible parents.
+ // @todo This must be handled in a #process handler.
+ $type = $form['#node']->type;
+ $options = menu_parent_options(menu_get_menus(), $type);
+ // If no possible parent menu items were found, there is nothing to display.
+ if (empty($options)) {
+ return;
+ }
+ $link = $form['#node']->menu;
+
+ $form['menu'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Menu settings'),
+ '#access' => user_access('administer menu'),
+ '#collapsible' => TRUE,
+ '#collapsed' => !$link['link_title'],
+ '#group' => 'additional_settings',
+ '#attached' => array(
+ 'js' => array(drupal_get_path('module', 'menu') . '/menu.js'),
+ ),
+ '#tree' => TRUE,
+ '#weight' => -2,
+ '#attributes' => array('class' => array('menu-link-form')),
+ );
+ $form['menu']['enabled'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Provide a menu link'),
+ '#default_value' => (int) (bool) $link['mlid'],
+ );
+ $form['menu']['link'] = array(
+ '#type' => 'container',
+ '#parents' => array('menu'),
+ '#states' => array(
+ 'invisible' => array(
+ 'input[name="menu[enabled]"]' => array('checked' => FALSE),
),
- );
+ ),
+ );
- // Populate the element with the link data.
- foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
- $form['menu']['link'][$key] = array('#type' => 'value', '#value' => $link[$key]);
- }
+ // Populate the element with the link data.
+ foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
+ $form['menu']['link'][$key] = array('#type' => 'value', '#value' => $link[$key]);
+ }
- $form['menu']['link']['link_title'] = array(
- '#type' => 'textfield',
- '#title' => t('Menu link title'),
- '#default_value' => $link['link_title'],
- );
+ $form['menu']['link']['link_title'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Menu link title'),
+ '#default_value' => $link['link_title'],
+ );
- $form['menu']['link']['description'] = array(
- '#type' => 'textarea',
- '#title' => t('Description'),
- '#default_value' => isset($link['options']['attributes']['title']) ? $link['options']['attributes']['title'] : '',
- '#rows' => 1,
- '#description' => t('Shown when hovering over the menu link.'),
- );
+ $form['menu']['link']['description'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Description'),
+ '#default_value' => isset($link['options']['attributes']['title']) ? $link['options']['attributes']['title'] : '',
+ '#rows' => 1,
+ '#description' => t('Shown when hovering over the menu link.'),
+ );
- $default = ($link['mlid'] ? $link['menu_name'] . ':' . $link['plid'] : variable_get('menu_parent_' . $type, 'main-menu:0'));
- // @todo This will fail with the new selective menus per content type.
- if (!isset($options[$default])) {
- $default = 'navigation:0';
- }
- $form['menu']['link']['parent'] = array(
- '#type' => 'select',
- '#title' => t('Parent item'),
- '#default_value' => $default,
- '#options' => $options,
- '#attributes' => array('class' => array('menu-parent-select')),
- );
- $form['menu']['link']['weight'] = array(
- '#type' => 'weight',
- '#title' => t('Weight'),
- '#delta' => 50,
- '#default_value' => $link['weight'],
- '#description' => t('Menu links with smaller weights are displayed before links with larger weights.'),
- );
+ $default = ($link['mlid'] ? $link['menu_name'] . ':' . $link['plid'] : variable_get('menu_parent_' . $type, 'main-menu:0'));
+ // @todo This will fail with the new selective menus per content type.
+ if (!isset($options[$default])) {
+ $default = 'navigation:0';
}
+ $form['menu']['link']['parent'] = array(
+ '#type' => 'select',
+ '#title' => t('Parent item'),
+ '#default_value' => $default,
+ '#options' => $options,
+ '#attributes' => array('class' => array('menu-parent-select')),
+ );
+ $form['menu']['link']['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight'),
+ '#delta' => 50,
+ '#default_value' => $link['weight'],
+ '#description' => t('Menu links with smaller weights are displayed before links with larger weights.'),
+ );
}
/**
* Implements hook_node_submit().
+ *
+ * @see menu_form_node_form_alter()
*/
function menu_node_submit($node, $form, $form_state) {
// Decompose the selected menu parent option into 'menu_name' and 'plid', if
@@ -683,7 +687,8 @@ function menu_node_submit($node, $form, $form_state) {
}
/**
- * Implements hook_form_FORM_ID_alter() for the node type form.
+ * Implements hook_form_FORM_ID_alter().
+ *
* Adds menu options to the node type form.
*/
function menu_form_node_type_form_alter(&$form, $form_state) {
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index 4053b6dc5..7a9e141bb 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -114,7 +114,9 @@ function node_form($form, &$form_state, $node) {
}
// Identify this as a node edit form.
+ // @todo D8: Remove. Modules can implement hook_form_BASE_FORM_ID_alter() now.
$form['#node_edit_form'] = TRUE;
+
$form['#attributes']['class'][] = 'node-form';
if (!empty($node->type)) {
$form['#attributes']['class'][] = 'node-' . $node->type . '-form';
@@ -136,6 +138,8 @@ function node_form($form, &$form_state, $node) {
);
// Invoke hook_form() to get the node-specific bits. Can't use node_invoke(),
// because hook_form() needs to be able to receive $form_state by reference.
+ // @todo hook_form() implementations are unable to add #validate or #submit
+ // handlers to the form buttons below. Remove hook_form() entirely.
$function = node_type_get_base($node) . '_form';
if (function_exists($function) && ($extra = $function($node, $form_state))) {
$form = array_merge_recursive($form, $extra);
@@ -143,9 +147,7 @@ function node_form($form, &$form_state, $node) {
if (!isset($form['title']['#weight'])) {
$form['title']['#weight'] = -5;
}
- // @todo Legacy support. Modules adding form building and processing functions
- // to the node form are encouraged to access the node using
- // $form_state['node']. Remove in Drupal 8.
+ // @todo D8: Remove. Modules should access the node using $form_state['node'].
$form['#node'] = $node;
$form['additional_settings'] = array(
@@ -281,7 +283,17 @@ function node_form($form, &$form_state, $node) {
'#submit' => array('node_form_delete_submit'),
);
}
+ // This form uses a button-level #submit handler for the form's main submit
+ // action. node_form_submit() manually invokes all form-level #submit handlers
+ // of the form. Without explicitly setting #submit, Form API would auto-detect
+ // node_form_submit() as submit handler, but that is the button-level #submit
+ // handler for the 'Save' action. To maintain backwards compatibility, a
+ // #submit handler is auto-suggested for custom node type modules.
$form['#validate'][] = 'node_form_validate';
+ if (!isset($form['#submit']) && function_exists($node->type . '_node_form_submit')) {
+ $form['#submit'][] = $node->type . '_node_form_submit';
+ }
+ $form += array('#submit' => array());
$form['#builder_function'] = 'node_form_submit_build_node';
field_attach_form('node', $node, $form, $form_state, $node->language);
diff --git a/modules/path/path.module b/modules/path/path.module
index 68d542494..e0766f9e1 100644
--- a/modules/path/path.module
+++ b/modules/path/path.module
@@ -94,55 +94,53 @@ function path_menu() {
}
/**
- * Implements hook_form_alter().
+ * Implements hook_form_BASE_FORM_ID_alter().
*/
-function path_form_alter(&$form, $form_state, $form_id) {
- if (!empty($form['#node_edit_form'])) {
- $path = array();
- if (!empty($form['#node']->nid)) {
- $conditions = array('source' => 'node/' . $form['#node']->nid);
- if ($form['#node']->language != LANGUAGE_NONE) {
- $conditions['language'] = $form['#node']->language;
- }
- $path = path_load($conditions);
- if ($path === FALSE) {
- $path = array();
- }
+function path_form_node_form_alter(&$form, $form_state) {
+ $path = array();
+ if (!empty($form['#node']->nid)) {
+ $conditions = array('source' => 'node/' . $form['#node']->nid);
+ if ($form['#node']->language != LANGUAGE_NONE) {
+ $conditions['language'] = $form['#node']->language;
+ }
+ $path = path_load($conditions);
+ if ($path === FALSE) {
+ $path = array();
}
- $path += array(
- 'pid' => NULL,
- 'source' => isset($form['#node']->nid) ? 'node/' . $form['#node']->nid : NULL,
- 'alias' => '',
- 'language' => isset($form['#node']->language) ? $form['#node']->language : LANGUAGE_NONE,
- );
-
- $form['path'] = array(
- '#type' => 'fieldset',
- '#title' => t('URL path settings'),
- '#collapsible' => TRUE,
- '#collapsed' => empty($path['alias']),
- '#group' => 'additional_settings',
- '#attached' => array(
- 'js' => array(drupal_get_path('module', 'path') . '/path.js'),
- ),
- '#access' => user_access('create url aliases') || user_access('administer url aliases'),
- '#weight' => 30,
- '#tree' => TRUE,
- '#element_validate' => array('path_form_element_validate'),
- );
- $form['path']['alias'] = array(
- '#type' => 'textfield',
- '#title' => t('URL alias'),
- '#default_value' => $path['alias'],
- '#maxlength' => 255,
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => t('Optionally specify an alternative URL by which this node can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
- );
- $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
- $form['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
- $form['path']['language'] = array('#type' => 'value', '#value' => $path['language']);
}
+ $path += array(
+ 'pid' => NULL,
+ 'source' => isset($form['#node']->nid) ? 'node/' . $form['#node']->nid : NULL,
+ 'alias' => '',
+ 'language' => isset($form['#node']->language) ? $form['#node']->language : LANGUAGE_NONE,
+ );
+
+ $form['path'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('URL path settings'),
+ '#collapsible' => TRUE,
+ '#collapsed' => empty($path['alias']),
+ '#group' => 'additional_settings',
+ '#attached' => array(
+ 'js' => array(drupal_get_path('module', 'path') . '/path.js'),
+ ),
+ '#access' => user_access('create url aliases') || user_access('administer url aliases'),
+ '#weight' => 30,
+ '#tree' => TRUE,
+ '#element_validate' => array('path_form_element_validate'),
+ );
+ $form['path']['alias'] = array(
+ '#type' => 'textfield',
+ '#title' => t('URL alias'),
+ '#default_value' => $path['alias'],
+ '#maxlength' => 255,
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#description' => t('Optionally specify an alternative URL by which this node can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
+ );
+ $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
+ $form['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
+ $form['path']['language'] = array('#type' => 'value', '#value' => $path['language']);
}
/**
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 1de52b55f..72cd86e66 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -240,6 +240,8 @@ function poll_form($node, &$form_state) {
$type = node_type_get_type($node);
+ // The submit handlers to add more poll choices require that this form is
+ // cached, regardless of whether AJAX is used.
$form_state['cache'] = TRUE;
$form['title'] = array(
@@ -359,7 +361,7 @@ function poll_form($node, &$form_state) {
* return just the changed part of the form.
*/
function poll_more_choices_submit($form, &$form_state) {
- // Make the changes we want to the form state.
+ // If this is a AJAX POST, add 1, otherwise add 5 more choices to the form.
if ($form_state['values']['poll_more']) {
$n = $_GET['q'] == 'system/ajax' ? 1 : 5;
$form_state['choice_count'] = count($form_state['values']['choice']) + $n;
@@ -424,10 +426,13 @@ function poll_choice_js($form, $form_state) {
}
/**
- * Renumber fields and create a teaser when a poll node is submitted.
+ * Form submit handler for node_form().
+ *
+ * Upon preview and final submission, we need to renumber poll choices and
+ * create a teaser output.
*/
function poll_node_form_submit(&$form, &$form_state) {
- // Renumber fields
+ // Renumber choices.
$form_state['values']['choice'] = array_values($form_state['values']['choice']);
$form_state['values']['teaser'] = poll_teaser((object) $form_state['values']);
}
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index ebd4f20ed..c9b140167 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -1336,11 +1336,14 @@ function hook_form_alter(&$form, &$form_state, $form_id) {
* Nested array of form elements that comprise the form.
* @param $form_state
* A keyed array containing the current state of the form.
+ * @param $form_id
+ * String representing the name of the form itself. Typically this is the
+ * name of the function that generated the form.
*
* @see hook_form_alter()
* @see drupal_prepare_form()
*/
-function hook_form_FORM_ID_alter(&$form, &$form_state) {
+function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
// Modification for the form with the given form ID goes here. For example, if
// FORM_ID is "user_register_form" this code would run only on the user
// registration form.
@@ -1354,6 +1357,43 @@ function hook_form_FORM_ID_alter(&$form, &$form_state) {
}
/**
+ * Provide a form-specific alteration for shared forms.
+ *
+ * Modules can implement hook_form_BASE_FORM_ID_alter() to modify a specific
+ * form belonging to multiple form_ids, rather than implementing
+ * hook_form_alter() and checking for conditions that would identify the
+ * shared form constructor.
+ *
+ * Examples for such forms are node_form() or comment_form().
+ *
+ * Note that this hook fires after hook_form_FORM_ID_alter() and before
+ * hook_form_alter().
+ *
+ * @param $form
+ * Nested array of form elements that comprise the form.
+ * @param $form_state
+ * A keyed array containing the current state of the form.
+ * @param $form_id
+ * String representing the name of the form itself. Typically this is the
+ * name of the function that generated the form.
+ *
+ * @see hook_form_FORM_ID_alter()
+ * @see drupal_prepare_form()
+ */
+function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
+ // Modification for the form with the given BASE_FORM_ID goes here. For
+ // example, if BASE_FORM_ID is "node_form", this code would run on every
+ // node form, regardless of node type.
+
+ // Add a checkbox to the node form about agreeing to terms of use.
+ $form['terms_of_use'] = array(
+ '#type' => 'checkbox',
+ '#title' => t("I agree with the website's terms and conditions."),
+ '#required' => TRUE,
+ );
+}
+
+/**
* Map form_ids to form builder functions.
*
* By default, when drupal_get_form() is called, the system will look for a
diff --git a/modules/translation/translation.module b/modules/translation/translation.module
index 5c9d1c440..2fc84e770 100644
--- a/modules/translation/translation.module
+++ b/modules/translation/translation.module
@@ -123,8 +123,8 @@ function translation_form_node_type_form_alter(&$form, &$form_state) {
* - Alters language fields on node forms when a translation
* is about to be created.
*/
-function translation_form_alter(&$form, &$form_state, $form_id) {
- if (!empty($form['#node_edit_form']) && translation_supported_type($form['#node']->type)) {
+function translation_form_node_form_alter(&$form, &$form_state) {
+ if (translation_supported_type($form['#node']->type)) {
$node = $form['#node'];
if (!empty($node->translation_source)) {
// We are creating a translation. Add values and lock language field.