'Teaser Thumb',
'description' => 'Add thumbnail image to teaser',
'page callback' => 'drupal_get_form',
'page arguments' => array('teaserthumb_admin_form'),
'access arguments' => array('administer site configuration'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
//------------------------------------------------------------------------------
/**
* Implementation of hook_theme()
*/
function teaserthumb_theme($existing, $type, $theme, $path) {
return array('teaserthumb_admin_form' => array(
'render element' => 'form',
),
);
}
//------------------------------------------------------------------------------
/**
* Admin settings form (module configuration page)
*/
function teaserthumb_admin_form($form, &$form_state) {
$presets = image_style_options(FALSE);
$form['teaserthumb_valid_node_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Valid node types'),
'#options' => node_type_get_names(),
'#default_value' => variable_get('teaserthumb_valid_node_types', array()),
'#description' => t('Select the node types you want to create teaser thumbnail'),
);
$form['teaserthumb_image_style'] = array(
'#type' => 'select',
'#title' => t('Thumbnail image style preset'),
'#default_value' => variable_get('teaserthumb_image_style', 'thumbnail'),
'#description' => t('Select an image module style preset to be used for generating thumbnail image.'),
'#options' => $presets,
);
$form['teaserthumb_image_align'] = array(
'#type' => 'select',
'#title' => t('Thumbnail image tag alignment'),
'#default_value' => variable_get('teaserthumb_image_align', 0),
'#description' => t('Select the "align" attribute of the img tag for the thumbnail image.'),
'#options' => array(t('None'), t('Left'), t('Right')),
);
$form['teaserthumb_min_width'] = array(
'#type' => 'textfield',
'#title' => t('Thumbnail image mininum width'),
'#default_value' => variable_get('teaserthumb_min_width', ''),
'#description' => t('Minimum width of an image to be used as a thumbnail. Leave this field blank for no minimum.'),
'#maxlength' => 10,
'#size' => 10,
);
$form['teaserthumb_min_height'] = array(
'#type' => 'textfield',
'#title' => t('Thumbnail image mininum height'),
'#default_value' => variable_get('teaserthumb_min_height', ''),
'#description' => t('Minimum height of an image to be used as a thumbnail. Leave this field blank for no minimum.'),
'#maxlength' => 10,
'#size' => 10,
);
$form['teaserthumb_position'] = array(
'#type' => 'radios',
'#title' => t('Thumbnail position'),
'#default_value' => variable_get('teaserthumb_position', 1),
'#description' => t('Select where to put the thumbnail image'),
'#options' => array(
t('Disabled (Thumbnail is not displayed)'),
t('Before the teaser body'),
t('After the teaser body'),
),
);
// create form for the draggable table
$form['priority'] = array('#tree' => TRUE);
$source_names = _teaserthumb_get_source_names();
$priorities = variable_get('teaserthumb_priorities', _teaserthumb_default_priorities());
foreach ($priorities as $priority) {
$id = $priority['id'];
$form['priority'][$id] = array(
'source' => array(
'#type' => 'item',
'#markup' => $source_names[$id],
),
'status' => array(
'#type' => 'checkbox',
'#default_value' => $priority['status'],
),
'weight' => array(
'#type' => 'weight',
'#default_value' => $priority['weight'],
'#attributes' => array('class' => array('priority-weight')),
),
);
}
_teaserthumb_debugout("--------\$form['priority']---------");
_teaserthumb_debugout($form['priority']);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
);
return $form;
}
//------------------------------------------------------------------------------
/**
* Theme function for admin form
*/
function theme_teaserthumb_admin_form($variables) {
$form = $variables['form'];
$rows = array();
$header = array(
t('Image source'),
t('Enable status'),
t('Weight'),
);
$attributes = array(
'id' => 'priority-table',
);
foreach(element_children($form['priority']) as $id) {
$rows[] = array(
'data' => array(
drupal_render($form['priority'][$id]['source']),
drupal_render($form['priority'][$id]['status']),
drupal_render($form['priority'][$id]['weight']),
),
'class' => array('draggable')
);
}
$info = t('This table determines from where the original image for the teaser thumbnail is obtained.');
$output = drupal_render($form['teaserthumb_valid_node_types']);
$output .= '' . t('Priority of image source') . '';
$output .= '
' . $info . '
';
$output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => $attributes));
$output .= drupal_render($form['common']);
$output .= drupal_render_children($form);
drupal_add_tabledrag('priority-table', 'order', 'sibling', 'priority-weight');
return $output;
}
//------------------------------------------------------------------------------
/**
* Admin form submit handler
*/
function teaserthumb_admin_form_submit($form, &$form_state) {
$priorities = array();
foreach ($form_state['values']['priority'] as $id => $priority) {
$priorities[] = array(
'id' => $id,
'status' => $priority['status'],
'weight' => $priority['weight'],
);
}
if (!empty($priorities)) {
// sort priority based on the weight
usort($priorities, '_teaserthumb_arraysort');
}
// save the settings
variable_set('teaserthumb_valid_node_types',
$form_state['values']['teaserthumb_valid_node_types']);
variable_set('teaserthumb_priorities', $priorities);
variable_set('teaserthumb_image_style',
$form_state['values']['teaserthumb_image_style']);
variable_set('teaserthumb_image_align',
$form_state['values']['teaserthumb_image_align']);
variable_set('teaserthumb_min_width',
$form_state['values']['teaserthumb_min_width']);
variable_set('teaserthumb_min_height',
$form_state['values']['teaserthumb_min_height']);
variable_set('teaserthumb_position',
$form_state['values']['teaserthumb_position']);
}
function _teaserthumb_arraysort($a, $b) {
return ($a['weight'] < $b['weight'])? -1: 1;
}
//------------------------------------------------------------------------------
/**
* Implements hook_node_view()
*/
function teaserthumb_node_view($node, $view_mode, $langcode) {
// This module works only with teaser
if($view_mode != 'teaser') {
_teaserthumb_debugout("NOP: view_mode is not teaser");
return;
}
// check if this node type is a target or not
$valid_node_types = variable_get('teaserthumb_valid_node_types', array());
if (empty($valid_node_types[$node->type])) {
_teaserthumb_debugout("NOP: this node type (" . $node->type . ") is not a target");
return;
}
$nid = $node->nid;
_teaserthumb_debugout(" ");
_teaserthumb_debugout("-----------------------------------------------------------");
_teaserthumb_debugout(" hook_node_view (nid=" . $nid . ", type=" . $node->type . ") ");
_teaserthumb_debugout("-----------------------------------------------------------");
// _teaserthumb_debugout($node);
// Load options
$image_style = variable_get('teaserthumb_image_style', 'thumbnail');
$position = variable_get('teaserthumb_position', 1);
$priorities = variable_get('teaserthumb_priorities', _teaserthumb_default_priorities());
$image_align = variable_get('teaserthumb_image_align', 0);
$align = _teaserthumb_get_align_attribute($image_align);
$img_url = '';
$loopend = FALSE;
foreach ($priorities as $priority) {
$id = $priority['id'];
if ($priority['status']) {
switch($id) {
case TT_SOURCE_IMAGEFIELD:
//----------------------------------------------------------------
// get image associated with the node (image_field)
//----------------------------------------------------------------
if ($img_url = _teaserthumb_get_thumbnail_from_imagefield($node)) {
$loopend = TRUE;
}
break;
case TT_SOURCE_BODY:
//----------------------------------------------------------------
// get image from the node body
//----------------------------------------------------------------
if ($img_url = _teaserthumb_get_thumbnail_from_body($node)) {
$loopend = TRUE;
}
break;
case TT_SOURCE_TAXONOMY:
//----------------------------------------------------------------
// get image associated with taxonomy used by the node
//----------------------------------------------------------------
if ($img_url = _teaserthumb_get_thumbnail_from_taxonomy($node)) {
$loopend = TRUE;
}
break;
}
// we found image to be used, let's exit the loop
if ($loopend) break;
}
}
_teaserthumb_debugout("----\$img_url----");
_teaserthumb_debugout($img_url);
if ($img_url) {
// e.g: public://images/sample01.jpg
// NOTE:
// image_style_path() --> does NOT cause styled image to be created
// image_style_url() --> cause styled image to be created
//
// $new_path = image_style_path($image_style, $img_url);
// _teaserthumb_debugout("----\$new_path----");
// _teaserthumb_debugout($new_path);
$new_url = image_style_url($image_style, $img_url);
// NOTE: $new_url is absolute URL.
// e.g: http://www.example.com/sites/default/files/styles/thumbnail/public/images/sample01.jpg?itok=XXXXXXX
_teaserthumb_debugout("----\$new_url----");
_teaserthumb_debugout($new_url);
/*-------- Extra (works without this section) ------*/
// convert absolute > relative URL
$host = "http://" . $_SERVER['HTTP_HOST'];
$new_url = str_replace($host, '', $new_url);
_teaserthumb_debugout("----\$new_url (relative)----");
_teaserthumb_debugout($new_url);
/*--------------------------------------------------*/
if (!empty($align)) {
$variables = array('path' => $new_url, 'attributes' => array('align' => $align, 'class' => array('teaserthumb')));
}
else {
$variables = array('path' => $new_url);
}
// theming support
$img_tag = theme('image', $variables);
// add link to the node
$img_tag = '' . $img_tag . '';
_teaserthumb_debugout("----\$img_tag----");
_teaserthumb_debugout($img_tag);
}
if (!empty($img_tag)) {
// Now construct HTML markup and insert it
if($position) {
// insert thumbnail image tag with a link to the node
// $html = ''
// . $img_tag . '';
$node->content['teaserthumbnail'] = array(
'#markup' => $img_tag,
'#weight' => ($position == 1)? -50: 50,
);
}
}
// update node teaser body (no media tags)
$body = '';
if(isset($node->content['body'][0]['#markup'])) {
$body = $node->content['body'][0]['#markup']; // teaser body
}
_teaserthumb_debugout("----\$body before _teaserthumb_strip_media----");
_teaserthumb_debugout($body);
$body = _teaserthumb_strip_media($body); // remove media tags
_teaserthumb_debugout("----\$body after _teaserthumb_strip_media----");
_teaserthumb_debugout($body);
$node->content['body'][0]['#markup'] = $body;
return;
}
//------------------------------------------------------------------------------
//
// Internal functions
//
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function _teaserthumb_get_node_full_body($node) {
// get the node body of proper language (current or undefined)
$body = field_get_items('node', $node, 'body');
// get full body
$full_body = isset($body[0]['safe_value'])? $body[0]['safe_value'] : check_markup($body[0]['value'], $body[0]['format']);
return $full_body;
}
//------------------------------------------------------------------------------
function _teaserthumb_get_source_names() {
return array(
TT_SOURCE_IMAGEFIELD => t('Image from node associated image field'),
TT_SOURCE_BODY => t('Image from node body'),
TT_SOURCE_TAXONOMY => t('Image associated with taxonomy term'),
);
}
//------------------------------------------------------------------------------
function _teaserthumb_get_align_attribute($align) {
switch($align) {
case 0:
return '';
case 1:
return 'left';
case 2:
return 'right';
}
return '';
}
//------------------------------------------------------------------------------
function _teaserthumb_default_priorities() {
$source_names = _teaserthumb_get_source_names();
return array(
array(
'id' => TT_SOURCE_IMAGEFIELD,
'source' => $source_names[TT_SOURCE_IMAGEFIELD],
'status' => 1,
'weight' => -10,
),
array(
'id' => TT_SOURCE_BODY,
'source' => $source_names[TT_SOURCE_BODY],
'status' => 1,
'weight' => -9,
),
array(
'id' => TT_SOURCE_TAXONOMY,
'source' => $source_names[TT_SOURCE_TAXONOMY],
'status' => 1,
'weight' => -8,
),
);
}
//------------------------------------------------------------------------------
function _teaserthumb_get_thumbnail_from_taxonomy($node) {
$tids = array();
$tags = field_get_items('node', $node, 'field_tags');
if (empty($tags)) {
return '';
}
foreach($tags as $index => $tag) {
if (!empty($tag['taxonomy_term'])) {
$term = $tag['taxonomy_term'];
_teaserthumb_debugout("[" . $index . "] name=" . $term->name . ", tid=" . $term->tid . ", vid=" . $term->vid);
$tids[] = $term->tid;
}
}
// the node has no taxonomy terms
if(empty($tids)) return '';
_teaserthumb_debugout("------tids------");
_teaserthumb_debugout($tids);
$img_url = '';
$files = array();
$query = db_select('file_managed', 'fm');
$query->innerJoin('file_usage', 'fu', 'fm.fid = fu.fid');
$query->fields('fm');
$query->fields('fu', array('id'));
$query->condition('fu.id', $tids, 'IN');
$query->condition('fm.status', 1);
$files = $query->execute();
if (!empty($files)) {
_teaserthumb_debugout("------teaserthumb_get_node_taxonomy_image------");
foreach ($files as $file) {
$image_info = image_get_info($file->uri);
if ($image_info) {
// this is image file
$img_urls[$file->id] = $file->uri;
_teaserthumb_debugout("Node nid:". $node->nid . " found taxonomy image: " . $file->uri. " for tid=" . $file->id);
}
}
_teaserthumb_debugout("----img_urls----");
_teaserthumb_debugout($img_urls);
// pick the image by the order of the terms user input at tag field
foreach ($tids as $tid) {
if (isset($img_urls[$tid])) {
$img_url = $img_urls[$tid];
if (_teaserthumb_validate_image_size($img_url)) {
break; // we need only the first good image found!
}
else { // NG
$img_url = '';
}
}
}
}
// $img_url - stream URI of the original image
// e.g: public://images/scaled/aaa.jpg
_teaserthumb_debugout("----returning img_url: " . $img_url . "----");
return $img_url;
}
//------------------------------------------------------------------------------
function _teaserthumb_get_thumbnail_from_imagefield($node) {
$img_url = '';
$files = array();
$query = db_select('file_managed', 'fm');
$query->innerJoin('file_usage', 'fu', 'fm.fid = fu.fid');
$query->fields('fm');
$query->fields('fu', array('id'));
$query->condition('fu.id', $node->nid);
$query->condition('fm.status', 1);
$files = $query->execute();
if (!empty($files)) {
foreach ($files as $file) {
$image_info = image_get_info($file->uri);
if ($image_info) {
// this is image file
$img_url = $file->uri;
if (_teaserthumb_validate_image_size($img_url)) {
break; // we need only the first good image found!
}
else { // NG
$img_url = '';
}
}
}
}
// $img_url - stream URI of the original image
// e.g: public://images/scaled/aaa.jpg
return $img_url;
}
//------------------------------------------------------------------------------
function _teaserthumb_get_thumbnail_from_body($node) {
global $base_url;
$img_url = '';
// obtain node teaser body and full body
if(!isset($node->content['body'][0]['#markup'])) {
return ''; // no body
}
else {
$full_body = _teaserthumb_get_node_full_body($node);
}
// remove program code section so that we do not pick up any img tag inside
$full_body = preg_replace('/.*?<\/pre>/ims', '', $full_body);
$full_body = preg_replace('/.*?<\/code>/ims', '', $full_body);
$full_body = preg_replace('/.*?<\/script>/ims', '', $full_body);
// search img tag in node's full body (not teaser body)
if ($cnt = preg_match_all('/
/imsu', $full_body, $matches)) {
// found at least one img tag
//
// $matches[0] is an array of entire matched strings
// $matches[0][0] => '
'
// $matches[0][1] => '
'
// $matches[0][2] => '
'
// $matches[1] is an array of attributes before src=
// $matches[1][0] => ' '
// $matches[1][1] => ' alt="sample" '
// $matches[1][0] => ' title="mytitle" alt="sample-ccc"'
// $matches[2] is an array of matches img src
// $matches[2][0] => '/sites/default/files/images/aaa.jpg'
// $matches[2][1] => '/sites/default/files/images/bbb.jpg'
// $matches[2][2] => '/sites/default/files/images/ccc.jpg'
// $matches[3] is an array of attributes after src=""
// $matches[3][0] => ' /'
// $matches[3][1] => ' width="1024" height="600" /'
// $matches[3][1] => ' rel="lightbox" /'
$tags = $matches[0];
$srcs = $matches[2];
// skip the image which already has a style
//
// 1. convert 1st image to thumbnail
// 2. remove all
tag
// 3. remove empty anchor tag
// 4. add thumbnail of the 1st image to the top of the body with a link to the node
for($i = 0 ; $i < $cnt ; $i++) {
$tag = $tags[$i];
$src = $srcs[$i];
// skip already styled image
/*--- do we need this? --
if(preg_match('/\/files\/styles/i', $src)) {
_teaserthumb_debugout("Skip alread styled image, src is: " . $src);
continue;
}
------------*/
$file_public_path = variable_get('file_public_path', conf_path() . '/files');
$file_public_url = $base_url . '/'. $file_public_path;
_teaserthumb_debugout("src: " . $src);
_teaserthumb_debugout("file_public_path: " . $file_public_path);
_teaserthumb_debugout("file_public_url: " . $file_public_url);
// check if this is a local file or not
$url = parse_url($src);
if (!empty($url['scheme'])) {
// absolute URL
if (strstr($src, $file_public_url)) {
_teaserthumb_debugout("OK: it is local file under Drupal public file dir");
// OK, it is local file under Drupal public file directory
$getimage_path = $src;
}
else {
_teaserthumb_debugout("NG: it is either remote file or local file outside of Drupal public file dir --> skip!");
// 1. remote file
// 2. local file but not under Drupal public file directory
// -----> skip it
continue;
}
}
else {
_teaserthumb_debugout("Neutral: it is relative path");
// relative URL
}
// Remove hostname and base URL from src
//
// From: http://www.example.com/drupal/sites/default/files/image/aaa.jpg
// To: /sites/default/files/image/aaa.jpg
//
// Note: $base_url: http://www.example.com/drupal (no trailing slash!)
// $file_public_path
//
$src = str_replace($base_url, '', $src);
$file_public_path = variable_get('file_public_path', conf_path() . '/files');
_teaserthumb_debugout("file_public_path: " . $file_public_path);
$img_url = str_replace($file_public_path, 'public:/', $src);
$img_url = preg_replace('/^\/*/', '', $img_url);
// $img_url - stream URI of the original image
// e.g: public://images/scaled/aaa.jpg
if (_teaserthumb_validate_image_size($img_url)) {
break; // we need only the first good image found!
}
else { // NG
$img_url = '';
}
}
}
return $img_url;
}
//------------------------------------------------------------------------------
function _teaserthumb_validate_image_size($img_url) {
$min_width = variable_get('teaserthumb_min_width', '');
$min_height = variable_get('teaserthumb_min_height', '');
$image_info = image_get_info($img_url);
if(!$image_info) {
_teaserthumb_debugout("NG: image_get_info(". $img_url . ") failed --> skip!");
return FALSE;
}
_teaserthumb_debugout("image_get_info(". $img_url . ") succeeded");
_teaserthumb_debugout("min_width: " . $min_width . ", min_height: " . $min_height);
_teaserthumb_debugout($image_info);
if (!empty($min_width)) {
if ($image_info['width'] < $min_width) {
_teaserthumb_debugout("NG! width is too small");
return FALSE;
}
}
if (!empty($min_height)) {
if ($image_info['height'] < $min_height) {
_teaserthumb_debugout("NG! height is too small");
return FALSE;
}
}
_teaserthumb_debugout("OK! passed the min width/height check!!");
return TRUE; // OK! can be used for a thumbnail
}
//------------------------------------------------------------------------------
function _teaserthumb_strip_media($string) {
// Remove all img tags
$img_pattern = "/
]+src=\"[^\"]+\"[^>]*>/i";
$string = preg_replace($img_pattern, '', $string);
// Remove all object blocks (video, flash)
$object_pattern = "/