THERE IS A SNIPPET FOR THAT!

10 handverlesene Drupal snippets

Was ist ein Snippet?

Ein kleines wiederverwendbares Code-Stück

Kleines Programmierbeispiel

Mini-Modul

Beispiel

"REDIRECT USER AFTER LOGIN"

Text

/**
 * Implements hook_user_login().
 */
function MY_MODULE_user_login(&$edit, $account) {
  // Don't redirect on password reset.
  $current_menu_item = menu_get_item();
  if ($current_menu_item['path'] == 'user/reset/%/%/%') {
    return;
  }
  // Redirect user to "node/35" after the login.
  $_GET['destination'] = 'node/35';
}

Aber da gibts doch auch ein Modul?!

Modul oder Snippet?

It depends.

Vorteile von Snippets

  • Nimm dir nur den Teil raus den du benötigst

  • Exakt anpassbar an die jeweiligen Anforderungen

  • “Everything in code”

  • Am Ende schlankere Drupal Instanz mit weniger Modulen.

Wo findet man Snippets?

Warum Snippets online teilen?

  • Feedback von anderen
    • Alternative Lösungswege
    • Probleme von diesem Lösungsweg
  • "Wartung" / Maintainence der Snippets
  • Einfacher Weg etwas zurückzugeben

10 SnippetS

Wie erstelle ich ein eigenes Token?

Problem

[term:root] funktioniert nur wenn der Term nicht selbst der Root-Term ist.

 

Lösung

Neues Token [term:root-or-current] selbst implementieren.

(oder konkret: Ein "besseres" [term:root] token implementieren. 

HOOK_TOKEN_inFO

/**
 * Implements hook_token_info().
 */
function MY_MODULE_token_info() {
  
  $info['tokens']['term']['root-or-current'] = array(
    'type' => 'text',
    'name' => t('Root or current term'),
    'description' => t('Root of term or current term if it is already the root'),
  ); 
 
  return $info;
}

hook_tokens

/**
 * Implements hook_tokens().
 */
function MY_MODULE_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $sanitize = !empty($options['sanitize']);
 
  $replacements = array();

  // Our token acts on "term" entities
  if ($type == 'term' && !empty($data['term'])) {
    $term = $data['term'];
 
    foreach ($tokens as $name => $original) {
      switch ($name) {
        
        // The name matches our token!    
        case 'root-or-current':
          $parents = taxonomy_get_parents_all($term->tid);          
          $root_term = end($parents);
          $replacements[$original] = $sanitize ? 
                check_plain($root_term->name) : $root_term->name;
          break;
      }
    }
  }
 
  return $replacements;
}

Wie definiere ich einen Zusätzlichen "View-mode"?

Problem

Zusätzlich zu "Full content" und "Teaser" will ich einen weiteren "View Mode" verwenden. 

 

Lösung

hook_entity_info_alter implementieren

HOOK_entity_inFO_alter

/**
* Implements hook_entity_info_alter().
*/
function YOUR_MODULE_NAME_entity_info_alter(&$entity_info) {
  $entity_info['node']['view modes']['custom_teaser'] = array(
    'label' => t('Custom teaser'),
    // should custom settings for this view mode enabled by default
    'custom settings' => FALSE, 
  );
}

BONUS: Eigenes .tpl FÜR View-mode

/**
* Implements hook_preprocess_node().
*/
function YOUR_MODULE_NAME_preprocess_node(&$variables) {
  if ($variables['view_mode'] == 'custom_teaser') {
    // eg. "node--article--custom-teaser.tpl.php" will be used if available.
    $variables['theme_hook_suggestions'][] = 'node__' . $variables['type'] . '__custom_teaser';
  }
} 

Wie definiere ich neue date-formats in Code?

Problem

Ich will ein neues Datums Format verwenden (Beispiel: Datum soll im Format "1. Dezember" ausgegeben werden.)

 

Lösung

  1. hook_date_format_types - "Format Type"
  2. hook_date_formats  - "Format String"
  3. "Format Type" soll "Format String" verwenden

hook_date_format_types

/**
* Implements hook_date_format_types().
*/
function hook_date_format_types() {
  return array(
    'my_format'  => t('My format'),
  );
}

Drupal Beischeid geben, dass wir einen neuen Format-Type wollen.

hook_date_formats

/**
* Implements hook_date_formats().
*/
function hook_date_formats() {
  $formats = array();
  $formats[] = array(
    'type'    => 'my_format',
    'format'  => 'j. F', // eg "1. Dezember", http://php.net/manual/de/function.date.php
    'locales' => array(),
  );
  return $formats;
}

Neuen Format-String definieren.

Date Type mit Format Verbinden

// in hook_install die variable setzen
variable_set('date_format_my_format', 'j. F');  

// oder in der settings.php hardcoden
$conf['date_format_my_format'] = 'j. F';

// oder in einem Feature exportieren

Beides verbinden durch setzen einer Variable.

Bei "access denied" auf die login Seite Leiten

Problem

Bei "Access denied" soll auf die Login Seite weitergeleitet werden

 

Lösung

Eigenes menu-item implementieren, das bei Bedarf weiterleitet.

 

 

HOOK_MENU

/**
 * Implements hook_menu().
 */
function MYMODULE_menu() {
  $items = array();
 
  // custom access denied menu item (redirects to login)
  $items['access-denied'] = array(
    'page callback' => 'MYMODULE_access_denied',
    'access callback' => TRUE,   
  );
 
    return $items;
}

Page Callback

function MYMODULE_access_denied() {
  global $user;
  if ($user->uid) {
    return MENU_ACCESS_DENIED;
  }

  // The code in drupal_get_destination() doesn't preserve any query string
  // on 403 pages, so reproduce the part we want here.
  $path = $_GET['destination'];
  $query = drupal_http_build_query(
            drupal_get_query_parameters(NULL, array('q', 'destination'))
  );
  if ($query != '') {
    $path .= '?' . $query;
  }
  $destination = array('destination' => $path);
  $url = url('user/login', array('query' => $destination, 'absolute' => TRUE));
  header('Location: ' . $url , TRUE, 302);
  drupal_exit();
}

Use the new menu-item


// Tell Drupal to use the new menu-item as a 403 page. 
// For example like this:
$conf['site_403'] = 'access-denied';

Wie definiere ich ein Pseudo Field (Inkl. Bonus)?

Problem

Bei jeden Node sollen zusätzliche Daten dargestellt werden (ohne dafür ein Feld anzulegen)

 

Lösung

5 hooks und 1 callback

First, the Callback

/**
 * Getter to return the phone number.
 */
function MY_MODULE_phone($node) {
  return '089 / 12345' . $node->nid;
}

HOOK_NODE_Load

/**
 * Implements hook_node_load().
 */
function MY_MODULE_node_load($nodes, $types) {
  if (!in_array('article', $types)) {
    return;
  }
 
  foreach ($nodes as $node) {
    // add the project number to each node
    $node->phone = MY_MODULE_phone($node);
  }
}

Add the property to the node object on load.

hook_field_extra_fields

/**
 * Implements hook_field_extra_fields().
 */
function MY_MODULE_field_extra_fields() {
  $extra = array();
  $extra['node']['article']['display']['phone'] = array(
    'label' => t('Phone number'),
    'description' => t('Phone number'),
    'weight' => 10,
  );
  return $extra;
}

Make it available in the display settings of the node type.

HOOK_NODE_VIEW

/**
 * Implements hook_node_view
 */
function MY_MODULE_node_view($node, $view_mode, $langcode) {
  if ($node->type != 'article') {
    return;
  }
 
  $node->content['phone'] = array(
    '#type' => 'item',
    '#title' => t('Phone number: '),
    '#markup' => $node->phone,
  );
}

Add it to the content array when the node is viewed.

hook_entity_property_info_alter

/**
 * Implements hook_entity_property_info_alter().
 *
 * Note: This hook is provided by Entity API.
 */
function MY_MODULE_entity_property_info_alter(&$info) {
  $info['node']['bundles']['article']['properties']['phone'] = array(
    'type' => 'text',
    'label' => t('Phone number'),
    'sanitized' => TRUE,
    'getter callback' => 'MY_MODULE_phone',
  );
}

BONUS: Make it available for Entity API (Rules / Search API).

HOOK_VIEWS_DATA_ALTER

/**
 * Implements hook_views_data_alter().
 *
 * Note: This hook is provided by Views.
 */
function MY_MODULE_views_data_alter(&$data){
  // Entity API seems to add a handler, but at a different place.
  $data['node']['phone'] = $data['entity_node']['phone'];
}

BONUS: Make it available for Views.

Wie Definiere einen eigenen "Daten Filter" für DIE SEARCH API?

Problem

Daten sollen vor dem Indizieren verändert werden, zB bestimmte Nodes sollen nicht indiziert werden.

 

Lösung

1 hook und 1 Plugin

hook_search_api_alter_callback

/**
 * Implements hook_search_api_alter_callback_info().
 */
function MYMODULE_search_api_alter_callback_info() {
  $callbacks['callback_nid_filter'] = array(
    'name' => t('NID filter'),
    'description' => t('Exclude NIDs from being indexed.'),
    'class' => 'SearchApiAlterNIDFilter',
    'weight' => 100,
  );
  return $callbacks;
}

Definiere das neue Callback.

The Callback Class

class SearchApiAlterNIDFilter extends SearchApiAbstractAlterCallback {
 
  public function supportsIndex(SearchApiIndex $index) {
    return $index->getEntityType() === 'node';
  }
 
  // Implement alterItems   
  public function alterItems(array &$items) {
    $nids = array(41,52,102);
 
    foreach($nids as $nid) {
      if (isset($items[$nid])) {
        unset($items[$nid]);
      }
    } 
  } 

}

(version with config form on dropbucket.org)

files[] = includes/callback_nid_filter.inc

In MYMODULE.info

erlauben DIe eigenen Comments zu löschen

Problem

Menschen sollen ihre eigenen Kommentare löschen dürfen.

 

Lösung

Custom access callback für comment/%/delete

hook_menu_alter

/**
 * Implements hook_menu_alter().
 */
function MY_MODULE_menu_alter(&$items) {
  $items['comment/%/delete']['access callback'] = 'MY_MODULE_comment_delete_access';
  $items['comment/%/delete']['access arguments'] = array(1);
}

Change the access callback for the "delete comment" menu item.

function MY_MODULE_comment_delete_access($cid) {
  global $user;
 
  if (!user_is_logged_in()) {
    return FALSE;
  }
 
  // Allow admin to delete any comments.
  if (user_access('administer comments')){
    return TRUE;
  }
 
  // Load the comment.
  $comment = comment_load($cid);
 
  // If user is comment author ..
  if ($comment->uid == $user->uid) {
    // .. check if comment mode for this node type is flat.
    $node = node_load($comment->nid);
    $comment_mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED);
    if ($comment_mode == COMMENT_MODE_FLAT) {
      // Comment mode is flat and user is author of the comment.
      return TRUE;
    }
  }
 
  return FALSE;
}

The new access callback for the "delete comment" menu item.

Und AUs.

There is a snippet for that!

By valderama

There is a snippet for that!

  • 1,435