I have a custom form with a custom schema. The schema has an ID that auto increments.

Now I want to show the content on custom pages; each id should have its own page.

What I want to do is if I'm going to recipe/1 than the page should show me all content from the recipe which has the id "1".

I tried to tell drupal that there is a new page called "recipe/%", but when I go to recipe/1 for example drupal tells me that the page is not found.

How do I tell drupal that there is a page?

function recipe_submit_menu() {
  $items = array();

  $items['recipe/add'] = array(
    'title' => 'Submit a recipe',
    'description' => 'A form to submit a recipe',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('recipe_submit_form'),
    'access arguments' => array('add_recipe'),
    'access callback' => TRUE

  $item['recipe/%'] = array(
    'title' => 'Recipe details',
    'page arguments' => array('3'),
    'page callback' => 'recipe_submit_page',
    'access arguments' => array('recipe_manage'),

  return $items;

function recipe_submit_form($form, &$form_state) {

  $form['recipe_title'] = array(
    '#type' => 'textfield',
    '#title' => t('Recipe title'),
    '#required' => TRUE,

  $form['author_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Author name'),

  $form['author_email'] = array(
    '#type' => 'textfield',
    '#title' => t('Author email'),
    '#required' => TRUE,

  $form['recipe_description'] = array(
    '#type' => 'textarea',
    '#title' => t('Recipe description'),
    '#maxlength' => 500,
    '#required' => TRUE,

  $form['recipe_instructions'] = array(
    '#type' => 'textarea',
    '#title' => t('Recipe instructions'),
    '#required' => TRUE,

  $form['recipe_ingredients'] = array(
    '#type' => 'textarea',
    '#title' => t('Recipe ingredients'),
    '#required' => TRUE,

  $form['submit_button'] = array(
    '#type' => 'submit',
    '#value' => t('Submit recipe'),

  return $form;

function recipe_submit_form_validate($form, &$form_state) {
  if (!filter_var($form_state['values']['author_email'], FILTER_VALIDATE_EMAIL)) {
    form_set_error('author_email',t('You have to enter a valid email address'));
    $form_state['redirect'] = FALSE;


function recipe_submit_form_submit($form, &$form_state) {
  global $language;
  $query = db_insert('recipe_submit')
      'submitted' => time(),
      'site_language' => $language->language,
      'recipe_title' => $form_state['values']['recipe_title'] ,
      'author_name' => $form_state['values']['author_name'],
      'author_email' => $form_state['values']['author_email'],
      'recipe_description' => $form_state['values']['recipe_description'],
      'recipe_instructions' => $form_state['values']['recipe_instructions'],
      'recipe_ingredients' => $form_state['values']['recipe_ingredients'],
  drupal_set_message(t('The recipe was sucessfully submitted.'));
  $form_state['redirect'] = '/';

 * Implements hook_permission().
function recipe_submit_permission() {
  return array(
    'add_recipe' => array(
      'title' => t('Permission to add a recipe'),
    'recipe_managed' => array(
      'title' => t('Permission to manage recipes'),
  • So far, you just stated facts and shown code, but you didn't ask any explicit question. (The question title doesn't count as explicit question.) What exactly don't you understand? What are you exactly trying to do that you aren't able? Don't you understand how to catch the saved values from the database?
    – apaderno
    Feb 13, 2017 at 11:42
  • 2
    You need to invest in a robust spellchecker or a better pair of spectacles - this is another spelling error. $item and $items are different variables.
    – Clive
    Feb 13, 2017 at 12:03
  • Also be aware that you take the non-existent 3rd parameter from the URL in 'page arguments' => array('3'). Feb 13, 2017 at 12:21
  • 1
    I am not sure why this was closed as "unclear what you're asking". The error is quite clear in the code that was posted although it might be a duplicate. The permission used in hook_menu is not the same as the one defined in hook_permission.
    – mradcliffe
    Feb 13, 2017 at 13:05
  • 1
    The one thing I will say is before you go too much further, you might want to rethink this approach and treat a Recipe as an entity. It will grant you access to everything Drupal that has entity hook-ins, like Views, Pathauto, Search API, Fields, user access, etc. You could even add EntityForm and Rules to abstract the entity creation form for users. The path you're on is simply going to reinvent the wheel and cost 3x as much code. The only change you would have to make is define hook_entity_info and some routing.
    – Kevin
    Feb 13, 2017 at 13:29


Browse other questions tagged or ask your own question.