Pane Field: World domination with ctools panes inside your content
If you're building flexible content with something like Paragraphs and build your sites from an editors perspective, you will really like this one.
Pane Field brings the ease of ctools panes to Entity Fields. With this modules you can use ctools panes inside your content!
Pane Field is a new Drupal module by VDMi.
Most of the time we will give our users 3 Paragraphs types:
- Text (just a simple WYSIWYG and a title field)
- Text with image (simple WYSIWYG, title field, image field (media/scald/image), image position)
- Image (media/scald/image)
Over time we learned that when content editors discover such flexible content, they immediately start thinking about exceptions. You’ll probably get some questions about “special” content like animations, videos and call-to-actions. That's where Pane Field comes in!
While most of these exceptions can be implemented in Paragraphs, it’ll become a problem when you have 10 different animations, or 10 different call to actions and the list keeps growing. That’s why we thought of another way to keep the ease of content editing, but have the flexibility of ctools panes. Which gives you - the developer - an very easy way to quickly create new pieces of content that the editor can use.
Ctools panes (also known as content types) are simple ctools plugins that basically define what they are, how they are configured and how they should be rendered. A definition is placed inside the same file that takes care of configuration/rendering. The definition will look something like this:
<?php/** * Plugins are described by creating a $plugin array which will be used * by the system that includes this file. */$plugin = array( 'title' => t('Buy our product'), 'description' => t('Buy our product and get another one for free call to action.'), 'category' => t('Call to Actions'), 'edit form' => 'shop_cta_buy_our_product_edit_form', 'render callback' => 'shop_cta_buy_our_product_render', 'admin info' => 'shop_cta_buy_our_product_admin_info', 'required context' => new ctools_context_required(t('Node'), 'node'), 'defaults' => array( 'title' => 'Improve your daily workflow with our turboblender', 'subtitle' => 'Buy now and get one free!', 'button' => 'Buy now!', 'button_link' => 'order', ));
The callbacks will look like this for a simple pane, they are in the same file as the definition:
/** * 'Edit form' callback for the content type. */function shop_cta_buy_our_product_edit_form($form, &$form_state) { $conf = $form_state['conf']; $form['title'] = array( '#title' => t('Title'), '#type' => 'textfield', '#default_value' => $conf['title'], ); $form['subtitle'] = array( '#title' => t('Subtitle'), '#type' => 'textfield', '#default_value' => $conf['subtitle'], '#maxlength' => 2048, ); $form['button'] = array( '#title' => t('Button'), '#type' => 'textfield', '#default_value' => $conf['button'], ); $form['button_link'] = array( '#title' => t('Button Link'), '#type' => 'textfield', '#default_value' => $conf['button_link'], ); return $form;}function shop_cta_buy_our_product_admin_info($subtype, $conf, $context) { $output = new stdClass(); $output->title = ''; $output->content = '<strong>'. t('Title') . ':</strong> ' . check_plain($conf['title']) . '</br>'; $output->content .= '<strong>'. t('Subtitle') . ':</strong> ' . check_plain($conf['subtitle']) . '</br>'; $output->content .= '<strong>'. t('Button') . ':</strong> ' . check_plain($conf['button']) . '</br>'; $output->content .= '<strong>'. t('Button Link') . ':</strong> ' . check_plain($conf['button_link']) . '</br>'; return $output;}function shop_cta_buy_our_product_render($subtype, $conf, $panel_args, $context) { $node = $context->data; $block = new stdClass(); $block->title = ''; $content = array( '#theme' => 'shop_cta_buy_our_product', '#path' => drupal_get_path('module', 'shop_cta'), '#title' => $conf['title'], '#subtitle' => $conf['subtitle'], '#button' => $conf['button'], '#button_link' => $conf['button_link'], ); $block->content = $content; return $block;}
And there you go, you created a new piece of custom content for your website. In the theme function you can use a template that has some custom HTML. Now you can enable the pane in the instance settings of the pane field:
As you can see, your new pane is available, all default ctools panes are also available.
When you edit content, you can now add a new Paragraph, select the paragraph type with the pane field and then select the new ctools pane:
You’re probably wondering “WHY?” at this moment
Pane Field causes extreme flexibility in your content without the hassle of creating a new paragraphs type, adding fields to them, adding preprocess functions, creating a bundle template. It allowes you to create exceptions to your base types much faster. It also is faster (in CPU time) compared to using a new Paragraphs type because it’s not a new entity, it’s just a field value with a reference to the ctools pane and some configuration values.One big note: because the pane configuration is simply stored serialized in the field value, you can’t use them in stuff like Views or Search API (you can render the field and index that though).
Here is a more comprehensive article about how to write content panes.