¿Qué son los complementos de Ctools (tipo de contenido, acceso, etc.) y cómo se crean?


Respuestas:


84

De vez en cuando, cuando se trabaja con el Administrador de páginas de Ctools y los Paneles , es útil agregar complementos personalizados de Ctools.

Los complementos de Ctools vienen en una gran cantidad de formas, y otros módulos, como Feeds , Addressfield y Openlayers, utilizan Ctools para proporcionar complementos extensibles por otros módulos. Sin embargo, las formas más comunes de complementos son probablemente "tipo de contenido" y "acceso". El primero no debe confundirse con la entidad "contenido" y sus paquetes, también llamados tipos de contenido.

Primero, el repetitivo :

Para que cualquier módulo proporcione complementos de ctools, primero deben decirle a Ctools dónde buscarlos. El siguiente enlace dice que proporcionamos complementos para ctools, de los tipos "content_types" y "access". La función podría simplificarse, pero de esta manera nos aseguramos de que solo el módulo correcto reciba información sobre los complementos, así como de que solo escanee el disco en busca de archivos cuando realmente proporcionemos el tipo de complemento que se solicita.

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

A continuación se muestra un ejemplo de estructura de directorios para un módulo que proporciona dos complementos. Un tipo de contenido y un complemento de acceso.

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

Complemento de tipo de contenido

Un tipo de contenido en el vocabulario de Ctools, se conoce más a menudo como un "Panel", como lo proporcionan, por ejemplo, Vistas. En esta pregunta: ¿Hay alguna manera de interceptar una lista de NID creados por una vista y usarlos como filtro para otra vista? , el autor pregunta sobre la alimentación programática de argumentos a una vista. Si bien en sí mismo no es muy difícil, la pregunta de seguimiento se convierte rápidamente en "¿Cómo muestro los resultados?".

Una respuesta será crear un nuevo "tipo de contenido".

Ahora, el complemento de tipo de contenido real, nuevamente usando la pregunta Vistas de arriba, podría verse así:

$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 este módulo habilitado, ahora debería haber una nueva categoría en Paneles, 'Mi categoría personalizada', donde en uno debería encontrar un solo panel, representando el código desde arriba.

Complemento de acceso

El complemento de acceso a continuación proporcionará la capacidad de archivar variantes y / o paneles basados ​​en la profundidad de un término medido desde la raíz del vocabulario.

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

¡Esto es asombroso! ¿Pero hay alguna documentación "oficial" para esto? (Google encuentra muchas publicaciones de blog pero nada "oficial" ..)
donquixote

1
Hay muchos ejemplos en el módulo ctools en sí, que es principalmente donde recogí las cosas. Intenté retomar la tarea de escribir documentos oficiales yo mismo en más de una ocasión, pero siempre me quedo sin fuerzas.
Letharion

Tengo un problema cuando sigo este tutorial, y es que el formulario de configuración no solo está en blanco, sino que carece de botones.
beth

De alguna manera me perdí esta pregunta / respuesta la primera vez, ¡una redacción increíble!
Clive

2
@beth El problema es $ form en module_content_type_edit_form () no debe pasarse por referencia.
Justin

1

Los complementos de CTools son pequeños archivos que pueden formar parte de cualquier módulo como forma de extender su funcionalidad. Se pueden usar para proporcionar componentes (paneles), agregar opciones de estilos adicionales a sus paneles, etc.

Consulte la página Complementos de CTools sin paneles para obtener documentación paso a paso. Entonces brevemente dice:

  1. Necesita agregar dependencias CTools en su .infoarchivo como:

    dependencies[] = ctools
    dependencies[] = panels
  2. Dígale a CTools dónde se encuentra su complemento:

    <?php
    function MYMODULE_ctools_plugin_directory($module, $plugin) {
      if (($module == 'ctools') && ($plugin == 'content_types')) {
        return 'plugins/content_types';
      }
    }
    ?>
  3. Implemente el complemento en un .incarchivo (de forma predeterminada como $module.$api.inc). Código de complemento de ejemplo:

    <?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 ubicación predeterminada de los complementos se ve así:

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

Para obtener más ejemplos, compruebe el ctools_plugin_examplemódulo que forma parte del módulo CTools o consulte la página de Ayuda ( Ejemplos de complementos CTools ) en la interfaz de usuario de Drupal después de habilitar el módulo.


En Drupal 8, esto ahora es parte del núcleo (ver: Drupal \ Component \ Plugin ) y proporciona herencia de objetos, interfaces de objetos y encapsulación de archivos individuales. Ver: Drupal 8 ahora: complementos orientados a objetos en Drupal 7

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.