Custom widget making field invisible I'm trying to create a custom module for Drupal 7 that makes two widgets available for Text fields. The widgets are showing up in the list of available widgets, but when I select one of them as the widget for a Text field, the field isn't visible on the form (although it is still listed in the Manage Fields section and its settings can be changed as normal). Here's my code so far:

&lt;?php
/**
 * Implements hook_menu().
 */
function autocomplete_jsb_users_menu() {
    $items['jsbu/speaker/autocomplete'] = array(
        'page callback' =&gt; 'jsbu_speaker_autocomplete',
        'access callback' =&gt; TRUE,
        'weight' =&gt; 1,
    );
    $items['jsbu/venue/autocomplete'] = array(
        'page callback' =&gt; 'jsbu_venue_autocomplete',
        'access callback' =&gt; TRUE,
        'weight' =&gt; 2,
    );
    return $items;
}

/**
 * Implements hook_field_widget_info().
 *
 * Two widgets are provided.
 * - A textfield Speaker name autocomplete widget.
 * - A textfield Venue name autocomplete widget.
 */
function autocomplete_jsb_users_field_widget_info() {
    return array(
        'autocomplete_speaker_name' =&gt; array(
            'label' =&gt; t('Autocomplete Speaker Name'),
            'field types' =&gt; array('text'),
        ),
        'autocomplete_venue_name' =&gt; array(
            'label' =&gt; t('Autocomplete Venue Name'),
            'field types' =&gt; array('text'),
        ),
    );
}

/**
 * Implements hook_field_widget_form().
 */
function autocomplete_jsb_users_field_widget_form(&amp;$form, &amp;$form_state, $field, $instance, $langcode, $items, $delta, $element) {
    //load the default text instance
    $element += text_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);

    /*if ($instance['widget']['type'] == 'autocomplete_speaker_name') {
        $element['value']['#autocomplete_path' ] = 'jsbu/speaker/autocomplete';
    } else if($instance['widget']['type'] == 'autocomplete_venue_name') {
        $element['value']['#autocomplete_path' ] = 'jsbu/venue/autocomplete';
    }*/
    return $element;
}

/**
 * Implements the autocomplete_jsbu_speaker() callback.
 */
function jsbu_speaker_autocomplete() {
    $matches = array();

    // Query the database
    $query = db_select('field_data_field_speaker_name', 'sn');

    // Select rows that match the string
    $query
        -&gt;fields('sn', array('field_speaker_name_value'))
        -&gt;orderBy('field_speaker_name_value', 'DESC');

    $result = $query.execute();

    // add matches to $matches  
    foreach ($result as $row) {
        $matches[$row-&gt;field_speaker_name_value] = check_plain($row-&gt;field_speaker_name_value);
    }

    // return for JS
    drupal_json_output($matches);
}

/**
 * Implements the autocomplete_jsbu_venue() callback.
 */
function jsbu_venue_autocomplete() {
    $matches = array();

    // Query the database
    $query = db_select('field_data_field_venue_name', 'vn');

    // Select rows that match the string
    $query
        -&gt;fields('vn', array('field_venue_name_value'))
        -&gt;orderBy('field_venue_name_value', 'DESC');

    $result = $query.execute();

    // add matches to $matches  
    foreach ($result as $row) {
        $matches[$row-&gt;field_venue_name_value] = check_plain($row-&gt;field_venue_name_value);
    }

    // return for JS
    drupal_json_output($matches);
}


Any ideas on what I'm doing wrong there/anything else I might need to add? Is the problem that I'm missing a hook?

EDIT: $element just before return:

Array (
    [#entity_type] =&gt; node
    [#bundle] =&gt; event
    [#field_name] =&gt; field_event_speaker
    [#language] =&gt; und
    [#field_parents] =&gt; Array
        (
        )

    [#columns] =&gt; Array
        (
            [0] =&gt; value
            [1] =&gt; format
        )

    [#title] =&gt; Speaker
    [#description] =&gt; 
    [#required] =&gt; 
    [#delta] =&gt; 0
    [value] =&gt; Array
        (
            [#autocomplete_path] =&gt; jsbu/speaker/autocomplete
        )

)
I think it's because you're missing the type, however, to make things easier and more compatible, why not load the "stock" widget and make modifications? 

Try adding this instead of your $element declarations:

$element += text_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);

That should load the default text form, then you can make modifications. You can take a look at the code it uses directly: see line 502 of text.module.

Your simplified code might look something like this:

   //load the default text instance
   $element += text_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);

   if ($instance['widget']['type'] == 'autocomplete_speaker_name') {
      $element['value']['#autocomplete_path' ] = 'jsbu/speaker/autocomplete';
   else if($instance['widget']['type'] == 'autocomplete_venue_name')
      $element['value']['#autocomplete_path' ] = 'jsbu/venue/autocomplete';
    }

   return $element;