You are here

Drupal 7 - Simple Settings and Configs

Creating content types for pleasure and fun sometimes means that you need to have fields populated with data when first presented to the author during node creation. This functionality usually involves two things: someplace to create/modify those default values and injecting that value into your node creation forms. For this example, we're going to create a simple content type with a title, body, and an extra textfield and we'll populate that textfield with a value we specified using a settings form we added to our very own configurations section. That's a lot of stuff to tackle so let's get started.

Before we can tackle the admin section and creating that default value we need a simple content type to use as our guinea code. I'm using the original Simple Content Type as my base and have modified it to add the extra textfield. I did not need to modify much to get the node I was looking for, here is the updated module.install file:


/**
 * Implements hook_install().
 * - Add the body field
 * - Configure the body field
 * - add a text field
 */
function simple_content_type_install() {
  // create the simple content type
  node_types_rebuild();
  $types = node_type_get_types();
  
  // add the body field to the node type
  node_add_body_field($types['simple_content_type']);
  // load the instance definition for our content type's body
  $body_instance = field_info_instance('node', 'body', 'simple_content_type');
  // configure the body field
  $body_instance['type'] = 'text_summary_or_trimmed';
  $body_instance['label'] = 'Simple Description';
  $body_instance['display'] = array(
    'default' => array(
      'label' => 'above', 
      'type' => 'text_default',
      'weight' => 0,
    ),
    'teaser' => array(
      'label' => 'hidden', 
      'type' => 'text_summary_or_trimmed',
      'weight' => 0,
    ),
  );
  $body_instance['widget']['weight'] = 0;
  
  // save our changes to the body field instance
  field_update_instance($body_instance);
  
  // create all the fields we are adding to our content type
  foreach (_simple_content_type_installed_fields() as $field) {
    field_create_field($field);
  }
  
  // create all the instance for our fields
  foreach (_simple_content_type_installed_instances() as $instance) {
    $instance['entity_type'] = 'node';
    $instance['bundle'] = 'simple_content_type';
    field_create_instance($instance);
  }
  
  // disable comments for this content type
  variable_set('comment_simple_content_type', COMMENT_NODE_CLOSED);
  // set the starting default value for the text field
  variable_set('simple_content_type_default_text', 'Pangus');
}

/**
 * Implements hook_uninstall().
 */
function simple_content_type_uninstall() {
  // gather all the content while the module was enabled
  $sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
  $result = db_query($sql, array(':type' => 'simple_content_type'));
  $nids = array();
  foreach ($result as $row) {
    $nids[] = $row->nid;
  }
  
  // delete all the nodes at once
  node_delete_multiple($nids);
  
  // delete all the fields defined by this module
  foreach (array_keys(_simple_content_type_installed_fields()) as $field) {
    field_delete_field($field);
  }
  
  // delete any remaining field instances attached to this content type
  $instances = field_info_instances('node', 'simple_content_type');
  foreach ($instances as $instance_name => $instance) {
    field_delete_instance($instance);
  }
  
  // delete our content type
  node_type_delete('simple_content_type');
  
  // purge all field information
  field_purge_batch(1000);
  
  // set the starting default value for the text field
  variable_del('comment_simple_content_type');
  variable_del('simple_content_type_default_text');
}

A quick and dirty break-down of the above: the install hook creates our new content type, adds a body and text fields and configures them; the uninstall hook purges the database of any information related to this content type. The astute reader will have noticed that we are also using variable_set() to initialize the simple_content_type_default_text 'variable' we will be using to store the default value we will be using to populate the textfield. More on that in a bit. The next part of our task involves setting up the module.module file. First, let's take a look at the hooks we need to implement to get our content type working at a base level:


/**
 * Implements hook_node_info().
 */
function simple_content_type_node_info() {
  
  $items['simple_content_type'] = array(
    'name' => t('Simple Content Type'),
    'type' => 'simple_content_type',
    'base' => 'node_content',
    'description' => t('A simple demonstration content type with a title, body, and text field.'),
    'has_title' => '1',
    'title_label' => t('Simple Title'),
    'body_label' => t('Simple Description'),
    'help' => t('Please fill in all fields.'),
  );
  
  return $items;
}
/**
 * Implement hook_form() with the standard default form.
 */
function simple_content_type_form($node, $form_state) {
  return node_content_form($node, $form_state);
}

Nothing surprising in the above: first we tell Drupal about our new content type and then we tell Drupal how to display the form used in creation/modification of nodes of this type. Besides the above we also are using a file (simple_content_type.functions.inc) to store all the non-hook functions we code for use in our hooks:


/**
 * Associative array of fields to add
 */
function _simple_content_type_installed_fields()  {
  // text field
  $fields['simple_content_type_textfield'] = array(
    'field_name' => 'simple_content_type_textfield',
    'label' => t('A Textfield'),
    'type' => 'text',
    'module' => 'text',
  );
  
  return $fields;
}
/**
 * Associative array of field instance settings
 */
function _simple_content_type_installed_instances()  {
  // textfield
  $instances['simple_content_type_textfield'] = array(
    'field_name' => 'simple_content_type_textfield',
    'type' => 'text',
    'label' => t('Simple Textfield'),
    'required' => 1,
    'widget' => array(
      'type' => 'text_textfield',
      'weight' => '-1',
      'settings' => array(
        'size' => '20',
        'max_length' => '100',
      ),
    ),
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'settings' => array(),
        'type' => 'text_default',
        'weight' => -1,
      ),
      'teaser' => array(
        'label' => 'above',
        'settings' => array(),
        'type' => 'hidden',
        'weight' => -1,
      ),
    ),
  );
  
  return $instances;
}

The first function provides information about what type of data is being gathered by this field and the second function provides information used to display this data either in node form or in form form. Add a module.info file and you can load this baby up. When you go to create a new node you should see something like this:

A Simple Content Type add/edit form without a default populating the textfield.

You may have noticed that all the fields are blank. Not to worry, that was expected. To use the variable we defined on install to populate the textfield only when a Simple Content Type node is being created we need to implement one more hook, hook_form_alter():


/**
 * Implements hook_form_alter().
 */
function simple_content_type_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id != 'simple_content_type_node_form')  {
    // this is not the form we are looking for
    return;
  }
  //modify the default value for the simple text field
  $language = $form['simple_content_type_textfield']['#language'];
  if (!isset($form['simple_content_type_textfield'][$language]['0']['value']['#default_value']))  {
    $form['simple_content_type_textfield'][$language]['0']['value']['#default_value'] = variable_get('simple_content_type_default_text', '');
  }
}

Because we are using the Field API to create and define the fields in our content type, and if we want the default value for the text field to be dynamically defined through a configuration form, then we need to modify the node form as it is being created in order for the value to be properly populated. So the first thing we do is make sure we are modifying the appropriate form. Once past the gate we need to check to see if there is a default value set already. To make this language neutral we grab the language being used before we do the check for that value. We do this check to make sure we are not modifying a node edit form as this field is required. Finally, if we need to, we set the default value for the text field using variable_get() and the value we defined on install. If you wanted to you could save and be on your merry way, happy knowing that you now had a content type that could populate fields with a value of your choosing. But would you really be? Happy, that is. What if I told you that for just two more functions you could have your very own configurations form and define the heck out of that variable any time you want? WOuld you still be happy? Or you want to know more? To set up the "Andy Pangus Administration" area we first need to implement the hook_menu() hook:


/**
 * Implements hook_menu().
 */
function simple_content_type_menu()  {
  
  // create the Andy Pangus admin category
  $items['admin/config/andy_pangus_admin'] = array(
    'title' => 'Andy Pangus Administration',
    'description' => 'Administration pages and tasks for Andy Pangus.',
    'position' => 'right',
    'weight' => -5,
    'page callback' => 'system_admin_menu_block_page',
    'file' => 'system.admin.inc',
    'file path' => drupal_get_path('module', 'system'),
    'access arguments' => array('administer nodes'),
  );
  
  // add the configs page to the admin section
  $items['admin/config/andy_pangus_admin/simple_content_type_settings'] = array(
    'title' => 'Simple Content Type Settings',
    'description' => 'Configuration settings for the Simple Content Type module',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('simple_content_type_configs_form'),
    'file' => 'simple_content_type.admin.inc',
    'access arguments' => array('administer nodes'),
    'type' => MENU_NORMAL_ITEM,
  );
  
  return $items;
}

In the menu hook we define two items: the administration page to list any configuration or settings forms we need and the page to display the single configuration form we will be using. For the item describing the administration category we use some predefined funcionality from the Drupal core and utilize a page callback from the system module to tie our category into the configurations page. We also use this opportunity to tell Drupal we want our category displayed on the right side of the configurations page and that only people who can administer nodes should be able to access this category. The second item describes the page which will be accessible from the admin category we defined with the first item. For this page we really just need to display a form so we use drupal_get_form() function and a form we define in a separate file, simple_content_type.admin.inc:


define('SIMPLE_CONTENT_TYPE_DEFAULT', t('Pangus'));
/**
 * Form builder; Create and display the Enspire Demo Admin configuration
 * settings form.
 */
function simple_content_type_configs_form($form, &$form_state)  {
  // Demo Page Title
  $form['simple_content_type_default_text'] = array(
    '#type' => 'textfield',
    '#title' => t('Simple Textfield Default Value'),
    '#description' => t('This value is used to populate the Simple Textfield in a Simple Content Type node during node creation.'),
    '#max_length' => 100,
    '#size' => 20,
    '#required' => TRUE,
    '#default_value' => variable_get('simple_content_type_default_text', SIMPLE_CONTENT_TYPE_DEFAULT),
  );
  
  return system_settings_form($form);
}

The configuration form for this module is short and sweet, only one value to set. It is only fitting that we use a textfield in our form to set the default value for the textfield in our content type. We should also remember to set the default value for this form field with variable we define on installation. Before returning the form for rendering we pass it through the system_settings_form() function to add a submit button with actions and an associated #submit assignment. Passing our form through this function means that we can let Drupal handle saving our settings to the correct place. Finally, the updated module.info file:


name = Simple Content Type
description = A simple demonstration content type
package = Andy Pangus Examples
core = 7.x
files[] = simple_content_type.install
files[] = simple_content_type.module
configure = admin/config/andy_pangus_admin/simple_content_type_settings

As a convenience, we've added a link to the module configuration page to the modules page next to our module:

The enabled module with associate configuration link.

Or we can access the module configuration page from the 'admin/config' page:

The Andy Pangus Administration category.

Once you've configured the module, we you create a new node of your content type, it should now populate the text field with whatever value you have set:

A Simple Content Type add/edit form with a default value populating the textfield.

This is probably one of the simplest uses of this functionality. Having the ability to define settings for a module provides the user with a much more configurable, and thus, re-usable piece of code and makes modules much more portable and able to be used by a wider audience. Not many people would have use for a textfield that was always populated with my name but they might be able to use that textfield as a way to define a url with a set prefix. Anywho, very useful.

Download the source for this example.

Tags: