'admin/settings/taxonomy_quick_find',
'title' => t('Taxonomy Quick Find'),
'description' => t('Configure provided blocks'),
'callback' => 'taxonomy_quick_find_admin',
'access' => user_access('administer taxonomy'),
);
$items[] = array(
'path' => 'taxonomy_quick_find',
'callback' => 'taxonomy_quick_find_json',
'access' => user_access('access content'),
'type' => MENU_CALLBACK,
);
}
return $items;
}
/**
* Administation page. Provides a list of existing blocks along with a form to add new ones.
*
* @param string $op
* The operation being performed. Default to 'list', but can be 'delete'.
*
* @param string $delta
* Only used when $op = 'delete. Defines which block is being deleted.
*
* @return string
* Rendered Output
*/
function taxonomy_quick_find_admin($op = 'list', $delta = NULL) {
$blocks = variable_get('taxonomy_quick_find_blocks', array());
if ($op == 'delete') {
if (!is_numeric($delta) || !isset($blocks[$delta])) {
return drupal_not_found();
}
return drupal_get_form('taxonomy_quick_find_admin_confirm_delete', $delta);
}
$rows = array();
foreach ($blocks as $delta => $block) {
$row = array();
$row[] = $block['name'];
$row[] = empty($block['types']) ? ''. t('None Set') .'' : theme('item_list', array_keys($block['types']));
$ops = l(t('edit'), 'admin/build/block/configure/taxonomy_quick_find/'. $delta, array(), 'destination=admin/settings/taxonomy_quick_find');
$ops .= ' | ';
$ops .= l(t('delete'), 'admin/settings/taxonomy_quick_find/delete/'. $delta, array(), 'destination=admin/settings/taxonomy_quick_find');
$row[] = $ops;
$rows[] = $row;
}
$output = theme('table', array(t('Title'), t('Configured Types'), t('Ops')), $rows);
$output .= drupal_get_form('taxonomy_quick_find_admin_configure_block');
return $output;
}
/**
* Block delete confirmation form
*
* @param string $delta
* The delta of the block being deleted
*
* @return array
* FAPI structured array
*/
function taxonomy_quick_find_admin_confirm_delete($delta) {
$form = array();
$form['delta'] = array(
'#type' => 'hidden',
'#value' => $delta
);
return confirm_form(
$form,
t('Are you sure you want to delete this block?'),
'admin/settings/taxonomy_quick_find',
t('Note: This action cannt be undone')
);
}
/**
* Submit handler for 'taxonomy_quick_find_admin_confirm_delete' form.
*/
function taxonomy_quick_find_admin_confirm_delete_submit($form_id, $form_values) {
$blocks = variable_get('taxonomy_quick_find_blocks', array());
drupal_set_message(t('Deleted Block: %name', array('%name' => $blocks[ $form_values['delta'] ]['name'])));
unset($blocks[ $form_values['delta'] ]);
variable_set('taxonomy_quick_find_blocks', $blocks);
}
/**
* Block configuration/creation form
*
* @param string $delta
* Delta of the block being configured. If NULL, then block is being created.
*
* @return array
* FAPI structured array
*/
function taxonomy_quick_find_admin_configure_block($delta = NULL) {
if (!isset($delta) || !( $settings = _taxonomy_quick_find_get_block($delta))) {
$settings = array();
}
$form = array();
$form['tqf'] = array(
'#type' => 'fieldset',
'#title' => isset($delta) ? t('Block Settings') : t('Add Block'),
'#tree' => TRUE,
'#collapsible' => TRUE,
'#collapsed' => !isset($delta),
);
//The Block Name
$form['tqf']['name'] = array(
'#title' => t('Block Name'),
'#type' => 'textfield',
'#required' => TRUE,
'#description' => t('Human readable name for this block. This is for reference and wont be used as the block\'s title.'),
'#default_value' => isset($settings['name']) ? $settings['name'] : '',
);
//The Node Types container
$form['tqf']['types'] = array(
'#type' => 'item',
'#theme' => 'taxonomy_quick_find_admin_configure_block_node_types',
'#description' => 'A limit of zero for a node type will disable the node type. Use the weight to control the position of the node type in the block.',
'#title' => t('Node Types')
);
//create a form element for each node type consisting of a 'label' element, a limit textifield and a weight select box
foreach (node_get_types('names') as $id => $name) {
$form['tqf']['types'][$id]['label'] = array('#type' => 'markup', '#value' => check_plain($name));
$form['tqf']['types'][$id]['limit'] = array(
'#type' => 'textfield',
'#default_value' => isset($settings['types'][$id]['limit']) ? $settings['types'][$id]['limit'] : 0,
'#max_length' => 3,
'#size' => 2,
);
$form['tqf']['types'][$id]['weight'] = array(
'#type' => 'weight',
'#default_value' => isset($settings['types'][$id]['weight']) ? $settings['types'][$id]['weight'] : 0,
);
}
//Define the checkboxes array for the vocabulary configuration
foreach (taxonomy_get_vocabularies() as $v) {
$vocabs[$v->vid] = $v->name;
}
$form['tqf']['vocabs'] = array(
'#title' => t('Vocabularies'),
'#type' => 'checkboxes',
'#description' => t('Check the vocabularies you would like the terms limited to.'),
'#options' => $vocabs,
'#default_value' => isset($settings['vocabs']) ? $settings['vocabs'] : array_keys($vocabs),
);
//If there is a delta then we are editing on a block configuration, otherwise we are adding
if (isset($delta)) {
$form['tqf']['#validate']['_taxonomy_quick_find_block_configure_configure_block_validate'] = array();
}
else {
$form['tqf']['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
}
//We need a CSS file to control some layout features.
drupal_add_css(drupal_get_path('module', 'taxonomy_quick_find') .'/taxonomy_quick_find.css');
return $form;
}
/**
* Theme function for the node type container element of the above form.
*/
function theme_taxonomy_quick_find_admin_configure_block_node_types($form) {
$rows = array();
foreach (element_children($form) as $key) {
$row = array();
$row[] = drupal_render($form[$key]['label']);
$row[] = drupal_render($form[$key]['limit']);
$row[] = drupal_render($form[$key]['weight']);
$rows[] = $row;
}
return theme(
'table',
array(t('Type'), t('Limit'), t('Weight')),
$rows,
array('id' => 'block_tqf_nodetypes')
);
}
/**
* Validate callback function for the above form. This is only used for EXISTING blocks which are being edited.
*/
function _taxonomy_quick_find_block_configure_configure_block_validate($form, $form_id = NULL) {
$form_values = array();
foreach (element_children($form) as $key) {
switch ($key) {
case 'types' :
foreach (element_children($form['types']) as $typekey) {
$form_values['tqf']['types'][$typekey] = array(
'limit' => $form['types'][$typekey]['limit']['#value'],
'weight' => $form['types'][$typekey]['weight']['#value'],
);
}
break;
default :
$form_values['tqf'][$key] = $form[$key]['#value'];
break;
}
}
taxonomy_quick_find_admin_configure_block_validate(NULL, $form_values);
}
/**
* Validate hook for the add block form (plus the edit block after the above function has rebuilt some form_values).
*/
function taxonomy_quick_find_admin_configure_block_validate($form_id, $form_values) {
foreach ($form_values['tqf']['types'] as $id => $v) {
if (!is_numeric($v['limit']) || $v['limit'] < 0) {
form_set_error('tqf][types]['. $id .'][limit', t('The limit for %field must be a positive integer or zero to disable.', array('%field' => $id)));
}
}
//Check there is at least one vocabulary selected
$form_values['tqf']['vocabs'] = array_filter($form_values['tqf']['vocabs']);
if (empty($form_values['tqf']['vocabs'])) {
form_set_error('tqf][vocabs', t('You must select at least one vocabulary'));
}
}
/**
* Submit handler for block configuration/addition form
*/
function taxonomy_quick_find_admin_configure_block_submit($form_id, $form_values) {
$blocks = variable_get('taxonomy_quick_find_blocks', array());
foreach ($form_values['tqf']['types'] as $type => $settings) {
if ($settings['limit'] == 0) {
unset($form_values['tqf']['types'][$type]);
}
else {
$form_values['tqf']['types'][$type]['limit'] = (int)$form_values['tqf']['types'][$type]['limit'] ;
}
}
//Sort the types (if its an array AND the array contains more than 1 type).
if (is_array($form_values['tqf']['types']) && count($form_values['tqf']['types']) > 1) {
uasort($form_values['tqf']['types'], '_taxonomy_quick_find_type_sort');
}
//Filter the disabled vocabs out of the array - no need to store them!
$form_values['tqf']['vocabs'] = array_filter($form_values['tqf']['vocabs']);
//If delta is set, save over the old block data...
if (isset($form_values['delta'])) {
$blocks[ $form_values['delta'] ] = array(
'name' => $form_values['tqf']['name'],
'types' => $form_values['tqf']['types'],
'vocabs' => $form_values['tqf']['vocabs'],
);
}
//otherwise add a new block entry
else {
$blocks[] = array(
'name' => $form_values['tqf']['name'],
'types' => $form_values['tqf']['types'],
'vocabs' => $form_values['tqf']['vocabs'],
);
}
variable_set('taxonomy_quick_find_blocks', $blocks);
}
/**
* Implementation of hook_block().
*/
function taxonomy_quick_find_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list' :
$configured_blocks = variable_get('taxonomy_quick_find_blocks', array());
$blocks = array();
foreach ($configured_blocks as $delta => $settings) {
$blocks[$delta] = array('info' => t('TQF') .':'. $settings['name']);
}
return $blocks;
case 'configure' :
return taxonomy_quick_find_admin_configure_block($delta);
case 'save' :
taxonomy_quick_find_admin_configure_block_submit(NULL, $edit);
case 'view' :
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == '') {
return array('content' => taxonomy_quick_find_view_block($delta));
}
break;
}
}
/**
* Helper function to get the settings for a block defined by its Delta
*
* @param string $delta
* Delta identification of block
*
* @return array
* Array of settings
*/
function _taxonomy_quick_find_get_block($delta) {
$settings = variable_get('taxonomy_quick_find_blocks', array());
return isset($settings[$delta]) ? $settings[$delta] : FALSE;
}
/**
* Function to get the contents for a block. This also includes the Javascript too.
*
* @param string $delta
* Delta identification of block to be displayed
*
* @return string
* Rendered Output
*/
function taxonomy_quick_find_view_block($delta) {
if ($block = _taxonomy_quick_find_get_block($delta)) {
//Get the terms for this node
$terms = taxonomy_node_get_terms(arg(1));
//If there are no terms for the node at all then there isn't a lot of point continuing...
if (empty($terms)) {
return FALSE;
}
//Remove all terms which aren't part of the blocks "vocab" list
if (!empty($block['vocabs']) && is_array($block['vocabs'])) {
foreach ($terms as $tid => $term) {
if (!$block['vocabs'][ $term->vid ]) {
unset($terms[$tid]);
}
}
}
//One last check to see if the terms array is empty (after removing ones from excluded vocabs)...
if (empty($terms)) {
return FALSE;
}
//TODO: Find nice way to preselect a term - maybe based on where the user came from (eg, taxonomy/term/12, preselect TID:12?)
reset($terms);
$term = current($terms);
$preset = $term->tid;
//By this point there should be at least ONE term in the array,
// If there is more than 1 term, add the "select a term" AJAX menu...
// If there is ONLY 1 term, use a static link.
if (count($terms) > 1) {
//Create form - preselecting a node, if necessary...
drupal_add_js(drupal_get_path('module', 'taxonomy_quick_find') .'/taxonomy_quick_find.js');
drupal_add_css(drupal_get_path('module', 'taxonomy_quick_find') .'/taxonomy_quick_find.css');
$output = drupal_get_form('taxonomy_quick_find_block_form', $delta, $terms, $preset);
}
else {
reset($terms);
$output = theme('taxonomy_quick_find_one_term', current($terms));
}
$types = node_get_types('names');
//Render out nodes for the types...
foreach ($block['types'] as $type => $settings) {
//If the limit is, somehow, not more than 0 - use a default of '3'.
if (!($setting['limit'] > 0)) {
$setting['limit'] = 3;
}
$result = db_query('SELECT n.nid, n.title FROM {node} n INNER JOIN {term_node} tn USING (nid) WHERE n.type = "%s" AND n.status = 1 AND tn.tid = %d ORDER BY n.created DESC LIMIT %d', $type, $preset, $settings['limit']);
if ($result && db_num_rows($result) > 0) {
$items = array();
while ($node = db_fetch_object($result)) {
$items[] = l($node->title, 'node/'. $node->nid);
}
$output .= theme('item_list', $items, ucwords(t($types[$type])), 'ul', array('class' => 'tqf_'. $type));
}
else {
$output .= theme('item_list', array(t('No items found.')), ucwords(t($types[$type])), 'ul', array('class' => 'tqf_'. $type));
}
}
return $output;
}
else {
return '';
}
}
/**
* Form for the block. This provides a drop down menu of all the terms for the current node.
*
* @param string $delta
* Block Delta
*
* @param array $terms
* Array of term objects, usually provided by taxonomy_node_get_terms
*
* @param int $preset
* (Optional) Term ID for preselected term in the drop down.
*
* @return array
* FAPI structured array
*/
function taxonomy_quick_find_block_form($delta, $terms, $preset = NULL) {
$form = array();
foreach ($terms as $tid => $term) {
$terms[$tid] = $term->name;
}
$form['terms'] = array(
'#type' => 'select',
'#options' => $terms,
'#title' => t('Select a term'),
'#attributes' => array('onchange' => 'Drupal.taxonomyQuickFind('. $delta .', this);'),
'#default_value' => $preset,
);
return $form;
}
/**
* JSON Callback. Provides the nodes for the newly selected terms.
*
* @param string $delta
* Block Delta. Required so we know which node types to limit the block to
*
* @param int $tid
* Selected Term ID
*/
function taxonomy_quick_find_json($delta = NULL, $tid = NULL) {
if (is_null($delta) || is_null($tid)) {
drupal_not_found();
exit;
}
if ($block = _taxonomy_quick_find_get_block($delta)) {
$items = array();
foreach ($block['types'] as $type => $settings) {
//If the limit is, somehow, not more than 0 - use a default of '3'.
if (!($setting['limit'] > 0)) {
$setting['limit'] = 3;
}
$result = db_query('SELECT n.nid FROM {node} n INNER JOIN {term_node} tn USING (nid) WHERE n.type = "%s" AND n.status = 1 AND tn.tid = %d ORDER BY n.created DESC LIMIT %d', $type, $tid, $settings['limit']);
if ($result && db_num_rows($result) > 0) {
while ($nid = db_fetch_array($result)) {
$node = node_load($nid['nid']);
$items[$type][] = array('title' => $node->title, 'url' => url('node/'. $node->nid));
}
}
else {
$items[$type][] = array('title' => t('No items found.'));
}
}
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
print drupal_to_js($items);
ob_start();
module_invoke_all('exit');
ob_end_clean();
exit;
}
else {
drupal_access_denied();
exit;
}
}
/**
* Theme function to allow overriding of the "one term" header for nodes with only one term accessible
*
* @param object $term
* Term Object from Taxonomy_get_term
*
* @return string
*/
function theme_taxonomy_quick_find_one_term($term) {
return t('Items for !term', array('!term' => l($term->name, taxonomy_term_path($term))));
}
/**
* Private function for sorting vocabularies
*/
function _taxonomy_quick_find_type_sort($a, $b) {
if ($a['weight'] > $b['weight']) {
return 1;
}
elseif ($a['weight'] < $b['weight']) {
return-1;
}
// TODO: This isn't ideal - what to do if the weights are the same?! We dont know the name of the block here so cant do alphabetical..
return 0;
}