Forms In Drupal Overview

In this post, we cover Form API of Drupal including form creation, validation and submission.


Creating Form


There is essentially two ways with slight variation on how the form is declared and initiated.
a)Simple Form
Have a module with the moduleName.module containing the following:

/**
* Implements hook_menu().
*/
function MODULENAME_menu() {
$items['fruit/simple'] = array(
'title' => 'Form API examples',
'description' => 'Example of using the Form API.',
'page callback' => 'drupal_get_form',
'page arguments' => array('fruit_simple_form'),
'access callback' => TRUE,
);
return $items;
}

/**
* A simple form.
*/
function fruit_simple_form($form, &$form_submit) {
$form['fruit'] = array(
'#title' => t('Favorite fruit'),
'#type' => 'textfield',
'#required' => TRUE,
'#description' => t('What is your favorite fruit?'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}

The input_menu() function defines the page the end point of ‘fruit/simple’ where the form is going to be rendered (see more on Menu Sys in Drupal at post Add And Manipulate Pages).
The ‘drupal_get_form’ is an internal drupal function that returns a render array containing the form. We later define a function ‘fruit_simple_form’ that builds the render array. This function is passed as an argument to the ‘drupal_get_form’ function in line 9.

The function argument – ‘$&form_state’ (i.e. fruit_simple_form) passed to ‘drupal_get_form’ function will contain values submitted by form.

The ‘#’ symbol at beginning for each form elements are the attributes for the different input elements

If you submit this is not going to be processed till the submission function is declared

b)Creating Embedded Form
This way of creating form is good in situations when you want to add addition code or information around the form. In our example, if wanted to have a text ‘Please, choose your favorite fruit’ in front of form then:

/**
* Implements hook_menu().
*/
function MODULENAME_menu() {
$items['fruit/embedded/simple'] = array(
'title' => 'Simple',
'description' => 'Simple example using a page callback.',
'page callback' => 'fruit_simple_page',
'access callback' => TRUE,
);
return $items;
}


/**
* A simple form.
*/
function fruit_simple_form($form, &$form_submit) {
$form['fruit'] = array(
'#title' => t('Favorite fruit'),
'#type' => 'textfield',
'#required' => TRUE,
'#description' => t('What is your favorite fruit'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}


/**
* Page demonstrating embedding a form on a page.
*/
function fruit_simple_page() {
$build = array(
'header_text' => array(
'#type' => 'markup',
'#markup' => '<p>' . t('Please, choose your favorite fruit') . '</p>',
),
'example_form' => drupal_get_form('fruit_simple_form'),
);
return $build;
}

Here, the ‘fruit_simple_page’ returns the render array to our menu item with items that are going to be rendered to html page. After specifying the text around the form, we add another element on page – ‘example-form’ that is going to construct the form by calling drupal internal function drupal_get_form.

Note on drupal_render()

The drupal_render() is the function that is eventually called to render page. This function can be called on specific parts of our build array(in our case, ‘example_form’ or ‘header_text’). So if we wanted to render the form before passing it to the page callback we could do:

function fruit_simple_page() {
$build = array(
..
'example_form' => drupal_render(drupal_get_form('fruit_simple_form')),
);
return $build;

This would render the from and return to our page call back before all page is rendered. However, we want to retain the array structure of our page callback as long as possible, so the other modules can manipulate as long as they need to.

Drupal Form Validation

Drupal knows to call a validation function in two ways:

1. The name of the render array function or form id plus ‘_validate’ at the end

All functions with ‘_validate’ are searched automatically. We don’t have to register.

/**
* Validation for fruit_simple_form().
*/
function fruit_simple_form_validate($form, &$form_state) {
// Check for the fruit 'orange'.
if ($form_state['values']['fruit'] == 'orange') {
form_set_error('fruit', 'Sorry, your favorite fruit is actually apple.');
}
}
2. Register validation function by adding a function name to a from element ‘validate’

For validating some other form, we have to register our custom validation function or submission as well for that matter. There are multiple hooks to use for altering form with our custom validation function. One most general is using Hook_form_alter() as following:

function MODULE-NAME_form_alter(&$form, &$form_state, $form_id)
{
    switch ($form_id) {
        case 'OUR-FORM-ID':
            //assign validation
            $form['#validate'][] = 'our_custom_validate';
            //assign submition
            $form['#submit'][] = 'our_custom_submit';
            break;
    }
}

Since this is a general hook, we filter the form of our interest via switch statement. Afterwards, we set functions to be called for form validation and submission. In those functions(i.e. our_custom_validate, our_custom_submit) you would put logic for validating the form and form processing

Note On Validation Errors

To set validation error:

function some_validate($form, &$form_state) {
..
if (empty($form_state[values]['text'])) {
                            form_set_error('text', t('Please select an text for layer #'.$layer));
                        }
..
}

Here, we check weather the field ‘text’ is empty. If it is empty then display error message. In addition, it will highlight the form element you specified in our example ‘text’ in function form_set_error(). To find out exact element name(i.e. ‘text’) to pass in form_set_error(), look at the attribute ‘name’ value for the element

Drupal Form Submission

Drupal knows to call a submission function in two ways:
1. The name of form id plus ‘_submit’ this function will be searched automatically. We don’t have to register

function fruit_simple_form_submit($form, &$form_state) {
// Display a message upon successful submission.
drupal_set_message(t("I like @fruit, too!", array('@fruit' =>$form_state['values']['fruit'])));
}

2. Register submission function by adding to the form validate array
In the form build function add the name to handle submission

$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
'#submit' => 'name_of_function_handling_submission',
'#validate' => 'name_of_function_handling_validation',
);

function name_of_function_handling_submission($form, &$form_state){
...
}

function name_of_function_handling_validation($form, &$form_state){
...
}

Here, we first register functions to the submit element(please, see highlighted lines) to handle the submission and validation. Afterwards, those functions are implemented.

Set Variable or Save Node on Form Submission

Most of the time on submission you will save a variable or create new node with some kind of content type. To save variables:

function form_handling_submit($form, &$form_state){
variable_set('var_name',$form['field_some']['#value']);
}

Here, on form submission a value is saved for variable name ‘var_name’

To create new node instance and save it on form submission:

function collect_publication_info_form_submit($form, &$form_state) {
// Create a node object, and add node properties.
$newNode = new stdClass;//or (object) NULL
$newNode->type = 'publication';
$newNode->title = $form['first_name']['#value'].' Publication';
$newNode->language = 'und';//or LANGUAGE_NONE or language code if Locale module is enabled
$newNode->uid = 0;//or any id you wish
node_object_prepare($newNode);

//custom fields of node
$newNode->field_publisher_first_name[LANGUAGE_NONE][0]['value'] = $form['publisher_first_name']['#value'];

$newNode = node_submit($newNode);//prepare and return id
node_save($newNode);

Here a new node instance is created with content type ‘publication’ and saved in database

Explore More Form Elements and Attributes

a) Radios

$form['car'] = array(
'#title' => t('Do you own a car?'),
'#type' => 'radios',
'#options' => array('yes' => t('Yes'), 'no' => t('No')),
'#default_value' => 'yes',
'#required' => TRUE,
);

the key of the ‘#options’ is the value in the form

b) Fieldset with Textfield and Select Example
To encapsulate several other inputs.

// Demonstrating a fieldset.
$form['car_brands'] = array(
'#title' => 'Car brands',
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['car_brands']['ford'] = array(
'#title' => t('Ford'),
'#type' => 'textfield',
'#field_prefix' => t('Capital Letters'),
'#field_suffix' => t('(usa manufactured)'),
'#maxlength' => 3,
'#size' => 3,
);
$form['car_brands']['fiat'] = array(
'#title' => t('Fiat'),
'#type' => 'select',
'#options' => array(
'model1' => t('model 1.'),
'model2' => t('model 2'),
'model3' => t('model 3'),
),
);

By default, all the elements with the fieldset is passed at the same level in that from field array(in our case $form[‘car_brands’]). There is an option for ‘tree’ that will embed each fieldset element as another array within the fieldset array.

c) Help Markup Field
For situation when we want to add some info like a help info to the form without any input

$form['help'] = array(
'#type' => 'markup',
'#markup' => '<p>' . t('For more information about elements and attributes, see the <a href="!url">Form API reference page</a>', array('!url' => url('http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7'))) . '.</p>',
);

The highlighted line contains attribute ‘#type’ that specifies ‘markup’ for any time we want to add html directly to the form. The ‘#markup’ includes the html itself

States Attribute

The state attribute tells the form what different actions is associated with different state

$form['car'] = array(
'#title' => t('Do you own a car?'),
'#type' => 'radios',
'#options' => array('yes' => t('Yes'), 'no' => t('No')),
'#required' => TRUE,
);

// Demonstrating a fieldset.
$form['car_brands'] = array(
'#title' => 'Car Brands',
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#states' => array(
'visible' => array(
':input[name="car"]' => array('value' => 'yes'),
),
),
);

Here, the highlighted lines makes the fieldset visible only if car input has selected value ‘yes’. There is also ‘invisible’ state and you can add more than one condition with multiple value in the array.

In case, you need a condition for text field being filled or not, then:

...
'#states' => array(
'visible' => array(
:input[name="child_first_name"]' => array('filled' => TRUE),
),
),
...

Here the input field ‘child_first_name’ can be of type ‘textfield’, ‘textarea’.

Finding Form ID

Here are two ways to Find Form Id:

1. Put the break points in ‘hook_form_alert(&$form, &$form_state, $form_id)’ and inspect $form_id variable

Drupal during the building process of a form before its rendered goes and looks in any modules for alter functions that manipulates the form at hand. That is one way to find

2. In Firebug, inspect the form element and look for ‘id’ attribute.

The form id is set to it:

<form id="commerce-cart-add-to-cart-form-2-8" class="commerce-add-to-cart commerce-.."

Here the form id is after replacing dashes with underscores commerce_cart_add_to_cart_form_2_8

Enforcing Constraints

Drupal has really good module for enforcing constraints – fapi validation on the user input. To install:

sudo drush dl fapi_validation
drush en fapi_validation

The FAPI Validation module comes with predefined constraints(i.e. ’email’, ‘length’,etc) that you can apply to user input as following:

...
$form['some_field'] = array(
'#type' => 'textfield',
'#title' => 'Some Field',
'#required' => TRUE,
'#rules' => array(
'email',
'length[10, 50]',
),
);
...

Here, we apply email constraint with the length limit as well. Drupal also enables to apply custom constrain defined and declared by you. For more info, please, see FAPI Validation

Redirecting After Submission

Often times you will need to redirect after successful form submission. Here is one of the may ways to redirect:

function some_form_submit($form, &$form_state){
...
$newNode = node_submit($newNode);//prepare and return id
node_save($newNode);
// Display a message upon successful submission.
drupal_set_message(t("Thank You @first_name @last_name for registering and becoming a member!", array('@first_name' =>$form_state['values']['member_first_name'],                                                                              '@last_name' =>$form_state['values']['member_last_name'])));
drupal_goto($destination);

//retrieving destination path to just created node
$destination = drupal_get_path_alias("node/".$newNode->nid);
drupal_goto($destination);
}

Here, we first create an new node – member from the information provided by user and then we redirect to the page of this particular node.

Adding Configuration Fields – hook_block_configure and hook_block_save

By default, every block comes with two fields – title and body, however. It may not be enough for some blocks that you are creating. In that case, there are two hooks – hook_block_configure and hook_block_save both to add additional fields to the block.

The hook_block_configure is used to add additional fields to the block configuration form as following:

function MODULE.NAME_block_configure($delta='') {
$form = array();
switch($delta) {
case 'twitter_feed' :
// Text field form element
$form['builder_twitter_invite'] = array(
'#type' => 'textarea',
'#rows' => '3',
'#title' => t('Enter twitter invite description displayed next to tweets'),
'#default_value' => variable_get('builder_twitter_invite', ''),
);
break;
}
return $form;
}

Here we are adding additional field of type ‘textarea’ with default value retrieved from variable ‘builder_twitter_invite’. This will enable anyone to input the value via the Admin->Blocks and configure UI form

Next, the new field needs to be saved and for that the hook_block_save is used as following:

function MODULE.NAME_block_save($delta = '', $edit = array()) {
switch($delta) {
case 'twitter_feed' :
variable_set('builder_twitter_invite', $edit['builder_twitter_invite']);
break;
}
}

Here, the field is taken from the form(i.e. $edit[‘builder_twitter_invite’]) and saved in the database via the function variable_set()

File Upload With and Without Managed_File

There are two ways to upload file via Drupal Form API. One is with the managed_file functionality and another without it.

1. Without Managed_file

Without Managed_file functionality, the form element is as follows:

function some_form_gen($element, $form_state, $complete_form){
   $element['image'] = array(
        '#type' => 'file',
        '#title' => t('Image'),
        '#description' => t('Upload a file, allowed extensions: jpg, jpeg, png, gif'),
        '#default_value' => variable_get('some_variable_'.$element['#delta'],''),
   );
return $element;
}

The element for file upload is of type – file. Also, the ‘default_value’ is retrieved from Drupal variable that contains the file FID set at the validation or submission as demonstrated next (perhaps, a better practice is to store File FID in the $form_state variable) Next, the file is saved on submission as follows:

function some_form_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors){
if (!empty($item['image'])) {
                    $file = file_save_upload('image', array(
                        // Validates file is really an image.
                        'file_validate_is_image' => array(),
                        // Validate extensions.
                        'file_validate_extensions' => array('png gif jpg jpeg'),
                    ));
                    // If the file passed validation:
                    if ($file) {
                        // Move the file into the Drupal file system.
                        if ($file = file_move($file, 'public://')) {
                            // Save the file for use in the submit handler.
                            $form_state['storage']['image'] = $file;
                        }
                        else {
                            form_set_error('image', t("Failed to write the uploaded file to the site's file folder."));
                        }
                    }
                }
...
}

Here, the file is saved or copied on form validation but it may be a better practice to do it so in save function

Upload File With Managed_File

It differs that with ‘managed_file’ functionality, the file is copied in the destination and the file FID is provided in $element[‘#value’][‘image’] variable.
To create form element:

define('REV_SLIDER_DEST', 'public://slider/revolution');
define('MAX_SIZE_LIMIT_DS', (int)(ini_get('upload_max_filesize')));

function some_form_process($element, $form_state, $complete_form){
...
$element['image'] = array(
        #title' => t('Image'),
        '#type' => 'managed_file',
        '#description' => t('Upload a file, allowed extensions: jpg, jpeg, png, gif'),
        '#default_value' => isset($element['#value']['image']) ? $element['#value']['image'] : '',
        '#upload_location' => REV_SLIDER_DEST.'/img',
        '#upload_validators' => array(
            'file_validate_extensions' => array('jpg jpeg png gif'),
            // Pass the maximum file size in bytes
            'file_validate_size' => array(MAX_SIZE_LIMIT_DS*1024*1024),
        ),
    );

Here the form element is of type ‘managed_file’. The default value is retrieved from the variable $element[‘#value’][‘image’]. Next, all is left to implement validation as following:

function some_form_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors){
...
 if($item['field_remove_item'] == 0){//check if it is no ajax remove taking place when using module field_remove_item 
                    if (!isset($item['image']) || !is_numeric($item['image']) || $item['image'] == 0) {
                        form_set_error('image', t('Please select an image to upload.'));
                    }else{
                        //make file permanent 
                        $file = file_load($item['image']);
                        // Change status to permanent.
                        $file->status = FILE_STATUS_PERMANENT;
                        //all permanent files need an entry in the 'file_usage' table
                        file_usage_add($file, 'MODULE-NAME', $entity_type, $entity->nid);
                        // Save.
                        file_save($file);
                    }
}

Here, the module field_remove_item is used to have ‘Remove’ button for field instances that are more than one. This is implemented as ajax call, so to avoid the general validation, there is check using $item[‘field_remove_item’]. Afterwards, the file FID is checked to see if file is present. At last, the ‘managed_file’ functionality does copy the file into destination location and save the file info in the table ‘file_managed’, however. The saved file entry in the table is saved with status – 0 which is temporary and is removed in some certain time. So to make it permanent, the file is loaded and status set to ‘FILE_STATUS_PERMANENT’. This will ensure the file is permanently saved

Other

1. How to add ‘class’, ‘title’, ‘name’ or any attribute value to a form element?
To add an extra value for ‘class’ attribute, add the following:

$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
'#attributes' => array(
    'class' => array('text'), // change to just 'text' for Drupal 6
    'title'=>'title',
  ),
);

Here the highlighted line would add ‘text’ to the ‘class’ attribute for the submit button

2. How to add placeholder value to the input field?

function ace_form_alter(&$form, &$form_state, $form_id){
if($form_id == 'user_login'){
...
$form['name']['#description'] = '';
$form['name']['#attributes']['placeholder'] = t('Username');
}

Here, for the login form the username input take placeholder value and the description field is removed

Add Color Wheel

You may have input for choosing color. While there are many different ways to add color wheel, here we demonstrate one powered by Spectrum.js
See details post Adding Color Wheel To Form Element In Drupal

Troubleshooting

The file used in the Image field may not be referenced.

This error comes up when the file usage information is not saved in the ‘file_usage’ table at the time the file is made permanent. By adding the following fixes:

file_usage_add($file, 'MODULE-USING-FILE', 'TYPE', 'INSTANCE_ID');

Here, the module using the file is specified with the type(i.e. node, user’, etc.) of instance along the id referencing the file
This also happened when we exported artifacts and saved their FIDs in file_manage table but forgot to update the file_usage table at the same time. As result, when editing the node, we weren’t able to save any more even tho the file was present and functioning as expected

Notice: Undefined index: #field_name in file_managed_file_save_upload()

Ensure the write permissions is set for the destination specified by ‘#upload_location’ attribute

Form Snippets

1. Comment form

$comment = new stdClass;
$comment->nid = $row->nid;
$form = drupal_get_form('comment_form', $comment);

Useful Links

  • For a full list of Form API elements and attributes
  • https://api.drupal.org/api/drupal/modules%21node%21node.module/function/node_save/7
  • http://timonweb.com/how-programmatically-create-nodes-comments-and-taxonomies-drupal-7
  • https://drupal.org/project/fapi_validation
  • http://fourkitchens.com/blog/2012/07/18/building-custom-blocks-drupal-7

Add and Manipulate Pages with Menu System in Drupal

In this post, we cover different ways to add and manipulate pages with Menu System in Drupal.

Every page loaded in Drupal:

domainname.com/path/of/somekind

is transformed as following request:

domainname.com/index.php?q=path/of/somekind

This is what you will see if the ‘clean url’ setting is turned off.
In Drupal, every path is routed through single page – index.php. This is called front controller design pattern seen in many other web frameworks today. Drupal determines where to route the request by looking at the path(everything on the right of domainname.com)

Drupal takes the path and references an index it has that assigns every path to a function call. If it finds that path in the index than it calls that function and expects the function to tell Drupal what to do next. Most of the time it will provide some content to built into the final page, but it may as well redirect to go to another page or present error message like access denied

Every module determines which paths are assigned to which call back functions and all that data is stored in db table ‘menu_router’

Simple Menu Callback

In your module file MODULENAME.module, add the following:

function MODULENAME_menu() {
    $items['pages'] = array(
        'title' => 'Menu system examples',
        'description' => 'Menu system example that returns a string.',
        'page callback' => 'register_member_page',
        'access callback' => TRUE,
    );

    return $items;
}

function register_member_page() {
    $build = array(
        'header_text' => array(
            '#type' => 'markup',
            '#markup' => '<p class="lead">' . t('Membership Registration') . '</p>',
        ),
       'example_form' => drupal_get_form('collect_member_info_form'),
    );
    return $build;
}

This is implementation of hook hook_menu(). The hook_menu() expects array of call back function(i.e. register_member_page) along other info. Here the Url path defined is ‘/pages’. The ‘page callback'(i.e.register_member_page()) is the call back function routed to this url – ‘/pages’ that will tell what to do next. The ‘access callback’ specifies permissions.

We can supply content to page request in 2 ways:
1. Through string containing html and text
2. Through the build array containing content in a structred array that can be later manipulated by other modules before rendered

Next implement the page callback function ‘pages_string’ that supplies the content as simple string(Nr.1)

function pages_string() {
    $output = '
    <p>Pages can be returned as strings.</p>
    <p>Pages can be returned as <em>render arrays</em>.</p>';
    $output .= theme('item_list', array(
            'title' => 'Render arrays are better because...',
            'items' => array(
                'They allow content to be modified as an array.',
                'Arrays are a lot easier to modify than HTML.',
            ))
    );

    return $output;
}

Here we structure the output as a string and use theme(‘item_list’…) function to help construct a list order ed or unordered with heading if you wish.

Next, make sure the module is installed and go to domainname.com/pages to verity it works

How to Use Render Arrays and Tabs

When callback function returns build array instead a string, then other modules can manipulate the content by adding/removing or reorder the elements in content before its rendered

function pages_menu() {
    $items['pages'] = array(
        'title' => 'Menu system examples',
        'description' => 'Menu system example that returns a string.',
        'page callback' => 'pages_string',
        'access callback' => TRUE,
    );
    $items['pages/default'] = array(
        'title' => 'String',
        'type' => MENU_DEFAULT_LOCAL_TASK,
        'weight' => -10,
    );
    $items['pages/render-array'] = array(
        'title' => 'Render array',
        'description' => 'Menu system example using a render array.',
        'page callback' => 'pages_render_array',
        'access arguments' => array('access content'),
        'weight' => 2,
        'type' => MENU_LOCAL_TASK,
    );

    return $items;
}

Here we taken the pages content page and added two tabs. The page ‘pages/default’ is the default tab by specifying the type to default. Important to note, that the default tab doesn’t have the page callback specified, so it falls back to the parent callback function – ‘pages_string’

Another tab(‘pages/render-array’) is added with new call back function ‘pages_render_array’. This tab has access arguments. Unless boolean is specified, it expects function. If no specified as it is here, then it uses default callback ‘user_access’ and it expect permission to be passed which we do here with ‘content access’

The build render array looks as following:

function pages_render_array() {
    $build = array(
        'string_paragraph' => array(
            '#type' => 'markup',
            '#markup' => '<p>Pages can be returned as strings.</p>',
        ),
        'render_array_paragraph' => array(
            '#type' => 'markup',
            '#markup' => '<p>Pages can be returned as <em>render arrays</em>.</p>',
        ),
        'why_render_arrays' => array(
            '#items' => array('They allow content to be modified as an array.', 'Arrays are a lot easier to modify than HTML.'),
            '#title' => 'Render arrays are better because...',
            '#theme' => 'item_list',
        ),
    );
    return $build;
}

Here we specify to element to be html strings and then the third is unorder list. This is being passed to theme() function ‘item_list’ as specified

Drupal caches menu registry, so you have to tell Drupal to rebuild the registry and you can do by clearing the cache resulting to rebuild

Sub-Tabs

function pages_menu() {
...
    $items['pages/render-array'] = array(
        'title' => 'Render array',
        'description' => 'Menu system example using a render array.',
        'page callback' => 'pages_render_array',
        'access arguments' => array('access content'),
        'weight' => 2,
        'type' => MENU_LOCAL_TASK,
    );
    $items['pages/render-array/tab1'] = array(
        'type' => MENU_DEFAULT_LOCAL_TASK,
        'title' => 'Tab 1',
    );
    $items['pages/render-array/tab2'] = array(
        'title' => 'Tab 2',
        'description' => 'Demonstrating secondary tabs.',
        'page callback' => 'pages_render_array',
        'access callback' => TRUE,
        'type' => MENU_LOCAL_TASK,
    );

    return $items;
}

Here we define two new items – ‘pages/render-array/tab1’ and ‘pages/render-array/tab2’ both of which are subpages of tab ‘pages/render-array’, so its important that the sub-tab path corresponds to the pages path its sub-tab from

How to Add Page Without Menu Item

function pages_menu() {
...
        $items['pages/callback'] = array(
        'title' => 'Example of a callback type',
        'page callback' => 'pages_render_array',
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
    );
...

Here we define separate page by specifying the type to be ‘MENU_CALLBACK’ instead ‘MENU_LOCAL_CALLBACK’. After clearing cash, the new page is displayed at domain.com/pages/callback end point

How to Pass Variables Through the Path

function pages_menu() {
...
 $items['pages/argument'] = array(
        'title' => 'Argument',
        'description' => 'Menu system example using an argument.',
        'page callback' => 'pages_argument',
        'access arguments' => array('access content'),
    );
}

function pages_argument($arg1) {
    $build['argument_paragraph'] = array(
        '#type' => 'markup',
        '#markup' => '<p>' . t('The argument passed was @arg1.', array('@arg1' => $arg1)) . '</p>',
    );

    return $build;
}

The only difference is to change the callback function to accept arguments. Here the callback function ‘pages_argument’ takes an arguments. So, with path domain.com/pages/argument/hello’, the argument ‘hello’ is going to be passed to the callback function ‘pages_argument’. For more arguments you just add them to the callback function parameter. Also can use the Drupals args() function

How To Use Placeholders to Pass Arguments in Middle of the Path

When you know the beginning and the end of the path but not the middle (i.e. node/*/edit)

function pages_menu() {
...
 $items['pages/%/placeholder'] = array(
        'title' => 'Placeholder',
        'description' => 'Menu system example using a placeholder.',
        'page callback' => 'pages_argument',
        'page arguments' => array(1),
        'access arguments' => array('access content'),
    );
}

There are two places to register the placeholder in hook_menu(). In the path, by specifying ‘%’ and ‘page arguments’ attributed as highlighted above. The number 1 specifies the location(starting from 0) of the path variable of placeholder. Afterwards, this variable is passed to the callback function

How To Create Dynamic Title With Title Callback

function pages_menu() {
...
  $items['pages/title/%'] = array(
        'description' => 'Example of a dynamic title.',
        'page callback' => 'pages_render_array',
        'access callback' => TRUE,
        'title callback' => 'pages_title_callback',
        'title arguments' => array(2),
    );
...
}

function pages_title_callback($arg) {
    return 'There is an argument in this title: ' . $arg;
}

Here, we specify the title callback and pass an argument. Afterward, we declare the callback that returns a string and is rendered as title

How To Modify Page Output with hook_page_alter()

How do adjust menu items that have been defined by other modules
How do we change the value returned by callback function defined by other modules

The idea of hook_page_alter() is that before content is rendered, modules have the last chance to manipulate the rendered page content.

function THEME_page_alter(&$page) {
    $page['content']['system_main']['why_render_arrays']['#weight'] = -10;
}

Here we reorder the array so that element item list named ‘why_render_arrays’ is moved up before other elements

How To Modify Menu Items With hook_menu_alter()

Instead modifying the render array, we modify the callback function all together. We will replace one page already exist with another we defined
Anything that is defined in hook_menu will be passed through the hook_menu_alter where it can be altered one more time

function pages_menu_alter(&$items) {
    $items['admin/content']['title'] = 'The Goods';
    $items['admin/content']['page callback'] = 'pages_render_array';
}

Here we override the admin page with our own defined page as declared in callback ‘pages_render_array’

How Define Path To Be Admin

Perhaps, you would like your new custom path to be part of Admin path whether its because you like to have the page in overlay or take advantage of the admin permissions, then:

function MODULE-NAME_admin_paths() {
    $paths = array(
        'path/*/edit' => TRUE,
    );
    return $paths;
}

here all the path of pattern – “‘path/*/edit” is going to be admin path with all the admin access rights, overlay functionality,etc.

How Use Include File To Improve Performance

On every page load, every .module file got loaded for every module currently installed. If we can make the code shorter in those .module files then we can improve the performance. One way doing it is by separating out the .module code into separate include files and then use special parameter in the hook_menu() item declaration goes in fetches that include file when needed. The idea, all of the code is not needed in the .module file at the same time.

function pages_menu() {
...
$items['pages/external'] = array(
        'title' => 'External file',
        'description' => 'Example of using an include for a page callback.',
        'page callback' => 'pages_external',
        'access callback' => TRUE,
        'file' => 'pages.external.inc',
        'file path' => drupal_get_path('module', 'NAMEOFMODULE'),
    );
...
}

Here, we specify the callback function ‘pages_external’ but the function is not in the .modules file. it is in the file ‘pages.external.inc’ that we specify to load in the highlighted lines. It will only include this file, when requesting ‘pages/external’

Blocks in Drupal

In this post, we cover how to programmatically create blocks in Drupal. To create manually block in Drupal, it has to be done in a separate module and cannot be done from theme space.

Add Block in Admin UI

To add block in admin ui(structure->blocks), add the following in the .module file:

function MODULENAME_block_info(){
    $blocks = array();

    $blocks['add_to_cart'] = array(
        'info' => t('Some Theme: Add to Cart Block'),//admin ui block name
    );

    return $blocks;
}

This will show the block in admin ui from which you can assign this block to particular region

Implementing Block

In the .module file add the following:

function MODULENAME_block_view($delta = ''){
    $blocks = array();
    switch($delta){
        case 'add_to_cart':{
            $blocks['subject'] = t('Add To Cart');
            $blocks['content'] = add_to_cart_block_contents($delta);
            break;
        }
    }
    return $blocks;
}

function add_to_cart_block_contents($delta){
    $output = '';
    switch($delta){
        case 'add_to_cart':{
            $output .= '<div> Add To Cart Content</div>';
            break;
        }
    }
    return $output;
}

Here, we add a block containing the string. If your block contains a lot of code, then you can override a template file in the theme or put in separate file and include it as following:

function add_to_cart_block_contents($delta){
...
        case 'add_to_cart':{
                        $block['content'] = theme_render_template(drupal_get_path('module', 'moduleName').'/inc/block--some-theme--contact-info.tpl.php', _config_contact_info());
            break;
        }
...
}

Here the content of block is put in the file ‘block–some-theme–contact-info.tpl.php’ and then rendered into the block content. The function _config_contact_info() is for passing the variables into the template file and returns array as following:

function _config_about_author(){
    return array(
        'title' => 'Contact Info',
        'content' => 'this is block content',
        'profile_photo' => '#',
    );
}

Here we are passing three variables – title, content and profile_photo into template file that is available as ‘$title’,’$content’ and ‘$profile_photo’
You can also return already rendered block instead array before rendered:

...
$block['content'] = array(
                 '#markup' => driver_config_content($delta),
              );
...

By putting in markup tag, it is already rendered content. This will not allow other module to alter/hook into your block

Include CSS and JS files

Sometimes your block will need Js or Css files, then you can include them as follows:

...
$blocks = array();
$blocks['content'] = array(
  '#markup' => mymodule_testblock_content(),
  '#attached' => array(
      'css' => array(
        drupal_get_path('module', 'mymodule') . '/css/mymodule.css',
      ),
      'js' => array(
        drupal_get_path('module', 'mymodule') . '/js/mymodule.js',
    ),
  ),
);
return blocks;
...

Adding a Form in the Block

Here is how to add the form:

function THEMENAME_block_view($delta = ''){
    $block = array();
    switch($delta){
        case 'add_to_cart':{
            $block['subject'] = t('Add To Cart');
            $block['content'] = drupal_get_form('fav_color_form');
            break;
        }
    }
}

function fav_color_form($form, &$form_submit){
    $form['color'] = array(
        '#title' => t('Favorite color'),
        '#type' => 'textfield',
        '#required' => TRUE,
        '#description' => t('What is your favorite color? Blue? No, wait-'),
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => 'Submit',
    );
    return $form;
}

Here, we use drupal function ‘drupal_get_form’ to build the render array with an argument of name of function that constructs the render array

Pass and Access Variables

So if you want to pass a variable into the ‘variable’ array accessible in other parts (modules, themes, etc.) of the site, then:

function THEMENAME_block_view($delta = ''){
    $block = array();

    switch($delta){
        case 'add_to_cart':{
            $block['subject'] = t('Add To Cart');
            $block['some_product'] = t('Default product comes here');
            $block['default_product_price'] = some_default_product(drupal_set_page_content());
            $block['content'] = add_to_cart_block_contents($delta);
            break;
        }
}

Here, by setting $block[‘some_product’] value, it becomes available in the variables array in other parts of drupal
In case, you like to access the nodes variables in block, here we accomplish this by calling ‘drupal_set_page_contents()’ which returns variables array containing variables from the node, page and other levels

Retrieve Block To Render

Say, you want to render a block in particular place in some template file then you can retrieve and render any block as following:

...
<?php $block = block_load('MODULE_NAME','BLOCK_DELTA');?>
<?php $renderable_block =  _block_get_renderable_array(_block_render_blocks(array($block)));?>
<?php print render($renderable_block);?>

In first line, the block is loaded from module its declared. Next line converts it into renderable array before rendering in last line

Note: if the block utilizes template file that receives some variables then the above example will break because those variables are not passed to the template(see _block_get_renderable_array()). For that reason, consider using the content instead covered next.

The above example makes the block into renderable array, so you can update before rendering, however. If there is no need to make any changes, then just render content to avoid overhead of reengineering renderable array as following:

                $block_raw = block_load('MODULE-NAME', BLOCK-DELTA);
                $block_list = _block_render_blocks(array($block_raw));
                $renderable_block = array_shift($block_list);
                $variable['SOME-BLOCKE'] = render($renderable_block->content);

In line first, it loads the block. In the second line, it generates the content of the block. Afterwards, the content is extracted and rendered

Make Block Configurable

To make

function MODULE_NAME_block_configure($delta='') {
    $form = array();

    switch($delta) {
        case 'twitter_feed' :
            // Text field form element
            $form['builder_twitter_title'] = array(
                '#type' => 'textfield',
                '#prefix' => t('Title of Twitter Feed'),
                '#default_value' => variable_get('builder_twitter_title', ''),
            );
            $form['builder_twitter_invite'] = array(
                '#type' => 'textarea',
                '#rows' => '3',
                '#title' => t('Enter twitter invite description displayed next to tweets'),
                '#default_value' => variable_get('builder_twitter_invite', ''),
            );
            break;
...
return $form;
}

Here, two fields – builder_twitter_invite, builder_twitter_title is being added to the block with delta(ID) of twitter_feed’ edit form, so user can edit these fields

To process user input, function

 
function MODULE_NAME_block_save($delta = '', $edit = array()) {
    switch($delta) {
        case 'twitter_feed' :
            variable_set('builder_twitter_invite', $edit['builder_twitter_invite']);
            variable_set('builder_twitter_title', $edit['builder_twitter_title']);
            break;
...

Here, the user input is retrieved from the form and then saved into variables accordingly.

Troubleshooting

1. Notice: Undefined property: stdClass::$content in _block_get_renderable_array() (line 337 of

This was happening when calling “$ctx_plugin->block_get_blocks_by_region($region_key);”. The solution was cache the blocks before calling block_get_blocks_by_region($region_key) as following:

        $list = $ctx_plugin->block_list($region_key);
        _block_render_blocks($list);

        $ctx_blocks = $ctx_plugin->block_get_blocks_by_region($region_key);

This ensures that the ‘content’ is set before calling block_get_blocks_by_region solving the error

Useful Links

  • http://fourkitchens.com/blog/2012/07/18/building-custom-blocks-drupal-7
  • https://api.drupal.org/api/drupal/modules!block!block.api.php/function/hook_block_view/7
  • https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7#attached

Making Drupal Multilingual

This post covers steps to turn your site into multilingual site.

Installation

The following modules are required.

sudo drush dl l10n_update 
sudo drush en l10n_update 
sudo drush dl i18nviews
sudo drush en i18nviews
sudo drush dl variable
sudo drush en variable
sudo drush dl transliteration
sudo drush en transliteration
sudo drush dl i18n
sudo drush en i18n

Here, we use drush to download(dl) and enable(en) each module
The following modules also needed but you may already have it:

A quick way to verify:

drush pml | grep ctools 
drush pml | grep token 
drush pml | grep pathauto 
drush pml | grep views 

You can verify if all of the modules installed and enabled at Admin->modules:
1. Core
Contact
Locale
Content translation
2. Chaos tool suite
Chaos tools
3. Multilingual – Internationalization
Block languages
Contact translation
Internationalization
Menu translation
Multilingual content
Multilingual select
String translation
Synchronize translations
Taxonomy translation
Translation sets
Views translation
4. Other
Pathauto
Token
Transliteration
5. Variable
Variable
6. Views
Views
Views UI

1. Set Date and Time

The date is displayed different for different countries. To configure, go Admin->Configurations->Regional and language -> Data and Time and all the date formats your site is going to use

2. Add Languages

To add all of the different languages for your site by going to Admin->Configurations->Regional and language -> Languages and clicking ‘Add Language’

3. Configure Language Detection

There are several methods for your site to detect the language new visitor comes to your site. The most common is based on url(i.e. some-site.com/fr, some-site.com/lv). To configure your choice of method, go to admin->Configurations->Regional and language -> Languages -> Detection and Selection.

4. Add Language Switcher

The multilingual modules come with a block that enables user to switch the language. Incorporate the block in your site wherever you wish by going to Admin->Structor->Block and selecting the region for the Language switcher block

5. Turn on Content Types

Next, turn on multilingual support for each of the content by going to admin->structure->content types->’some type’. Then under ‘Publishing Options’ enable the multilingual support. You have to do this for all content types

6. Add Translation

Open to edit any of the content pages that you would like to translate. In the edit mode, there should be a tab – Translate. In the ‘Translate’ section, click on ‘Add Translation’

7. Make Admin Always One Language

By default, after you add translation to one of the content nodes, automatically the whole admin section is also in that language. To keep one default langauge for Admin section, install module ‘admin language’:

drush dl admin_language
drush en admin_language

Afterwards, configure the admin language under ‘Admin -> Configurations -> Region and Langauge -> Languages -> Admin Language’

Site Menu Altered for Multilingual Support

When multiple languages is enabled for a site and the language detection configured, then the main menu contains multiple links each different language for the same page. Here is custom code snippet from template.tpl.php to filter menu links specific to currently selected language:

    //load all menu links
    $mainMenuArray = menu_load_links('main-menu');
    $finalMainMenu = array();//array holding the final menu
    foreach($mainMenuArray as $key=>$menuItem){
        global $language;//retrieves all languages configured
        $currentLang = $language->language;
        if($menuItem['language'] == 'und'){
//for default language still set the language code
            $menuItem['language'] = language_default('language');
        }
//filter all menu links of currently selected language
        if($currentLang == $menuItem['language'] ){
            $linkPath = $menuItem['link_path'];
            $linkPathAlias = drupal_get_path_alias($linkPath, $currentLang);
            $currentUrl = drupal_get_path_alias($_GET['q'],$currentLang);

            if($currentUrl == $linkPathAlias){
//decorate the link of currently selected page
                $finalMainMenu[$key]['active'] = 'muted-img';
            }
            $finalMainMenu[$key]['url'] = $linkPathAlias;
            $finalMainMenu[$key]['title'] = $menuItem['link_title'];
        }
    }
    $vars['mainMenu'] = $finalMainMenu;

Here all links of the main menu is loaded including different language then traveled through and only set ones that are of the selected langauge

XML Sitemap for Each Language

Make user to generate XML sitemap for each language. Go to Admin->Configurations->Search And Metadate -> Xml Sitemap and click ‘Add New XML Sitemap’ to generate a new sitemap

Useful Sources

https://drupal.org/node/1268692

Drupal Commerce Install and Setup

Before installing, here is a list of modules required for Drupal Commerce module:

Installing and Enabling Drupal Commerce

We use Drush to install and enable commerce module as following:

sudo drush dl rules
sudo drush dl views
sudo drush dl entity
sudo drush dl addressfield
sudo drush en rules views entity addressfield
sudo drush dl commerce
sudo drush en commerce commerce_ui commerce_product commerce_product_ui commerce_product_reference commerce_cart commerce_customer_ui commerce_line_item_ui commerce_order_ui commerce_payment commerce_payment_ui commerce_product_pricing_ui commerce_product_pricing_ui commerce_tax commerce_tax_ui

To check which modules are enabled and which not but,perhaps, need to be, run the following:

drush pml | grep commerce

This will display all modules associated with drupal commerce along the status if enabled or not

Summary of all commerce modules:

commerce_tax, commerce_tax_ui, commerce_product_reference, commerce_product_pricing, commerce_product_pricing_ui, commerce_product, commerce_product_ui, commerce_price, commerce_payment_example, commerce_payment, commerce_payment_ui, commerce_order, commerce_order_ui, commerce_line_item, commerce_line_item_ui, commerce_customer, commerce_customer_ui, commerce_checkout, commerce_cart, commerce, commerce_ui.

Overview

In the following are steps to set up commerce functionality in the Drupal site:

1. Add Product Type
2. Add Taxanomy

Each taxanomy element is an product attribute such as size, color, etc. Later in the product display page, user will be able to select product attribute and that product will be displayed available to added in shopping cart a functionality that comes with the commerce module out of the box.

3. Add Content Types

This is a Content Type for displaying each product individually

Step-1: Creating Product Types

Go to ‘Admin/Store/Products/Product Types’ and add new product type such as ‘themes’. We are going to sell Drupal themes just like in our store Designs Square

Step-2: Adding Attributes

In order to add attributes to products, we first create these attributes by creating taxanomies for each attribute and adding items that are the attribute values. To add the taxanomies go to ‘Admin/Structure/Taxonomy/Add Taxonomy’

Step-3: Attach Attributes to Product

Go to Product Type(such as ‘theme’) and in ‘manage fields’ section, add a new field with type of ‘Term Reference’. Afterwards, specifying which taxonomy reference is this. Now your product have a product attribute.

!!!make sure select ‘Enable this field to function as an attribute field on Add to Cart forms’ under the ‘Attribute Field Settings’ section, so that when user selects this attribute in the display product page, the product with the particular attributed is displayed and available to add in shopping cart

Step-4: Add Products

To add a product, go to ‘Admin/Store/Products/Add Product’ and select the type of product(i.e. ‘theme’). Do all variations as each separate product

Step-5: Add Displays

1. Create Content Type(for example, ‘Product Display’)
To create Content Type, go to ‘Admin/Structure/Content Types/Add Content Type’ and type ‘Product Display’. Afterwards, add new field with type of ‘Product Reference’ field and select all the product types related to the display (in our case, we have only one product type – ‘theme’ )

2. Add Display for Each Product
Next, we add all of the products each at the time by going to ‘Admin/Content/Add Content/Product Display’, and create a product display(for example, Drupal Newspaper Theme – Newscast). Afterwards, select associated products under the ‘Products Reference’ select box (for example, for the Drupal Newspaper Theme – Newscast we have ‘Basic Light Newscast Theme’, ‘Plus Dark Newscast Theme’,etc )

Test Drive

Without the Payment System configured, you should be able to test it. If your page.tpl.php is customized, make sure you have the default page.tpl.php for the following templates files:

  • page–checkout.tpl.php
  • page–cart.tpl.php
  • page–YOUR-DISPLAY-TYPE.tpl.php

Go to your product display page(Admin/Content/Product_Name) and walk through the checkout process

Configuring Payment System

Required Modules: commerce_payment, commerce_payment_ui
!Consider enabling payments example(commerce_payment_example)

Payment Method 1 – PayPal
A. Set up PayPal account at developer.paypal.com
B. Install PayPal module as follows:

sudo drush dl commerce_paypal
sudo drush en commerce_paypal
sudo drush en commerce_paypal_ec
sudo drush en commerce_paypal_wps

C. Configure payment method. (store->configuration-payement methods)
a) Click ‘enable’
b) Click ‘edit’ and add the email under Payment Settings
!To turn on live, just select radio button for ‘live’
Payment Method 2 – Authorize.Net
1. Create Test Account with Authorize.net
2. Install Module ‘commerce_authnet’
3. following the same steps as configuring PayPal Payment method
Payment Method 3 – Stripe (Our Favorite)
1.create account
2. install drupal module ‘commerce_stripe’
3. Download strip-php lib and put it in sites/all/libraries/stripe-php
4. configuring Payment method
5. Enable Permissions for the not authenticated visitors. Otherwise, the ‘check out’ button will not show up
To see cards available for test see https://stripe.com/docs/testing

Taxes

Required Modules – commerce_tax, commerce_tax_ui

sudo drush dl commerce_tax
sudo drush en commerce_tax
sudo drush dl commerce_tax_ui
sudo drush en commerce_tax_ui

To add tax rate, go to ‘Admin/Store/Configuration/Taxes/Add tax rate’
Make sure the Rate is in decimal format
Drupal comes with two tax types – Sales and VAT each describing when applied
The ‘Tax rates’ deals with how much of the taxes
The taxes automatically show up at the checkout.

Order

All about orders are in ‘Admin/Store/Orders’
! You can add fields to the orders. To do so go to ‘Admin/Store/Configurations/Orders Settings’

Other

Commerce module also adds the following entities:

  • customer profiles
  • products
  • line items
  • payment transactions

Things to know about Line Items

  • show up in order
  • none taxable
  • cannot create but it is created by modules installed
  • To view line items, go to ‘Admin/Store/Configuration/line items’

Things about Rules

  • example – send email to customer after checkout
  • Good for applying taxes on certain location using rules see Lynda.com

To Set limits on products use Commerce_Stock and go to ‘Admin/Store/Configuration/Stock management’. Once enabled all products, it will have additional field to specify size

Setting Up Email To Notify When Order Received
Go to ‘Admin/Configuration/Workflow/Rules/Send an order notification e-mail/Add New Action/Send Mail’. This will send email whenever an new order is made

Each purchase create customer profile a snapshot of time. good for collecting additional info.

Commerce Product Display Manager Module
To better manage views/admin product displays. See more at https://drupal.org/project/commerce_product_display_manager

Commerce VBO Views
Edit/Create/administer products

Issues

1. the ‘attribute field setting’ is missing for the products field with ‘term reference’
Make sure the module ‘commerce_cart’ is enabled

Useful Links

  • http://www.youtube.com/watch?v=gLO7nt48omE&list=UUwY8NJJnQtMs1NBbOTvHdmQ
  • http://www.slideshare.net/willhall/things-i-wish-i-knew-about-drupal-commerce-12546226

Module Development in Drupal

In this post, we cover different aspects for developing modules in Drupal including creating modules, setting variables and other

Creating Module

Modules location

  • The /modules folder that is reserved for core is not good location for your custom modules
  • The good location is /sites/all/modules folder to keep the contributed and custom modules(/sites/all/modules/contr or /sites/all/modules/custom)

Modules Naming

  • keep lower case
  • its not good practice to include numbers

->the modules description along the name and core version is stored in .info files as following:

name = Sample Module
description = sample module description
core = 7.x
version = 7.x-0.1-dev ;to show up in the admin ui
package = Block Wrapper
files[] = nameOfModule.module
dependencies[] = module1
configure = admin/config/moduleName ;this adds configuration button next to module name in modules list

In order to show up in core admin UI, need .module file. It can be empty but required. Documentation can be included

/**
*@file
*Custom functionally for your custom module
*/

Try, clear cache and check to install the module from admin/modules interface

Create Module Admin Interface

Once installed, next we create an admin UI interface to be able edit configurations and settings of the custom module. To do so, we are going to use hook_config_menu:

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

    //Admin config group
    $items['admin/config/kapasoft'] = array(
        'title' => 'Kapasoft',
        'description' => 'Configure Interface with Driver',
        'access arguments' => array('administer kapasoft configurations'),
    );

    //admin configuraiton - settings
    $items['admin/config/kapasoft/manage'] = array(
        'title' => 'Kapasoft configuration',
        'description' => 'Manage Kapasoft Interface config settings',
        'access arguments' => array('administer kapasoft configurations'),
        'page callback' => 'drupal_get_form',
        'page arguments' => array('kapasoft_config_form'),
    );

    return $items;
}

Here we create the module’s admin page – ‘manage’ in admin UI section ‘admin/config/kapasoft’. Next, clear the cache and see if it appears in the admin menu

You should see an error, because in the ‘page callback’ we specify function that builds a form but its not yet declared. Lets do it now

Admin Menu Form

Here, we create a form displayed in admin UI for our module to manipulate settings. In last step, we specified the function(i.e kapasoft_config_form) that builds the form. Now, we implement it as follows:

function kapasoft_config_form($nodes, &$form_state){
    $form = array();

    $form['overview'] = array(
        '#markup' => t('This interface allows to manage KapaSoft modules Settings'),
        '#prefix' => '<p>',
        '#suffix' => '</p>',
    );

    $form['interface_config'] = array(
        '#title' => t('Interface Config'),
        '#description' => t('Configurations of Driver'),
        '#type' => 'fieldset',
        '#collapsible' => TRUE,
        '#collapsed' => FALSE,
    );

    $form['interface_config']['driver_url'] = array(
        '#title' => t('Driver Url'),
        '#description' => t('url of the driver'),
        '#type' => 'textfield',
        '#default_value' => 'localhost',
        '#required' => TRUE,
    );

    $form['interface_config']['driver_port'] = array(
        '#title' => t('Driver Port'),
        '#description' => t('port of the driver'),
        '#type' => 'textfield',
        '#default_value' => '3000',
        '#required' => TRUE,
    );

    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Save'),
    );
    return $form;
}

Here we add two fields and set default values. Afterwards, clear the cache and go to the admin UI (admin/config/kapasoft/manage) to see the form with default settings.

Make Data Persistent

One of the ways Drupal provides ability to persist almost any type of data are through the variable_get, variable_set and variable_del API. Good for settings but shouldn’t be used for content

Lets, adjust our default values:

function kapasoft_config_settings_form($nodes, &$form_state){
...
 $form['interface_config']['driver_url'] = array(
        '#title' => t('Driver Url'),
        '#description' => t('url of the driver'),
        '#type' => 'textfield',
        '#default_value' => variable_get('kapasoft_driver_url', 'localhost'),
        '#required' => TRUE,
    );

    $form['interface_config']['driver_port'] = array(
        '#title' => t('Driver Port'),
        '#description' => t('port of the driver'),
        '#type' => 'textfield',
        '#default_value' => variable_get('kapasoft_driver_port', 3000),
        '#required' => TRUE,
    );
}

In the highlighted lines, the default value is retrieved from variable. If the variables hasn’t been set,yet, then it sets to the default values as specified(i.e. ‘locahlost’, 3000))

At submission, lets save the new variables as well:

function kapasoft_config_form_submit($form, &$form_state){
    //rebuild the form
    $form_state['rebuild'] = TRUE;

    //Save kapasoft setting variables
    variable_set('kapasoft_driver_url', $form_state['values']['driver_url']);
    variable_set('kapasoft_driver_port', $form_state['values']['driver_port']);
 
    //notify user
    drupal_set_message(t('kapasoft driver settings are saved'));
}

At form submission, the values from the form is taken and saved using the variable_set API

Variable_get With Defaults

So far as implemented, it only works with the form. If the form is not submitted, variables are not saved.

In addition, defaults are set in dozen places that don’t scale. In another words, we would have to edit code for each instance of variable_get/variable_set if the default value changes

So, we going to use hook_install to set the default variables once at the time module is installed. This hook is placed in moduleName.install file as following:

function kapasoft_config_install(){
    //set default variables
    variable_set('kapasoft_driver_url', 'localhost');
    variable_set('kapasoft_driver_port', '3000');

    //get localization function for installation as t() may not be available
    $t = get_t();

    //give user feedback
    drupal_set_message($t('Kapasoft driver configurations created'));
}

function kapasoft_config_uninstall(){
    //Delete variables
    variable_del('kapasoft_driver_url');
    variable_del('kapasoft_driver_url');
    
    //get localization function for installation as t() may not be available
    $t = get_t();
    
    //give user feedback
    drupal_set_message($t('Kapasoft driver configurations removed'));    
}

Next, remove all default values from moduleName.module file, so there is single point of initialization for defaults in the moduleName.install file(i.e. make variable_get(‘kapasoft_driver_url’, 3000) to variable_get(‘kapasoft_driver_url’))

Adding Configuration Button

To add a configuration button next to module name in the modules list, add the following line in the modulesName.info file:

...
configure = admin/config/kapasoft/manage

Here the path ‘admin/config/kapasoft/manage’ is the path specified in the moduleName_config_menu() function above

Shorten Code

We can shorten code by completely removing submit function(i.e kapasoft_config_settings_form_submit()) and let the Drupal built in mechanism handle our form submission by updating the form build function as follows:

function kapasoft_config_form($nodes, &$form_state){
...
//    $form['submit'] = array(
//        '#type' => 'submit',
//        '#value' => t('Save'),
//    );

    return system_settings_form($form);
}

As you see, we uncomment the submit button and return Drupal function ‘system_settings_form() with an argument that contains our admin form. This will handle the submission, save the variables and display the message to user. Note, make sure the variable names are the same as specified in form.

Load Other Modules

To utilize other modules within your module, all you need is to load it as following:

module_load_include('inc', 'location', 'earth');
module_load_include('inc', 'gmap3_tools');

This loads the ‘location’ and gmap3_tools modules. Afterwards, you are able to use any of their modules API

How To add Content Type

Here is a great article Creating Custom Content Type…

How to add Block

see post Blocks in Drupal

Troubleshooting

1. Form structure and values
When implementing form validation, it may be useful to print out the form structure

function bazar_node_form_validate($form, &$form_state){
    //to see what validated - the structure
    dpm($form_state);
    //purposely set error
    form_set_error('','testing');

The ‘bazar_node_form_validation’ is custom form validation function added to the list of function names that are used to validate the form in hook_form_alter:

/**
 * implements hook_form_alter()
 */
function bazar_form_alter(&$form, &$form_state, $form_id){
    //like to add validation but i don't know the form id
    dpm($form_id);
    //i would like to see the structure of the form
    dpm($form);
    //return to browser, clear craches and go to form

    //Afterwards, we can turn on debuging only for our form of interest. From the form id we can figure out the validation callback function to be bazar_node_form_validate
    switch($form_id){
        case 'bazar_node_form':{
            //dpm($form);
            //look for #validate that takes list of function names that are used to validate the form. I can ad custom funciton to this array
            $form['#validate'][] = 'bazar_node_form_validate';
            break;
        }
    }
}

Here, we are adding custom validation function ‘bazar_node_form_validate’ to the form with id ‘bazar_node_form’

2. Verify variables loaded
Here is an example to find out what variables are loaded for your theme function(the theme hook specifies theme funciotn)

function theme_ThemeName_gmap($variables){
    dpm($variables);
}

This will print out all the variables passed to this theme. The theme funciton ‘theme_ThemeName_gmap’ was specified in the theme_hook

Useful Links

  • https://api.drupal.org/api/drupal/

Externalizing Configurations in Drupal, Node.js and Grails

In this post, we cover how configurations can be externalize for platform Drupal and frameworks Node.js, Grails. By externalizing configurations, it becomes easer to deploy and move around applications and libraries.

Drupal

There are two approaches
1. Configurations in file
In the sites/default/settings.php add the configurations as follows:

$conf['global_driver_url'] = 'localhost';
$conf['global_driver_port'] = '3000';

The $conf is Drupals global variable array as described here
Then to access it anywhere as follows:

global $conf;
var driverPort = $conf['global_driver_port'];
var driverUrl = $conf['global_driver_url'];

So, here you reference the global variable $conf and then access any variables you wish

2. Configurations from User
We create a content type that contains the configurations. For example, we have content-type name ‘Interface Configurations’ with machine name ‘interface_configurations’

Then in preprocessor in template.php file, we load it as follows:

$nid_config = db_select('node', 'n')
        ->fields('n', array('nid'))
        ->fields('n', array('type'))
        ->condition('n.type', 'interface_configurations')
        ->execute()
        ->fetchCol();
    //load the configurations
    $configurationNode = node_load($nid_config);
    $interfaceConfig = array();
    $interfaceConfig['driver_url'] = $configurationNode->field_driver_url['und'][0]['value'];
    $interfaceConfig['driver_port'] = $configurationNode->field_driver_port['und'][0]['value'];
    $vars['interfaceConfig'] = $interfaceConfig;

Here, we first retrieve the Id of the configuration node containing the configurations. Afterward, it is loaded and values retrieved. At last, it is put in $vars array, so it is available in the html template

Node.js

There are several ways doing it in Node.js and there are some modules such as nconf for the that purpose. In the following, is one way of externalizing configurations in Node.js framework:
1. we create config.js that contains configurations and place it in root folder as follows:

var config = {}

config.controller_url = process.env.CONTROLLER_URL || '/minnehaha';
config.controller_host = process.env.CONTROLLER_HOST || 'localhost';
config.controller_port = process.env.CONTROLLER_PORT || 8010;

module.exports = config;

Here we first declare variable config that will hold the configurations. Then assign our configurations. The ‘process’ contains the command line Node.js variables. So, if you like to have environment based configurations such as dev, prod, etc, then you will have to if/switch condition on ‘process.env.NODE_env’ variable.

Important to note, that the ‘process.env’ queries all of the command environment variables(i.e. PATH,GRAILS_HOME,etc.), so you have access to all of them.

At last, we make or configurations available anywhere in Node.js applications in the next step

2. To make these configurations available, we import the module and then access the configurations as follows:

var config = require('./../config');
...
   var options = {
        host: config.controller_host,
....

Here, the config module is imported and assigned to ‘config’ variable after which the configurations are accessed

Grails

For external configurations in Grails framework,please, see post Externalizing Configurations Per Grails Application

Useful Links:

  • http://stackoverflow.com/questions/5869216/how-to-store-node-js-deployment-settings-configuration-files
  • http://devincarlson.ca/blog/configuring-drupal-use-proxy-server-when-making-external-http-requests

Upgrading Drupal Core and Modules via Drush

There may be a time when it is a time to upgrade your drupal core and modules. It may also be a situation, when some feature or functionality doesn’t work as it should be. In that case, it may be that one of the modules are out of date causing it malfunction.

Its recommended to back up the database and the code of the Drupal site before upgrading

Step 1. Check The Status

To check status on what is out of date or which module has an upgrade available run:

drush cron

This will update the ‘Status Report’. To see the report, login as Admin and go to Reports->Status Report

Step 2. Upgrade Modules and the core

To upgrade the modules and the core, run

drush upc

This will start an interactive mode and walk through the process upgrading each module and eventually the core

To see available options ‘drush upc –help’ in situations where you don’t want to update core but only modules, for example

drush upc --no-core

This will only update modules and skip the core update.

Step 3. Updating Database

To update database, run

drush updb

This will run all database updates
To see available options run ‘drush updp –help’

Step 2 & 3: To upgrade code and database at once

To upgrade modules, core together with database udpates, run:

drush up

Its combines the step 2 and 3. For finding available options, run ‘drush up –help’

Other

1. Find Current project info

drush status

This will display current Drupal and Drush vers, database driver, php configuration, etc.

Useful Lins

Updating drupal core and modules

Drupal install with Drush

In this posts, we list steps to install Drupal site utilizing Drush

Tested: Drush 5.8, Mac 10.7.5, MySQL 5.0.10

Step-1. Download and Install

1)Download Drupal
To download Drupal, run the following in command line:

drush pm-download drupal

This creates folder drupal-x.ver and downdloads drupal. if need specific version, then replace ‘drupal’ to ‘drupal-7.18’ for example

drush pm-download drupal-7.18

2) Rename default folder
After downloading drupal, the drupal code is in default folder – drupal-x.ver. Perhaps, you like to move into name of your website.

sudo mv drupal-7.18 nameOfMySite

3)Create and Set up Database(DB)
Here is how to setup database from the command line interface:

mysql -u USER -p
mysql>create database NAME_OF_NEW_DB;
mysql>GRANT ALL PRIVILEGES ON NAME_OF_NEW_DB.* TO db_user@'localhost' IDENTIFIED BY 'db_passwd';
mysql>flush privileges;

In line one, we login the mysql server run locally. In line two, the new database is created with name ‘NAME_OF_NEW_DB’. In line three, a new user is crated for the new database and all privileges are granted for that user. In last line, the cache is flushed for our changes to take an effect.

4) Install Drupal
Install Drupal as follows:

cd nameOfMySite
sudo drush si --db-url=mysql://dbUser:dbPass@localhost:3306/nameOfDb --account-pass=adminPassword

Here the dbUser, dbPass and nameOfDb are the credentials created in step 3

Besides installing Drupal, it also configures database. The ‘–acount-pass=adminPassword’ specifies password for admin user for the Drupal website.

5. Configure Local DNS
To rout the request to your local drupal instance, update the hosts file. For Unix based systems, it is located at /etc/hosts. If your local domain name is going to be test.com, then insert the following line in the /etc/hosts file:

127.0.0.1       test.com

6. Configure Virtual Host
At last, configure the virtual host for your new site in Apache web server. Depending where is your Apache Web server installed and what version, the location for virtual host settings my differ. In our case, it is located at apacheRoot/conf/extra/httpd-vhosts.conf. So, to configure the virtual host for our new drupal instance, we would insert the following:

 
...
<VirtualHost *:80>
    DocumentRoot "/path/to/drupal_root_dir"
    ServerName test.com
    <Directory /path/to/drupal_root_dir>
        Options FollowSymLinks
        AllowOverride All
    </Directory>
</VirtualHost>
...

In line 3 and 5, the directory of our new drupal site is installed. In line 4, the local domain that we configured in previous step is specified.
Afterwards, Restart Apache server to reload virtual hosts configurations

service apache2 restart

or

sudo /root/To/Apache/dir/bin/apachectl restart

This will restart Apache and load the new configurations
!Some Apache Web Server versions need specifically enable the virtual host, then

sudo a2ensite yoursite

7. Test it!
Open browser and point it to the test.com. If it doesn’t work, see the Troubleshooting section below for help.

Step-2 Set up Root directory

If your web server is configured to service the drupal site from the subfolder than:
a)Specify directory from where the drupal site is serviced from.
In  the .htaccess(in site root folder) uncomment line “ReriteBase/drupal” and updated it to the location of your site:

RewriteBase /PathToSite

b)Configure the Drupal base Url
To configure Drupal base, uncommenting $base_url in settings.php file( usually in sites/default/settings.php) as follows:

$base_url = 'http://www.example.com/pathToSite'; 

Media Modules

For making it possible to insert images into text area using WYSIWYG, there are two modules if using WYSIWYG module for your editor solution:

If you are using CKEditor Module for editor solution instead, then the IMCE module is sufficient

The CKEditor works with the above modules. There is currently issue with WYSIGWYG default module to work with CKEditor, but solution is to use the dev(7.x-2.x-dev) module of WYSIGWYG

Step-3 Install other Useful modules

a) JQuery Update – updated jquery module for drupal core (http://drupal.org/project/jquery_update)

drush dl jquery_update-7.x-2.x-dev -y
drush en jquery_update-7.x-2.x-dev -y

Note:As you see, we chose the dev version of jquery_update to ensure it contains lates jquery lib version, however, in your case it may be different. Afterwards, select jquery version you wish your drupal site uses by going into admin->modules->jquery_update->Configure and select version

b) Twitter Bootstrap – see post ‘Installing Twitter Bootstrap with Drupal

c) WYSIWYG [wysiwyg] – install necessary module before downloading and configuring one of the wysiwyg editors. To install:

drush dl wysiwyg
sudo drush en wysiwyg

Once module wysiwyg installed, then enabled it in Admin->Modules->Check ‘wysiwyg’ module and save. Next, press ‘configure’ to see all the available wysiwyg editors with instructions how to install and enable any from the list. Our favorite – WYMEditor

!Alternative to WYSIWYG module is CKEditor Module. While it is limited to CKEditor, it is slick and can be configured well.

d) Admin Menu [admin_menu]- makes the admin menue items to drop down in hierarchal manner instead one level
To install:

drush dl admin_menu
sudo drush en admin_menu

e) Path Auto [pathauto] – provides an option to alias url to whatever you choose or auto generate alias url from title field.

drush dl pathauto
sudo drush en pathauto

Note: the module ‘pathauto’ dependes on module ‘token’. If installed via drush, then the dependency is installed automatically

f) Date [date] – adds field type of Date with nice date picker UI. To install:

drush dl date
sudo drush en date

Afterwards, enable the time pop-up picker in the Admin->Modules section

g) Views[views] – enable to create views that is an excellent feature to aggregate content in custom way for front page or any section  of the page for that matter. To install:

drush dl views
sudo drush en views

Note: You may be interested in better_exposed_filters module for exposing more enhanced filters to user
Note: the module ‘views’ has dependency of module ‘ctools’ that is auto installed with drush

h)Database Migration – for backing up and migrating database, the backup_migrate is good choice

i)Botcha – to stop spam at form submission including user registertion

Step-4 Developers Modules

a)Theme Developer[devel_themer] – helps to see templates used any page, profiling db queries, generate content and other cool stuff. To install:

drush dl devel_themer
drush en devel_themer

!If you install not via drush then make sure your install also the dependencies. With Drush, it does automatically
Few tools from Theme Developer:

  • Go to Structure->Blocks and enable Develpers block. In the Developers blog you can select ‘devel setting’ to enable profiling DB queries
  • Go to Configuration->Development->Generate Content. This generates some content to work with
  • Select ‘Themer info’ right bottom corner to see what templates called, events triggered and variable renedered

b) Block Class IU[block_class] – it enables to add css styling to any block from UI never need to go into code
To install:

drush dl block_class
drush en block_class

c) Install firebug for Drupal. In Firefox select Tools->Add On->Search with keyword ‘firebug’ and select Drupal Firebug add on. Afterward, restart firefox.
That installs for the browser, but then for firebug support in your drupal development site:

drush dl drupalforfirebug
drush en drupalforfirebug

d) Advanced Help [advanced_help] – To access advanced help index (good for developing views). To install

drush dl advanced_help
drush en advanced_help

e)Examples For Developers – examples for custom module development

drush dl examples
drush en examples

f) Coffee[coffee] – is great UI feature to get around quickly. By pressing AlT+D, it opens the input box where you can type the module or admin functionality you want to get/edit or configure. Afterwards, click the link to go there

g)Module Filter [module_filter] – for assistance on navigating around the modules, the module_filter module is great by filtering and adding extra menu in modules section.

h) Module Instructions[module_instructions] – pulls up all ReadMe files easy available to read in the Modules section

Transform for Versioning and Exporting

Drupal has a way to convert all site or parts of the sites functionality into features for ability to version it into code as well as easy migrating. Here are all the modules that will do the work for Drupal 7:
a)Features – makes it easy for you to export features that is content types, views, etc all of which can be called configurations and content Structure. It packages into a custom module that you can transfer on another Drupal instance

b) uuid features – is integration for Features module that adds a capability for exporting content itself not only the content structure. It also supports file exports, services. Make sure you specify which content structures enabled for the feature module at ‘admin/config/content/uuid_features’. Make sure also create missing UUIDs at admin/config/system/uuid

c)StrongArm – It provides ability to feature variables and configurations

d)commerce_features – it provides ability to feature commerce customer profiles, products, tax rates and types.

d)features_extra – One of the features_extra submodules is fe_blocks. This provides an ability to convert block configurations. This especially useful if your site is using context for organizing blocks and you need disable all the blocks in the ‘structure/blocks’

SEO Modules

Besides ‘autopath’ module for url naming, here are other useful SEO related modules

a) XMLSiteMap
[xmlsitemap] – generates xml site map that is submitted to search engines

b) Site Verify
[site_verify] – provides an easy way to verify your site with search engines

c) SEO Checklist
[seo_checklist] – provides a check list for SEO of your site

c) Google Analytics
[google_analytics] – enables google analytics in site

Other

a) Add This
[addthis] – enables your site users to vote and plus(+1) your products

b) Add To Any
[addtoany] – helps readers share, bookmark, and email your pages and articles (aka stories) using any service, such as Facebook, Twitter, Google+, Pinterest, and other.

c)Enable Menu Title in HTML
Twitter Bootstrap and other CSS styling frameworks often use icons class to insert icons in front of title. By default, Drupal doesn’t permit the title contain html. There is a moduel menu_html that allows easy enable title be html

d)Reference Entities
Entity Reference helps to reference other elements. Really good for building some complex data structures vi UI like photo gallery,podcast,etc.

Troubleshooting

1. Error:

Drupal requires you to enable the PHP extensions in the following list (see the system requirements page for more information):gd
Looks like  missing php5-gd2.so lib. Run:

sudo port install php5-gd2
sudo port activate php5-gd2

2. Error:
Command site-install needs a higher bootstrap level to run - you will[error] need to invoke drush from a more functional Drupal environment to run this command.
Make sure you are in the directory of drupal that was downloaded in step 1.

3. Error:

...SQLSTATE[HY000] [1045] Access denied for user 'someuser'@'localhost...

Apparently, the mysql user provided to drush unable connect database. Ensure the user is remote localhost enabled. Here is how to test:

mysql -u someuser -p -h localhost

If not then, you have to enable it as remote user as follows:

mysql>GRANT ALL PRIVILEGES ON *.* TO someuser@'localhost' IDENTIFIED BY 'db_passwd';
mysql>FLUSH PRIVILEGES;

This will make user ‘someuser’ as remote access user from ip of ‘localhost

Rewrite Fails:
If you able to load from root but unable to go any other pages of the drupal website then it likely an issue with rewrite. To troubleshoot, first check that appache is loading mod_rewrite:

apachectl -t -D DUMP_MODULES

This displays all modules loaded by apache web service. Look to see if ‘rewrite_module’ is present. If it is, then ‘rewrite’ loads, but, apparently, it hasn’t been configured correctly. One way is to have virtual host configuring your drupal portal including rewrite as well:

...
<VirtualHost *:80>
    DocumentRoot "/Users/user/Sites/drupal_root"
    ServerName drupal-test.com
    <Directory /Users/user/Sites/drupal_root>
        Options FollowSymLinks
        AllowOverride All
    </Directory>
    ErrorLog "/private/var/log/apache2/drupal-test.com-error_log"
    CustomLog "/private/var/log/apache2/drupal-test.com-access_log" common
</VirtualHost>
...

The highlighted lines configure the overwrite. The DocumentRoot is folder where your drupal site is serviced from. The ServerName is your configured local DNS name in /etc/hosts file. Put this in your /etc/apache2/extra/httpd-vhosts.conf and uncomment the following line in http.conf:

...
Include /private/etc/apache2/extra/httpd-vhosts.conf

This will make apache load this virtual host configuration.

4. Error:
After login as admin, there is following error:

  file_put_contents(temporary://devel_themer/: failed to open stream: DrupalTemporaryStreamWrapper::stream_open" call failed in devel_themer_store_krumo() 

Apparently, Drupal(devel_themer module) uses local file system for storing temporary files. Make sure the temp folder for drupal got permissions to write. Go to Administration >> Configuration >> Media >> File system and look ‘Temporary Directory’ to find out where is the folder located. Afterwards, enable write permission

5. PDOException: SQLSTATE[HY000] [2002] Connection refused in lock_may_be_available() [..] includes/lock.inc drupal

This error is because Drupal unable to connect to MySQL database. You can double check your DB configurations in settings.php by connecting manually from command line as follows:

mysql -u userName -p -h hostName

Where the userName and hostName is the value from the db configuration in settings.php. Most likely, you don’t have a user with that hostname in the database. To check, run:

SELECT user FROM mysql.user;

And look for the username as well as the hostName. If it doesn’t exist then to create one:

GRANT ALL PRIVILEGES ON db_name.* TO db_user@'hostname' IDENTIFIED BY 'db_passwd';

Photo Gallery with Drupal

This post covers how to make photo gallery in drupal 7

Core Modules required:

  • field
  • field storage
  • field ui
  • file
  • image
  • overload (not necessary but make better experience)

Other Modules

Creating Multiple Photo Galleries

1. Create Content Type – Photo. The fields added are image, a little description and title in our case.
2. Configure image field for colorbox. In ‘manage display’ select format ‘colorbox’ with following settings:

  • Content Image style = thumbnail
  • Colorbox image style = large
  • Gallery = per page gallery
  • This are the ‘full content’ settings

3. Create Content Type – Gallery
4. Add new field of type ‘Entity Reference’ for the content type – Gallery.
This field used to able select photos that is assigned to a Gallery

  • Set Number of values unlimited so as all photos assigned to the gallery got to be displayed
  • For setting ‘Entity Selection’, choose the content type ‘Photo Page’

  • Under ‘Manage Display’ select Format to be ‘Render Entity’. Make sure that this setting is also for ‘Full Content’ and not only ‘Default’ configurations

Note: I went back and updated Teaser for the Photo Page Content type. Afterwards, updated the gallery new field to use ‘Teaser’ instead ‘Full content’ when rendering photos. It provided more flexibility while keeping the Photo page full content as needed.
5. Assigning Photos to the Gallery
From any galleries page, select photos that are associated with the gallery. Afterwards, in the gallery page, all of those photos will be rendered. Clicking on any of the images will start the colorbox widget that you enables scroll through all the images. By clicking on title, it will redirect to the photo page itself

Things To Find Out

1. How to display gallery with relationship from photo to gallery?
The above example is when the relationship between Photos and Gallery is in the direction from Gallery to the Photo. However, it may be desireable to specify gallery from the photo page. In another words, have the relationship from photo to gallery and then render those photos in the Gallery. This was covered in the YouTube How To Make Gallery in Drupal 7 but seems incomplete
2. How to reference a view instead photo page in the Gallery page?
In the above example, we referenced to Photo page in the gallery page, however. Instead referencing the photo page, it may be desirable to reference a view that way giving more flexibility. I got stuck when trying to reference view instead of photo page. Here are my steps:
Steps 1-3 the same as listed above
Step 4. Create a view of type – ‘Entity Reference’ named with machine name ‘bildes_galerija’. Make sure select searchable fields at format->Entity Reference list->Settings
Step 5. Reference a view. For content type – Gallery, created new image field as type of ‘Entity Reference’. In the configuraitons under the ‘entity selection’, select ‘view:filter by the entity view filter’.

With this, i anticipated that the photos in the gallery page is going to be render like the view specified, however. it render the same way as it did when referencing Photo Page.

Useful Links:



http://groups.drupal.org/node/147189