Що таке плагін Ctools (тип вмісту, доступ тощо) та як їх створювати?


Відповіді:


84

Раз у раз під час роботи з менеджером сторінки Ctools і панелями корисно додавати плагіни Ctools.

Плагіни Ctools надходять у великій кількості форм, а інші модулі, такі як канали , адресне поле та Openlayers, використовують Ctools для надання додатків, розширюваних іншими модулями. Однак, найпоширеніші форми плагіна - це "тип вмісту" та "доступ". Перший не слід плутати з сутністю "content" та її пакетами, які також називаються типами вмісту.

По-перше, плита котла :

Щоб будь-який модуль надав плагіни ctools, вони повинні спочатку повідомити Ctools, де їх шукати. Гак внизу говорить про те, що ми надаємо плагіни для ctools, типів "content_types" і "access". Функцію можна зробити простішою, але таким чином ми гарантуємо, що тільки потрібний модуль розповість про плагіни, а також лише скануючи диск на наявність файлів, коли ми фактично надаємо тип плагіна, про який вимагають.

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

Нижче наводиться приклад структури каталогів для модуля, що забезпечує два додатки. Один тип вмісту та один плагін доступу.

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

Плагін типу вмісту

Тип вмісту в словнику Ctools частіше відомий як "Панель", як це передбачено, наприклад, Views. У цьому запитанні: чи є спосіб перехопити список створених представленням NID і використовувати їх як фільтр для іншого перегляду? , автор запитує про програмне подання аргументів на думку. Хоча в цьому самому це не дуже важко, подальше запитання швидко стає "Як відобразити результати?".

Одна з відповідей - створити новий "тип контенту".

Тепер власне плагін типу вмісту, знову використовуючи запитання Views зверху, може виглядати так:

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

Якщо цей модуль увімкнутий, тепер у Панелях має з’явитися нова категорія - «Моя спеціальна категорія», де в одній слід знайти одну область, що надає код зверху.

Доступ до плагіна

Плагін доступу нижче забезпечує можливість вибору варіантів та / або панелей на основі глибини терміна, виміряної від кореня словника.

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

Це круто! Але чи є на це «офіційна» документація? (Google знаходить багато публікацій у блозі, але нічого "офіційного" ..)
donquixote

1
У самому модулі ctools є чимало прикладів, де я передусім підбирав речі. Я не раз намагався підібрати завдання писати офіційні документи, але завжди вистачає пари.
Летаріон

У мене є одна проблема, коли я слідую за цим підручником, і це те, що форма конфігурації не тільки порожня, але і не має кнопок.
beth

Я якось пропустив це питання / відповідь перший раз, дивовижно написати!
Клайв

2
@beth Випуск $ форми у module_content_type_edit_form () не повинен передаватися посиланням.
Джастін

1

Плагіни CTools - це невеликі файли, які можуть бути частиною будь-якого модуля як спосіб розширити його функціонал. Їх можна використовувати для надання компонентів (панелей), додавання додаткових параметрів стилів на ваші панелі тощо.

Перегляньте сторінку плагінів CTools без панелей для покрокової документації. Отже коротко:

  1. Вам потрібно додати залежності .infoфайлів CTools у свій файл як:

    dependencies[] = ctools
    dependencies[] = panels
    
  2. Повідомте CTools, де знаходиться ваш плагін:

    <?php
    function MYMODULE_ctools_plugin_directory($module, $plugin) {
      if (($module == 'ctools') && ($plugin == 'content_types')) {
        return 'plugins/content_types';
      }
    }
    ?>
    
  3. Реалізуйте плагін у .incфайл (за замовчуванням як $module.$api.inc). Приклад коду плагіна:

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

Місце розташування плагінів виглядає так:

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

Для отримання додаткових прикладів, будь ласка, перевірте ctools_plugin_exampleмодуль, який є частиною модуля CTools, або замовте сторінку довідки ( приклади плагінів CTools ) в інтерфейсі Drupal після включення модуля.


У Drupal 8 це тепер є частиною ядра (див.: Drupal \ Component \ Plugin ), і він забезпечує спадкування об'єктів, інтерфейси об'єктів та інкапсуляцію одного файлу. Дивіться: Drupal 8 Now: Об'єктно-орієнтовані плагіни в Drupal 7

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.