ปลั๊กอิน Ctools คืออะไร (ประเภทเนื้อหาการเข้าถึงและอื่น ๆ ) และจะสร้างได้อย่างไร?


คำตอบ:


84

ทุกครั้งที่ทำงานกับCtools Page managerและPanelsจะมีประโยชน์ในการเพิ่มปลั๊กอิน Ctools ที่กำหนดเอง

ปลั๊กอินของ Ctools มีหลายรูปแบบและโมดูลอื่น ๆ เช่นFeeds , AddressfieldและOpenlayersทั้งหมดใช้ประโยชน์จาก Ctools เพื่อให้ปลั๊กอินที่ขยายได้โดยโมดูลอื่น ๆ แม้ว่ารูปแบบส่วนใหญ่ของปลั๊กอินอาจเป็น "ประเภทเนื้อหา" และ "เข้าถึง" ก่อนอื่นต้องไม่สับสนกับเอนทิตี "เนื้อหา" และบันเดิลหรือที่เรียกว่าประเภทเนื้อหา

ครั้งแรกที่ boilerplate :

สำหรับโมดูลใด ๆ ที่จะให้ปลั๊กอิน ctools พวกเขาควรบอก Ctools ก่อนว่าจะมองหาพวกมันได้ที่ไหน เบ็ดด้านล่างกล่าวว่าเราให้บริการปลั๊กอินสำหรับ ctools ประเภท "content_types" และ "การเข้าถึง" ฟังก์ชั่นนี้สามารถทำให้ง่ายขึ้นได้ แต่วิธีนี้เรามั่นใจได้ว่ามีเพียงโมดูลที่เหมาะสมเท่านั้นที่จะได้รับการบอกกล่าวเกี่ยวกับปลั๊กอินรวมถึงให้มันสแกนดิสก์เพื่อหาไฟล์เมื่อเราระบุประเภทของปลั๊กอินที่ต้องการ

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 ซึ่งเป็นจุดเริ่มต้นที่ฉันเลือกสิ่งต่าง ๆ ฉันพยายามที่จะรับงานเขียนเอกสารอย่างเป็นทางการด้วยตัวเองมากกว่าหนึ่งครั้ง แต่ก็หมดแรงเสมอ
Letharion

ฉันมีปัญหาหนึ่งเมื่อฉันทำตามบทช่วยสอนนี้และนั่นคือรูปแบบการกำหนดค่าไม่เพียง แต่ว่างเปล่า แต่ยังขาดปุ่ม

ฉันพลาดคำถาม / คำตอบในรอบแรกอย่างน่ากลัวเขียนขึ้น!
ไคลฟ์

2
@beth ปัญหาคือ $ form ใน module_content_type_edit_form () ไม่ควรผ่านการอ้างอิง
Justin

1

ปลั๊กอิน CTools เป็นไฟล์ขนาดเล็กซึ่งสามารถเป็นส่วนหนึ่งของโมดูลใด ๆ ก็ได้เพื่อเพิ่มความสามารถในการทำงาน สามารถใช้เป็นส่วนประกอบ (บานหน้าต่าง) เพิ่มตัวเลือกสไตล์เพิ่มเติมให้กับพาเนลของคุณ ฯลฯ

โปรดตรวจสอบหน้าCTools Plugins โดยไม่ต้องติดตั้งแผงสำหรับขั้นตอนเอกสาร ดังนั้นสั้น ๆ มันจะเป็นเช่น:

  1. คุณต้องเพิ่มการอ้างอิง CTools ลงใน.infoไฟล์ของคุณเป็น:

    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 UI หลังจากเปิดใช้งานโมดูล


ใน Drupal 8 ตอนนี้เป็นส่วนหนึ่งของคอร์ (ดู: Drupal \ Component \ Plugin ) และให้การสืบทอดวัตถุ, อินเตอร์เฟสวัตถุและการห่อหุ้มไฟล์เดี่ยว ดูที่: Drupal 8 ตอนนี้: ปลั๊กอินที่เน้นวัตถุใน Drupal 7

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.