Que sont les plugins Ctools (type de contenu, accès, etc.), et comment les crée-t-on?

Réponses:

84

De temps en temps, lorsque vous travaillez avec Ctools Page manager et Panels , il est utile d’ajouter des plugins Ctools personnalisés.

Plugins ctools vient dans un grand nombre de formes et d' autres modules, comme aliments du bétail , Addressfield et Openlayers tout faire usage de ctools pour fournir des plugins extensibles par d' autres modules. Cependant, les formes les plus courantes de plug-in sont probablement "type de contenu" et "accès". Le premier ne doit pas être confondu avec l'entité "contenu" et ses ensembles, également appelés types de contenu.

Tout d'abord, le passe-partout :

Pour qu'un module fournisse des plugins ctools, ils doivent d'abord indiquer à Ctools où les rechercher. Le crochet ci-dessous indique que nous fournissons des plugins pour ctools, des types "content_types" et "access". La fonction pourrait être simplifiée, mais de cette manière, nous nous assurons que seul le module adéquat est informé des plug-ins, et nous ne le faisons analyser que sur le disque pour rechercher les fichiers lorsque nous fournissons le type de plug-in demandé.

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;
  }
}

Vous trouverez ci-dessous un exemple de structure de répertoire pour un module fournissant deux plugins. Un type de contenu et un plugin d'accès.

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

Type de contenu plugin

Un type de contenu dans le vocabulaire Ctools, est plus souvent appelé "volet", tel que fourni par exemple par Vues. Dans cette question: Y a - t-il un moyen d'intercepter une liste de NID créés par une vue et de les utiliser comme filtre pour une autre vue? , l’auteur s’interroge sur l’utilisation programmée d’arguments dans une vue. Bien que cela en soi ne soit pas très difficile, la question suivante devient rapidement: "Comment puis-je afficher les résultats?".

Une réponse, sera de créer un nouveau "type de contenu".

Maintenant, le plugin de type de contenu actuel, utilisant à nouveau la question de vues ci-dessus, pourrait ressembler à ceci:

$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;
}

Avec ce module activé, il devrait maintenant y avoir une nouvelle catégorie dans les panneaux, "Ma catégorie personnalisée", dans laquelle on devrait trouver un seul volet, rendant le code à partir de ci-dessus.

Plugin d'accès

Le plugin d’accès ci-dessous permettra de classer les variantes et / ou les volets en fonction de la profondeur d’un terme, mesurée à partir de la racine du vocabulaire.

<?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
la source
C'est génial! Mais existe-t-il une documentation "officielle" pour cela? (google trouve beaucoup de blogs mais rien d '"officiel" ..)
donquixote Le
1
Il y a beaucoup d'exemples dans le module ctools lui-même, qui est principalement l'endroit où j'ai pris les choses en main. J'ai essayé de prendre moi-même la tâche d'écrire des documents officiels plus d'une fois, mais je suis toujours à bout de souffle.
Létharion
J'ai un problème lorsque je suis ce tutoriel, c'est que le formulaire de configuration est non seulement vide, mais qu'il manque de boutons.
Beth
J'ai raté cette question / réponse du premier coup, génial!
Clive
2
@beth Le problème est $ form dans module_content_type_edit_form () ne doit pas être passé par référence.
Justin
1

Les plugins CTools sont de petits fichiers qui peuvent faire partie de n’importe quel module pour étendre ses fonctionnalités. Ils peuvent être utilisés pour fournir des composants (panneaux), ajouter des options de styles supplémentaires à vos panneaux, etc.

Veuillez vérifier la page Plugins sans panneaux de CTools pour une documentation étape par étape. Donc brièvement ça va comme:

  1. Vous devez ajouter des dépendances CTools dans votre .infofichier en tant que:

    dependencies[] = ctools
    dependencies[] = panels
    
  2. Indiquez à CTools où se trouve votre plugin:

    <?php
    function MYMODULE_ctools_plugin_directory($module, $plugin) {
      if (($module == 'ctools') && ($plugin == 'content_types')) {
        return 'plugins/content_types';
      }
    }
    ?>
    
  3. Implémenter un plugin dans un .incfichier (par défaut, comme $module.$api.inc). Exemple de code de plugin:

    <?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;
    }
    ?>
    

L'emplacement par défaut des plugins ressemble à ceci:

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

Pour plus d'exemples, veuillez vérifier le ctools_plugin_examplemodule faisant partie du module CTools ou consultez la page d'aide ( exemples de plug-in CTools ) dans l'interface utilisateur Drupal après l'activation du module.


Dans Drupal 8, cela fait maintenant partie du noyau (voir: Drupal \ Component \ Plugin ) et fournit l'héritage d'objet, les interfaces d'objet et l'encapsulation de fichier unique. Voir: Drupal 8 maintenant: plugins orientés objet dans Drupal 7

Kenorb
la source