Was sind Ctools-Plugins (Inhaltstyp, Zugriff usw.) und wie werden sie erstellt?

56

Was sind Ctools-Plugins und wie erstellt man sie?

Letharion
quelle

Antworten:

84

Bei der Arbeit mit Ctools Page Manager und Panels ist es von Zeit zu Zeit hilfreich, benutzerdefinierte Ctools-Plugins hinzuzufügen.

Ctools-Plugins gibt es in einer Vielzahl von Formen, und andere Module wie Feeds , Adressfelder und OpenLayer verwenden Ctools, um Plugins bereitzustellen, die durch andere Module erweiterbar sind. Die gebräuchlichsten Formen von Plugins sind jedoch wahrscheinlich "Inhaltstyp" und "Zugriff". Die erste darf nicht mit der Entität "Inhalt" und ihren Bündeln, auch Inhaltstypen genannt, verwechselt werden.

Zunächst das Boilerplate :

Damit ein Modul ctools-Plug-ins bereitstellt, muss es Ctools zunächst mitteilen, wo es nach ihnen suchen soll. Der folgende Haken besagt, dass wir Plugins für ctools vom Typ "content_types" und "access" bereitstellen. Die Funktion könnte einfacher gemacht werden, aber auf diese Weise stellen wir sicher, dass nur das richtige Modul über die Plugins informiert wird und dass es die Festplatte nur nach Dateien durchsucht, wenn wir tatsächlich den Typ des gewünschten Plugins bereitstellen.

function HOOK_ctools_plugin_directory($owner, $plugin_type) {
  // We'll be nice and limit scandir() calls.
  if ($owner == 'ctools' && ($plugin_type == 'content_types' || $plugin_type == 'access')) {
    return 'plugins/' . $plugin_type;
  }
}

Im Folgenden finden Sie eine Beispielverzeichnisstruktur für ein Modul, das zwei Plugins bereitstellt. Ein Inhaltstyp und ein Zugriffs-Plugin.

module/
module/module.info
module/module.module
module/plugins/
module/plugins/content_types/
module/plugins/content_types/two_views_in_one.inc
module/plugins/access/
module/plugins/access/term_depth.inc

Inhaltstyp-Plugin

Ein Inhaltstyp im Ctools-Vokabular wird häufiger als "Bereich" bezeichnet, wie dies beispielsweise in Ansichten angegeben ist. In dieser Frage: Gibt es eine Möglichkeit, eine Liste von NIDs, die von einer Ansicht erstellt wurden, abzufangen und als Filter für eine andere Ansicht zu verwenden? fragt der Autor nach der programmgesteuerten Eingabe von Argumenten in eine Ansicht. Während das an sich nicht sehr schwer ist, wird die Folgefrage schnell zu "Wie zeige ich die Ergebnisse an?".

Eine Antwort wird darin bestehen, einen neuen "Inhaltstyp" zu erstellen.

Nun könnte das Plugin für den eigentlichen Inhaltstyp unter Verwendung der obigen Frage "Ansichten" folgendermaßen aussehen:

$plugin = array(
  'title' => t('Render a View with arguments from another'),
  'single' => TRUE,
  'category' => array(t('My custom category'), -9),
  // Despite having no "settings" we need this function to pass back a form, or we'll loose the context and title settings.
  'edit form' => 'module_content_type_edit_form',
  'render callback' => 'module_content_type_render',
);

function module_content_type_render($subtype, $conf, $args, $context = NULL) {
  $block = new stdClass;
  $block->title = 'My View';

  $view = views_get_view('get_nids');
  $view->preview('display_machine_name', array($arg1, $arg2));

  $nids = '';
  foreach($view->result as $node) {
    $nids += $node->nid . ',';
  }
  $nids = rtrim($nids, ',');
  $view = views_get_view('get_related');
  $view->execute_display('display_machine_name', array($nids));
  $block->content = $view->render();

  return $block;
}

/**
 * 'Edit form' callback for the content type.
 */
function module_content_type_edit_form($form, &$form_state) {
  // No settings beyond context, which has already been handled.
  return $form;
}

Wenn dieses Modul aktiviert ist, sollte es jetzt eine neue Kategorie in den Bereichen "Meine benutzerdefinierte Kategorie" geben, in der sich ein einzelner Bereich befinden sollte, in dem der Code von oben dargestellt wird.

Zugriffs-Plugin

Das folgende Access-Plugin bietet die Möglichkeit, Varianten und / oder Fenster basierend auf der Tiefe eines Begriffs, gemessen an der Wurzel des Vokabulars, auszufiltern.

<?php
/**
 * @file
 * Plugin to provide access control based upon a parent term.
 */

/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */
$plugin = array(
  'title' => t("Taxonomy: term depth"),
  'description' => t('Control access by the depth of a term.'),
  'callback' => 'term_depth_term_depth_ctools_access_check',
  'default' => array('vid' => array(), 'depth' => 0),
  'settings form' => 'term_depth_term_depth_ctools_access_settings',
  'settings form validation' => 'term_depth_term_depth_ctools_access_settings_validate',
  'settings form submit' => 'term_depth_term_depth_ctools_access_settings_submit',
  'summary' => 'term_depth_term_depth_ctools_access_summary',
  'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')),
);

/**
 * Settings form for the 'term depth' access plugin.
 */
function term_depth_term_depth_ctools_access_settings($form, &$form_state, $conf) {
  // If no configuration was saved before, set some defaults.
  if (empty($conf)) {
    $conf = array(
      'vid' => 0,
    );
  }
  if (!isset($conf['vid'])) {
    $conf['vid'] = 0;
  }

  // Loop over each of the configured vocabularies.
  foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) {
    $options[$vid] = $vocabulary->name;
  }

  $form['settings']['vid'] = array(
    '#title' => t('Vocabulary'),
    '#type' => 'select',
    '#options' => $options,
    '#description' => t('Select the vocabulary for this form. If there exists a parent term in that vocabulary, this access check will succeed.'),
    '#id' => 'ctools-select-vid',
    '#default_value' => $conf['vid'],
    '#required' => TRUE,
  );

  $form['settings']['depth'] = array(
    '#title' => t('Depth'),
    '#type' => 'textfield',
    '#description' => t('Set the required depth of the term. If the term exists at the right depth, this access check will succeed.'),
    '#default_value' => $conf['depth'],
    '#required' => TRUE,
  );

  return $form;
}

/**
 * Submit function for the access plugins settings.
 *
 * We cast all settings to numbers to ensure they can be safely handled.
 */
function term_depth_term_depth_ctools_access_settings_submit($form, $form_state) {
  foreach (array('depth', 'vid') as $key) {
    $form_state['conf'][$key] = (integer) $form_state['values']['settings'][$key];
  }
}

/**
 * Check for access.
 */
function term_depth_term_depth_ctools_access_check($conf, $context) {
  // As far as I know there should always be a context at this point, but this
  // is safe.
  if (empty($context) || empty($context->data) || empty($context->data->vid) || empty($context->data->tid)) {
    return FALSE;
  }

  // Get the $vid.
  if (!isset($conf['vid'])) {
    return FALSE;
  }
  $depth = _term_depth($context->data->tid);

  return ($depth == $conf['depth']);
}

/**
 * Provide a summary description based upon the checked terms.
 */
function term_depth_term_depth_ctools_access_summary($conf, $context) {
  $vocab = taxonomy_vocabulary_load($conf['vid']);

  return t('"@term" has parent in vocabulary "@vocab" at @depth', array(
    '@term' => $context->identifier,
    '@vocab' => $vocab->name,
    '@depth' => $conf['depth'],
  ));
}

/**
 * Find the depth of a term.
 */
function _term_depth($tid) {
  static $depths = array();

  if (!isset($depths[$tid])) {
    $parent = db_select('taxonomy_term_hierarchy', 'th')
      ->fields('th', array('parent'))
      ->condition('tid', $tid)
      ->execute()->fetchField();

    if ($parent == 0) {
      $depths[$tid] = 1;
    }
    else {
      $depths[$tid] = 1 + _term_depth($parent);
    }
  }

  return $depths[$tid];
}
Letharion
quelle
Das ist fantastisch! Aber gibt es dafür eine "offizielle" Dokumentation? (google findet viele blog posts aber nichts "offizielles" ..)
donquixote
1
Es gibt viele Beispiele im ctools-Modul selbst, in dem ich hauptsächlich Dinge aufgegriffen habe. Ich habe mehr als einmal versucht, selbst offizielle Dokumente zu schreiben, aber es geht mir immer die Puste aus.
Letharion
Ich habe ein Problem, wenn ich diesem Tutorial folge, nämlich, dass das Konfigurationsformular nicht nur leer ist, sondern keine Schaltflächen enthält.
Beth
Irgendwie habe ich diese Frage / Antwort beim ersten Mal verpasst, tolles Schreiben!
Clive
2
@beth Das Problem ist $ form in module_content_type_edit_form () sollte nicht als Referenz übergeben werden.
Justin
1

CTools-Plugins sind kleine Dateien, die Teil jedes Moduls sein können, um dessen Funktionalität zu erweitern. Sie können verwendet werden, um Komponenten (Fenster) bereitzustellen, Ihren Fenstern zusätzliche Stiloptionen hinzuzufügen usw.

Bitte überprüfen Sie die CTools Plugins ohne Panels Seite für eine schrittweise Dokumentation. So kurz geht es:

  1. Sie müssen CTools-Abhängigkeiten in Ihre .infoDatei einfügen als:

    dependencies[] = ctools
    dependencies[] = panels
  2. Teilen Sie CTools mit, wo sich Ihr Plugin befindet:

    <?php
    function MYMODULE_ctools_plugin_directory($module, $plugin) {
      if (($module == 'ctools') && ($plugin == 'content_types')) {
        return 'plugins/content_types';
      }
    }
    ?>
  3. Plugin in eine .incDatei implementieren (standardmäßig als $module.$api.inc). Beispiel für einen Plugin-Code:

    <?php
    $plugin = array(
      'title' => t('Twitter feed'),
      'description' => t('Twitter feed'),
      'category' => 'Widgets',
      'icon' => '',
      'render callback' => 'twitter_block',
      'defaults' => array(),
    );
    
    // render callback
    function twitter_block() {
      // Add twitter widget javascript
      $url = TWITTER_USER
      $widget_id = TWITTER_WIDGET_ID;
      $data = array();
    
      $data['url'] = $url;
      $data['widget_id'] = $widget_id;
    
      $content = array(
        '#theme' => 'my_block',
        '#content' => $data,
      );
    
      $block = new stdClass();
      $block->content = $content;
      $block->title = '';
      $block->id = 'twitter_block';
    
      return $block;
    }
    ?>

Der Standardspeicherort der Plugins sieht folgendermaßen aus:

MYMODULE/
    plugins/
        content_types/
        templates/
    MYMODULE.info
    MYMODULE.module  

Weitere Beispiele finden Sie im ctools_plugin_exampleModul CTools oder auf der Hilfeseite ( CTools-Plugin-Beispiele ) in der Drupal-Benutzeroberfläche, nachdem Sie das Modul aktiviert haben.


In Drupal 8 ist dies nun Teil des Kerns (siehe: Drupal \ Component \ Plugin ) und bietet Objektvererbung, Objektschnittstellen und Einzeldateikapselung. Siehe: Drupal 8 Jetzt: Objektorientierte Plugins in Drupal 7

Kenorb
quelle