Context: In my Drupal 7 project, I have a module with several submodules. Because the module's root directory got crowded, I moved the submodule files to their own directories within the root.

My module's structure is like this:

├── mymodule.info
├── mymodule.module
├── mymodule1
│   ├── mymodule1.block.inc
│   ├── mymodule1.form.inc
│   ├── mymodule1.info
│   ├── mymodule1.module
│   ├── mymodule1.page.inc
│   └── pages
│       └── foo.tpl.php
└── mymodule2
    ├── classes
    │   └── foo
    │       └── Bar.php
    ├── mymodule2.form.inc
    ├── mymodule2.info
    ├── mymodule2.install
    ├── mymodule2.module
    ├── mymodule2.page.inc
    └── pages
        ├── foo.tpl.php
        └── bar.tpl.php

Before "the big move", files that are now in the subdirectories mymodule1 and mymodule2, were located in their parent directory (the module's root directory).

The problem: Ever since moving the files, my custom forms are not loading anymore. I have a form in mymodule1.form.inc, which used to load and render perfectly before. Now, when I use drupal_get_form() to load the form, I only get an empty form with a hidden build ID input.

Keep in the mind that the only thing that has changed here, is that the .inc files have been moved to the subdirectory, along with the module file. Also, drupal_get_path('module', 'mymodule1') returns the correct path to the module in the subdirectory.

Strangely, there are also block hooks, located in mymodule1.block.inc, which work perfectly fine, even after clearing all caches.

This is the first time I'm working with separate directories per submodule within a module. I got the inspiration from the module i18n, which uses the same construction. I searched in the Drupal documentation and the code of i18n, but could not find where I'm going wrong.

Does anyone know where I could possibly have gone wrong, or if I need to add data to mymodule1.module or mymodule1.info to make this work? Thank you.

Some details: Caches were cleared through <path to project>/admin_menu/flush-cache multiple times.

I use module1_hook_info() to direct the hooks for blocks and forms to separate files. This is the return value:

array (size=9)
  'block_info' => 
    array (size=1)
      'group' => string 'block' (length=5)
  'block_configure' => 
    array (size=1)
      'group' => string 'block' (length=5)
  'block_save' => 
    array (size=1)
      'group' => string 'block' (length=5)
  'block_view' => 
    array (size=1)
      'group' => string 'block' (length=5)
  'forms' => 
    array (size=1)
      'group' => string 'form' (length=4)
  'form' => 
    array (size=1)
      'group' => string 'form' (length=4)
  'form_validate' => 
    array (size=1)
      'group' => string 'form' (length=4)
  'form_submit' => 
    array (size=1)
      'group' => string 'form' (length=4)
  'form_alter' => 
    array (size=1)
      'group' => string 'form' (length=4)

My form functions are called:

  • mymodule1_foobar_form
  • mymodule1_foobar_form_validate
  • mymodule1_foobar_form_submit
  • Have you updated the code that includes mymodule1.form.inc to include the new path?
    – Clive
    Commented Dec 18, 2015 at 11:20
  • @Clive I'm not including this file anywhere, since it worked without include before (and I didn't see similar includes in other modules) in neither .module or .info. Do you mean a require_once, module_load_include()? I got the impression that require_once is bad practice. Commented Dec 18, 2015 at 11:47
  • I mean module_load_include() - I reckon your original code worked because of an unintended side effect, more details in the answer
    – Clive
    Commented Dec 18, 2015 at 11:50

2 Answers 2


Thanks to Clive I found module_load_include(), which is used to load files when working with a form. I moved hook_forms() back to my main module's file and now load the mymodule1.form.inc through there, like so:

 * Implements hook_forms().
function mymodule1_forms($form_id, $args)
    module_load_include('inc', 'mymodule1', 'mymodule1.form');
    $forms = array();

    $forms['mymodule1_foo_form'] = array(
        'callback' => 'mymodule1_foo_form',

    return $forms;

Now all my forms are loading correctly (again), over both mymodule1 and mymodule2.

The one thing I'm not sure about, that whether this could have been achieved without redundantly declaring the form callbacks to their same-named form IDs.


I'm going to take a stab at what happened here, I might be wrong.

hook_form() isn't a normal hook, it's only invoked for modules that define node types (you haven't indicated any of yours do). It isn't invoked when you arbitrarily invoke drupal_get_form(). Same goes for hook_form_validate() and hook_form_submit().

Some of the hooks in your hook_hook_info() implementation are called for all modules, though. e.g. hook_forms() and hook_form_alter().

I would surmise that mymodule contained an implementation of hook_form_alter() or hook_forms(), which was coincidentally invoked on the same page(s) as the forms that you've now moved to mymodule1 were displayed. Those hooks being invoked implicitly result in mymodule.form.inc being included, and the functions were available.

Now that you've moved the code into mymodule1, I'm guessing you haven't implemented either of the hooks that would have resulted in that coincidental behaviour. So Drupal now can't find your form function, and fails silently.

To fix, include the file manually:

module_include('inc', 'mymodule1', 'mymodule1.form');
  • mymodule contains no code other than a theme registry function. The form hooks have been always been part of mymodule1. Before moving the files, the form was displayed. I do have an identical hook_info in mymodule2, which also has its own forms (which are also not loading now). Commented Dec 18, 2015 at 11:57
  • I put module_load_include('inc', 'mymodule1', 'mymodule1.form'); on top of mymodule1.module and cleared my cache. This made no difference for me. Commented Dec 18, 2015 at 11:58
  • Worth a shot I guess, I don't know the answer then. I do know that using hook_hook_info() won't work to auto-include MODULE.form.inc, though, as you can see from the explanation about hook_form(), so I guess the quirk is elsewhere
    – Clive
    Commented Dec 18, 2015 at 11:59
  • I've tried including the file through module1.info (using files[]), but this did not make any difference either. Commented Dec 18, 2015 at 12:04
  • 1
    It wouldn't - files[] is for autoloading classes
    – Clive
    Commented Dec 18, 2015 at 12:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.