Theme and Template
There are two meanings of ‘theme’ in Drupal, first one is the folder under ‘themes’ and it’s the whole presentation layer; second one is the theme API.
For the second one, Drupal have its mechanism to cast the content into the mock-ups, which’s suffix is like ‘xxxx.tpl.php’. We call the mock up is templates. It looks likes that:
/**
* This is the block.tpl.php.
*/
<div id="<?php print $block_html_id; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
<?php print render($title_prefix); ?>
<?php if ($title): ?>
<h4<?php print $title_attributes; ?>><?php print $title; ?></h4>
<?php endif; ?>
<?php print render($title_suffix); ?>
<?php print $content; ?>
Templates has the naming convention according to the different components, here’s some example:
-
Fields: field–
.tpl.php -
Nodetype: node–
.tpl.php -
Views: views-view–
.tpl.php (we can check this in view admin UI)
The theme suggestion information could be checked using dpm to check the theme suggestion
What if you would like to use some existing template but not in the suggest list? you can use
What if you would like to add some template not use that naming convention? You can use theme
function, but remember to register the theme before you use that.
/**
* Implements hook_theme().
*/
function THEME_NAME_theme() {
$path = drupal_get_path('theme', 'THEME_NAME') . '/templates';
$templates['TEMPLATE_NAME'] = array(
'template' => 'TEMPLATE-FILE',
'path' => $path,
'type' => 'theme',
);
return $templates;
}
Panelizer vs Panel
Panel is like a container to put all the different kind of components together, a component maybe a view with it’s own format, a field in the node, a block provided by the module, a custom html markup. In the panel, we call every component as pane
To organize the content better, we could use different layouts. In the layouts, we define several regions in grid system. It’s good for the responsive as well.
Here’s a sample of layout defined via ctool plugin.
$plugin = array(
'title' => t('Full'),
'category' => t('CATEGORY'),
'icon' => 'full.png',
'theme' => 'panels_full',
'css' => 'full.css',
'regions' => array(
'banner' => t('Banner'),
'body' => t('body'),
'tabs' => t('Tabs'),
'bottom' => t('Bottom'),
),
);
Panelizer is a super version of the panel. We could turn on panelizer for a content type, create several variation for this content type, and choose which node use a specific variation.
And even more, we could do some special handling base on that variation (e.g. content, layout, context) only for one node.
Ctools Plugins
Ctools module is a contributed module to provide a set of API and function, like Page Manager, Context tools, Access tools (visibility rules), configuration exportability, form wizards and so on.
And the Plugins
is one of functions this module provide. Using this tool we could extend the modules or themes with `.inc’ file. There’re 3 kinds of include file: layouts (in theme), content type and styles (in modules, feature).
content_types
ctools plugin exits in modules, it allow us to create our own panel pane that display dynamic content. In the pane, we could even setup a form to do the configuration.
In .module
file, we could use HOOK_ctools_plugin_directory
to register the plugin directory like this:
/**
* Implements hook_ctools_plugin_directory().
*/
function MODULE_ctools_plugin_directory($owner, $plugin_type) {
switch ("$owner:$plugin_type") {
case 'panels:styles':
return "plugins/$plugin_type";
case 'panels:content_types':
return "plugins/$plugin_type";
case 'ctools:content_types':
return "plugins/$plugin_type";
}
return NULL;
}
In the .inc
file itself, we will do 2 things, clarify how to render and how to finish configuration (optional).
$plugin = array(
'title' => t('TESTING'),
'description' => t('TESTING'),
'hook theme' => array(
'path' => '/PATH/TO/TEMPLATE',
'template' => 'TEMPLATE-NAME',
),
),
'settings form' => 'CALL_BACK_FUNCTION',
);
content type
plugins could also lives in features, feature recreate action will not override/ remove the registration or .inc
file. And we avoid putting content type
plugins in the theme level, as the pane could be used across different themes.
Here’s another sample for the layout include file. TBC
Form API
Form API is most used concept in Drupal. There are some many technique(trap) in there area. I list some of them I encounter in daily work.
- Method GET and POST matters, as the form token is needed.
$form['#method'] = 'get';
drupal_render_children
could help us to print the remaining items (e.g hidden fields), so we could focus on the fields we want to tailor-make.:
<div class="row collapse">
<div class="small-10 large-11 xlarge-10 columns">
<?php print render($form['search_keys']); ?>
</div>
<div class="small-2 large-1 xlarge-2 columns">
<?php print render($form['op']); ?>
<?php
// Print remaining items (hidden fields).
print drupal_render_children($form);
?>
</div>
</div>
- The class attributes should be stored in a array like this
'#attributes' => array(
'class' => array('button', 'form-submit', 'postfix', 'icon', 'icon-search'),
'id' => 'edit-submit',
),
- How to use programatically render a form.
$form = drupal_get_form('user_register_form');
print drupal_render($form);
Block and context
Block is container to wrap the content/logic provided by a module, in this aspect, it’s like the pane created by ctools. But block could be put in the region based on the context (e.g. content type, URL). You don’t need to configure the setting for every panel/node. As all the setting is done in the module itself.
/**
* Implements hook_block_info().
*/
function module_name_block_info() {
$blocks = array();
$blocks['block_name'] = array(
'info' => t('GSA Search Form'),
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function module_name_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'block_name':
$block['subject'] = '';
$block['content'] = drupal_get_form('form_id');
break;
}
return $block;
}
/**
* Implements hook_form().
*/
function module_name_form($form, &$form_state) {
$form = array(
'search_keys' => array(
'#type' => 'textfield',
'#required' => TRUE,
'#attributes' => array(
'class' => array('form-text'),
'id' => 'edit-search-keys',
'placeholder' => array('Search'),
),
'#theme_wrappers' => array(),
),
'op' => array(
'#type' => 'submit',
'#attributes' => array(
'class' => array('button', 'form-submit', 'postfix', 'icon', 'icon-search'),
'id' => 'edit-submit',
),
'#value' => 'I',
),
'#theme' => 'theme_name',
);
return $form;
}
Formatter and Widget
Drupal provide a serias field type to us, but sometimes we need some special field, like the map, icon, feature, which is combination of entity reference, existing field type, taxonomy.
In this case, we need to build a new field. And we need to answer two questions, how could we render that in page (we use formatter
), and how could we update the content in admin UI (we use widget
).
- Define how to render
formatter
:
function hook_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
$settings = $instance['widget']['settings'] + field_info_widget_settings($instance['widget']['type']);
$module_path = drupal_get_path('module', 'fcl_custom_fields');
$js_path = $module_path . '/js';
$css_path = $module_path . '/css';
switch ($display['type']) {
case 'fcl_custom_experience':
foreach ($items as $delta => $item) {
// Provide the element as a themeable item.
$element[$delta] = array(
'#theme' => 'fcl_custom_experience',
'#type' => $item['type'],
'#title' => $item['title'],
'#desc' => $item['desc'],
);
}
break;
}
}
-
Define how to render
widget
, usinghook_field_widget_form()
. -
Define how to save, using
hook_field_presave()
.
View
I touched View
in the first week I start using Drupal, so it is most basic advanced concept. View is the query UI to help us retrieve data from the DB.
fields
, type
, filter
, order
reflect the select field1, field2, ... fieldn from table where criteria1 order by key1
And the view
is doing more than the SQL GUI, it also provide the exposed filter, contextual filter to let user interact (AJAX). No return result message, header, footer is also very help to better the user experiences.
Preprocessor
This is another blog talking about the hook system.
Feature
This is a very powerful concept in Drupal. You can export the setting stored in DB to a file, in Drupal we call that ‘Feature’. Feature is very helpful in setup environment.
But in the meantime it generate a lot of problem
- It’s impossible to change one feature in the same time, the merge conflict cannot be fix, as the code is generated by the machine.
- Odd status when revert, need review, default.
- Export feature time/ resource consuming.
Javascript API
drupal_add_js
could be used to load the JS via HOOK, and weight
, position
is the option to control the loading position.
-
Drupal.setttings
is what enable us to pass information from PHP code to JS code -
Drupal.behaviors
will get called DOM has loaded (for AJAX load as well), we can usecontext
to know which DOM is being processed. -
Once
function is jQuery plugin, we can useonce()
in Drupal out of the box.
// The following will change the color of each paragraph to red, just once
// for the "changecolor" key.
$('p').once('changecolor').css('color', 'red');
How Foundation work in Drupal
Setup the font size base, use rem to setup breakpoint: small, medium, large, x-large.
Build up the variables (color, font-family)
We put grid in page.tpl.php
and layout template (used in panel) and any template.
Try to use Foundation class instead of creating customized styling.
If customized styling is needed, it means either create helper class and reuse, or create a component classes and reuse.
P.S. Drupal Exmaple module is a really good template we could start working on.
drupal variable vs drupal conf
we could get and use Drupal vaiable anywhere via drupal_get()
and drupal_set()
.
conf()
will persistent the drupl variable.
js setting
Entity and Node
@todo
We could use wrapper_metadata_entity('node', $node)
to simplify the access to fields’ value.
How to render a node depending on the place, like in detail pages we use ‘Full’, in listing we use ‘Teaser’. ‘Full’ and ‘Teaser’ is the default view_mode
of the node. We can also create a customized one to extend the use cases.
Example code?
/**
* Implements hook_entity_info_alter().
*/
function MYMODULE_entity_info_alter(&$entity_info) {
$entity_info['node']['view modes']['alternate'] = array(
'label' => t('Alternate'),
'custom settings' => TRUE,
);
}
/**
* Implements template_preprocess_node()
*/
function THEME_preprocess_node(&$variables) {
$node = $variables['node'];
$view_mode = $variables['view_mode'];
// Set up template suggestions for non-standard view modes
if ($view_mode !== 'full') {
$variables['theme_hook_suggestions'][] = 'node__' . $node->type . '__' . $view_mode;
}
}
paragraph
@todo
theme setting
Sometimes we would like to put some setting only in theme level, we could use the theme setting.
- in the
theme.info
define a setting like this:
' this setting is for the theme
['setting_name'] = ''
- define the admin UI using form api in
form['setting_name'] =
@todo
- use the theme setting in any hook like this
if @todo
drush command
Drupal provide cli utility drush
to let us finish admin job efficiently and make it posible to put all the command into shell script.
drush vset theme_debug 1
this command will turn the theme debug on, the theme hook suggestion will be printed along with the html markup.
drush cc all && drush rr
clean all the cache
drush sqlq 'select * from table limit 20'
run sql command
drush fr
revert feature
more drush command we could refer this website.