Cosa sono i plug-in Ctools (tipo di contenuto, accesso, ecc.) E come si creano?


Risposte:


84

Di tanto in tanto quando si lavora con il gestore della pagina Ctools e i pannelli , è utile aggiungere plug-in Ctools personalizzati.

I plug-in di Ctools sono disponibili in molti formati e altri moduli, come Feed , Addressfield e Openlayer, fanno tutti uso di Ctools per fornire plug-in estensibili da altri moduli. Le forme più comuni di plugin, tuttavia, sono probabilmente "tipo di contenuto" e "accesso". Il primo non deve essere confuso con l'entità "contenuto" e i suoi pacchetti, detti anche tipi di contenuto.

Innanzitutto, il boilerplate :

Affinché qualsiasi modulo fornisca plugin di ctools, dovrebbero prima dire a Ctools dove cercarli. Il gancio sotto, dice che forniamo plugin per ctools, dei tipi "content_types" e "access". La funzione potrebbe essere semplificata, ma in questo modo ci assicuriamo che solo i moduli corretti vengano informati sui plug-in, oltre a fare in modo che esegua la scansione dei file sul disco solo quando forniamo effettivamente il tipo di plug-in richiesto.

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

Di seguito è riportata una struttura di directory di esempio per un modulo che fornisce due plugin. Un tipo di contenuto e un plug-in di accesso.

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

Plugin del tipo di contenuto

Un tipo di contenuto nel vocabolario di Ctools, è più spesso noto come "riquadro", come fornito ad esempio da Views. In questa domanda: esiste un modo per intercettare un elenco di NID creati da una vista e usarli come filtro per un'altra vista? , l'autore chiede di fornire a livello di programmazione argomenti a una vista. Sebbene ciò non sia molto difficile, la domanda di follow-up diventa rapidamente "Come posso visualizzare i risultati?".

Una risposta sarà quella di creare un nuovo "tipo di contenuto".

Ora, il plug-in del tipo di contenuto effettivo, utilizzando nuovamente la domanda Views dall'alto, potrebbe apparire così:

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

Con questo modulo abilitato, ora dovrebbe esserci una nuova categoria in Pannelli, 'La mia categoria personalizzata', dove in uno dovrebbe trovare un singolo riquadro, rendendo il codice dall'alto.

Accedi al plugin

Il seguente plug-in di accesso fornirà la possibilità di filtrare varianti e / o riquadri in base alla profondità di un termine misurata dalla radice del vocabolario.

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

Questo e spettacolare! Ma esiste una documentazione "ufficiale" per questo? (google trova molti post sul blog ma niente di "ufficiale" ..)
donquixote,

1
Ci sono molti esempi nel modulo ctools stesso, che è principalmente dove ho raccolto le cose. Ho provato a raccogliere il compito di scrivere documenti ufficiali da solo in più di un'occasione, ma a corto di vapore.
Letharion,

Ho un problema quando seguo questo tutorial, e cioè che il modulo di configurazione non è solo vuoto, ma manca di pulsanti.
Beth,

In qualche modo ho perso questa domanda / risposta la prima volta, fantastico scrivere!
Clive

2
@beth Il problema è $ form in module_content_type_edit_form () non deve essere passato per riferimento.
Giustino,

1

I plugin CTools sono piccoli file che possono far parte di qualsiasi modulo come modo per estenderne le funzionalità. Possono essere utilizzati per fornire componenti (riquadri), aggiungere opzioni di stili aggiuntivi ai pannelli, ecc.

Consultare la pagina Plugin CTools senza pannelli per la documentazione dettagliata. Quindi brevemente va come:

  1. Devi aggiungere dipendenze CTools nel tuo .infofile come:

    dependencies[] = ctools
    dependencies[] = panels
    
  2. Indica a CTools dove si trova il tuo plug-in:

    <?php
    function MYMODULE_ctools_plugin_directory($module, $plugin) {
      if (($module == 'ctools') && ($plugin == 'content_types')) {
        return 'plugins/content_types';
      }
    }
    ?>
    
  3. Implementa il plugin in un .incfile (di default come $module.$api.inc). Esempio di codice 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;
    }
    ?>
    

La posizione predefinita dei plugin è simile a:

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

Per ulteriori esempi, controlla il ctools_plugin_examplemodulo che fa parte del modulo CTools o controlla la pagina di aiuto ( esempi di plugin CTools ) nell'interfaccia utente di Drupal dopo aver abilitato il modulo.


In Drupal 8, questo fa ora parte del core (vedi: Drupal \ Component \ Plugin ) e fornisce l'ereditarietà degli oggetti, le interfacce degli oggetti e l'incapsulamento di un singolo file. Vedi: Drupal 8 Now: plugin orientati agli oggetti in Drupal 7

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.