Apa itu plugin Ctools (tipe konten, akses, dll), dan bagaimana cara membuatnya?

56

Apa itu plugin Ctools, dan bagaimana cara membuatnya?

Pelajaran
sumber

Jawaban:

84

Sesekali ketika bekerja dengan manajer Halaman Ctools , dan Panel , akan berguna untuk menambahkan plugin Ctools khusus.

Plugin Ctools hadir dalam banyak bentuk, dan modul lain, seperti Feed , Addressfield dan Openlayers semuanya menggunakan Ctools untuk menyediakan plugin yang dapat dikembangkan oleh modul lain. Bentuk plugin yang paling umum, mungkin "tipe konten", dan "akses". Yang pertama tidak harus bingung dengan entitas "konten" dan bundelnya, juga disebut tipe konten.

Pertama, pelat ketel :

Untuk setiap modul yang menyediakan plugin ctools, mereka harus terlebih dahulu memberi tahu Ctools di mana mencarinya. Kait di bawah ini, mengatakan bahwa kami menyediakan plugin untuk ctools, dari tipe "content_types", dan "akses". Fungsi ini dapat dibuat lebih sederhana, tetapi dengan cara ini kami memastikan bahwa hanya modul yang tepat yang diberi tahu tentang plugin, dan hanya meminta pemindaian disk untuk file ketika kami benar-benar menyediakan jenis plugin yang diminta.

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 bawah ini adalah contoh struktur direktori untuk modul yang menyediakan dua plugin. Satu tipe konten dan satu plugin akses.

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 jenis konten

Jenis konten dalam kosa kata Ctools, lebih sering dikenal sebagai "Pane", seperti yang disediakan oleh misalnya Views. Dalam pertanyaan ini: Apakah ada cara untuk mencegat daftar NID yang dibuat oleh tampilan dan menggunakannya sebagai filter untuk tampilan lain? , penulis bertanya tentang argumen pemrograman makan untuk tampilan. Sementara itu di dalamnya sendiri tidak terlalu sulit, pertanyaan tindak lanjut dengan cepat menjadi, "Bagaimana cara menampilkan hasilnya?".

Satu jawaban, adalah membuat "tipe konten" baru.

Sekarang, plugin jenis konten yang sebenarnya, lagi menggunakan pertanyaan Views dari atas, bisa terlihat seperti ini:

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

Dengan modul ini diaktifkan, sekarang harus ada kategori baru di Panel, 'Kategori kustom saya', di mana dalam satu harus menemukan panel tunggal, rendering kode dari atas.

Akses plugin

Plugin akses di bawah ini akan memberikan kemampuan untuk menghapus varian dan / atau panel berdasarkan kedalaman istilah yang diukur dari akar kosa kata.

<?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
sumber
Ini luar biasa! Tetapi apakah ada dokumentasi "resmi" untuk ini? (google menemukan banyak posting blog tetapi tidak ada yang "resmi" ..)
donquixote
1
Ada banyak contoh dalam modul ctools itu sendiri, yang terutama di mana saya mengambil semuanya. Saya sudah mencoba mengambil tugas menulis dokumen resmi sendiri lebih dari satu kali, tetapi selalu kehabisan tenaga.
Letharion
Saya punya satu masalah ketika saya mengikuti tutorial ini, dan itu adalah bahwa bentuk konfigurasi tidak hanya kosong, tetapi tidak memiliki tombol.
beth
Saya entah bagaimana melewatkan pertanyaan / jawaban ini pertama kali, menulis yang luar biasa!
Clive
2
@beth Masalahnya adalah $ form di module_content_type_edit_form () tidak boleh diteruskan dengan referensi.
Justin
1

Plugin CTools adalah file kecil yang dapat menjadi bagian dari modul apa pun sebagai cara untuk memperluas fungsinya. Mereka dapat digunakan untuk menyediakan komponen (panel), menambahkan opsi gaya tambahan ke panel Anda, dll.

Silakan periksa halaman CTools Plugins without Panel untuk dokumentasi langkah demi langkah. Jadi singkatnya seperti:

  1. Anda perlu menambahkan dependensi CTools ke .infofile Anda sebagai:

    dependencies[] = ctools
    dependencies[] = panels
    
  2. Beri tahu CTools tempat plugin Anda berada:

    <?php
    function MYMODULE_ctools_plugin_directory($module, $plugin) {
      if (($module == 'ctools') && ($plugin == 'content_types')) {
        return 'plugins/content_types';
      }
    }
    ?>
    
  3. Terapkan plugin dalam .incfile (secara default sebagai $module.$api.inc). Contoh kode 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;
    }
    ?>
    

Lokasi default plugin terlihat seperti:

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

Untuk contoh lebih lanjut, silakan periksa ctools_plugin_examplemodul yang merupakan bagian dari modul CTools, atau checkout halaman Bantuan ( Contoh Plugin CTools ) di Drupal UI setelah mengaktifkan modul.


Dalam Drupal 8, ini sekarang bagian dari inti (lihat: Drupal \ Component \ Plugin ) dan menyediakan warisan objek, antarmuka objek dan enkapsulasi file tunggal. Lihat: Drupal 8 Sekarang: Plugin Berorientasi Objek di Drupal 7

kenorb
sumber