Commit 8bb40fdf authored by Mathieu Lutfy's avatar Mathieu Lutfy Committed by Aegir user

Panelizer module moved to sites/all, otherwise cloning crashes

parent 110860bc
This diff is collapsed.
This diff is collapsed.
Panelizer
---------
The Panelizer module allows supported entities to be treated as Panels [1],
giving options for different default displays on a per bundle basis. For
example, this allows each node display to be customized individually.
Panelizer is a descendent and replacement for the "Panel Nodes" module bundled
with Panels; no upgrade path is available as of yet.
Features
--------------------------------------------------------------------------------
* Supports all of Drupal core's included entities - nodes, taxonomy terms, users
and comments. (More may be available in the future)
* Can be easily extended to support additional entities, e.g. Fieldable Panels
Panes [2] and Bean [3] includes full support.
* Each entity bundle (content type, vocabulary, etc) may have each view mode
configured individually, allowing for each to be tailored separately.
* Each entity bundle may optionally have multiple displays defined; if this
option is enabled, each entity of that type/bundle will have an option to
select which is used.
* Each entity bundle / view mode combination may its default display controlled.
* Full support for content revisions, and provides integration with both
Revisioning and Workbench Moderation.
Requirements
--------------------------------------------------------------------------------
CTools v7.x-1.9 or newer.
Panels v7.x-3.6 or newer.
Configuration & Usage
--------------------------------------------------------------------------------
Visit Structure >> Panelizer to enable the module for the entities you need;
these may also be controlled via the entity bundle's settings page, e.g. for an
"Article" content type it may be enabled at the following page:
admin/structure/types/manage/article
You may need to visit Site Building >> Pages and enable the appropriate pages
for supported entities to use their "Full page override" view mode.
Note that in all cases, modifying Panelizer settings for an entity requires the
corresponding 'update' permission for that entity.
Panelizer operates in four basic modes:
- No Default, No Choice
In this mode, the given bundle is panelized, but there is no default panel
associated or selectable. In this case, each entity has a small form on the
"Customize display" tab that says to 'Panelize it!'. When this button is
clicked, a default panel is attached to the entity and the display may then
be customized.
- With Default, No Choice
In this mode, all entities of the given bundle are given the default panel
automatically. Users with appropriate privileges may then customize the panel
for that node. Once customized, the default is no longer applied and changes
to the default will not propagate downstream.
- No Default, With Choice
In this mode, all entities of this bundle will be given a selector to choose
which panel to display on the entity page. The default choice will be
"No Panel". When a panel has been chosen, users with permission can then
customize that panel. Once this is done, the default choice will no longer be
associated with the panel and a choice can no longer be made. The "Reset"
button on the Panelizer settings tab for that entity can return the entity to
a default state and restore the choice.
- With Default, With Choice
Like above, entities will have a selector to choose which panel to use.
However, unlike above, entities that have never made a selection will
automatically be given the default panel. All configured entities will have
some kind of panel, whether it is one of the choices or a customized panel for
that entity.
Entity View Modes
--------------------------------------------------------------------------------
Panelizer will allow you panelize each view mode individually. One view mode,
the "Full page override" is not actually a view mode - it uses Page Manager to
completely override the output of the page the entity is viewed one. This will
often conflict somewhat with the Default view mode. It is recommended that you
do not panelize both the Default and the Full page override, but instead pick
whichever one you think is most needed. The actually difference between the two
are quite subtle: Placement of the title is different, and the comment form
will not appear in the Default view mode but it will appear in the Full Page
Override.
Permissions
--------------------------------------------------------------------------------
Once Panelizer is enabled for an entity/bundle combination, it may be necessary
to visit People >> Permissions and give users appropriate permissions. All of
the Panelizer tabs have their own permission, and if these are revoked it is
possible to create panelized entities that can only choose panels but not modify
them.
Known Issues / Caveats
--------------------------------------------------------------------------------
Panelizer currently uses the Page Manager to render the panelized entities. At
this time there is no direct support for view modes. This is a desired feature,
though we are somewhat hampered by Drupal only allowing 2 levels of local tasks
(tabs) where configuring for multiple view modes really would prefer a third
level.
Panelizer 7.x-3.x is Revision Aware. This has the downside that duplicating
panels for revisions can generate a lot of extra data. Please keep this in mind
-- it may be necessary to periodically clean up older revisions.
API
--------------------------------------------------------------------------------
Panelizer 7.x-3.x is constructed on an Object Oriented plugin. There is one
plugin per entity type and it MUST be named exactly the same as the entity
type. The easiest way to add Panelizer support for a custom entity is to copy
the node entity.
As a CTools plugin, you will be required to implement
hook_ctools_plugin_directory. Then copy node.inc to your plugin directory as
MY_ENTITY_TYPE.inc and modify the name of the handler it uses. Copy
PanelizerEntityNode.class.php to MyModuleEntityMyEntity.class.php -- and make
sure the name of this file matches the handler in your .inc file.
The required implementation pieces are straightforward. You do need to set a
flag if the entity supports revisions so that Panelizer can write the
information.
If the entity does not support bundles it can only panelize the entire entity.
Troubleshooting / Known Issues
--------------------------------------------------------------------------------
* When using older releases of Pathauto it was possible that saving an entity's
overridden Panelizer display (i.e. nodes, etc) would cause the entity's path
alias to be reset. This was a bug in Pathauto prior to v7.x-1.3 and can be
fixed by updating that module to the latest release.
* Revisions handling using Workbench Moderation and the Panels IPE (In-Place
Editor) is problematic. This problem is being collaborated on in the following
issue:
https://www.drupal.org/node/2457113
Credits / Contact
--------------------------------------------------------------------------------
Currently maintained by Damien McKenna [4]. Originally written by merlinofchaos
[5], with many contributions by dww [6] and awebb [7].
Ongoing development is sponsored by Mediacurrent [8].
The best way to contact the author is to submit an issue, be it a support
request, a feature request or a bug report, in the project issue queue:
https://www.drupal.org/project/issues/panelizer
References
--------------------------------------------------------------------------------
1: https://www.drupal.org/project/panels
2: https://www.drupal.org/project/fieldable_panels_panes
3: https://www.drupal.org/project/bean
4: https://www.drupal.org/u/damienmckenna
5: https://www.drupal.org/u/merlinofchaos
6: https://www.drupal.org/u/dww
7: https://www.drupal.org/u/awebb
8: https://www.mediacurrent.com/
/**
* @file
* Custom CSS for use with Panelizer and IPE.
*/
body.panels-ipe .panels-ipe-form-container .form-item-revision,
body.panels-ipe .panels-ipe-form-container .form-item-log {
margin-bottom: 0;
}
body.panels-ipe .panels-ipe-form-container .form-item-revision label,
body.panels-ipe .panels-ipe-form-container .form-item-log label {
color: white;
}
This diff is collapsed.
This diff is collapsed.
/**
* @file
* This JavaScript provides Vertical Tabs integration with Panelizer so that the
* tab displays a summary of what is enabled.
*/
(function ($) {
'use strict';
Drupal.behaviors.panelizerFieldsetSummary = {
attach: function (context) {
$('fieldset.panelizer-entity-bundle', context).drupalSetSummary(function (context) {
// Identify whether Panelizer is enabled.
if ($('input#panelizer-status:checked', context).length === 0) {
return Drupal.t('Not panelized');
}
// Indicate which view modes are panelized.
var vals = [];
$('input[name*="view modes"][name*=status]:checked', context).each(function () {
vals.push(Drupal.t("@name: enabled", {'@name' : $(this).attr('title')}));
});
// The view modes might not actually be enabled.
if (vals.length === 0) {
return Drupal.t('No view modes enabled');
}
else {
return vals.join('<br/>');
}
});
}
};
})(jQuery);
/**
* @file
* Provides confirm forms for additional IPE buttons that are Panelizer
* specific.
*/
(function ($) {
'use strict';
Drupal.behaviors.PanelizerIPE = {
attach: function (context) {
// Disable the Leave Page dialog warning.
if ($(context).is('form#panels-ipe-edit-control-form.panels-ipe-edit-control-form')) {
window.onbeforeunload = null;
window.onunload = null;
}
// Update the default with this display.
$('input#panelizer-save-default', context).once('save-default-alert', function() {
$(this).bind('mouseup', function (e) {
if (!confirm(Drupal.t("This will save this configuration as the new default for all entities of this type. This action cannot be undone. Are you sure?"))) {
this.ipeCancelThis = true;
return false;
}
});
});
// Redirect to confirmation page.
$('input#panelizer-ipe-revert', context).once('revert-alert', function() {
$(this).bind('mouseup', function (e) {
window.location.href = Drupal.settings.panelizer.revert_default_url;
this.ipeCancelThis = true;
return false;
});
});
}
};
})(jQuery);
/**
* @file
* This javascript provides Vertical Tabs integration with Panelizer so that the
* tab displays the correct value of the field within the tab.
*/
(function ($) {
'use strict';
Drupal.behaviors.panelizerFieldsetSummary = {
attach: function (context) {
$('fieldset.panelizer-entity-options', context).drupalSetSummary(function (context) {
var val = $('select', context).val();
if (val === 0) {
return Drupal.t('Not panelized');
}
return Drupal.t('Use display @name',
{ '@name' : $('option[value="' + $('select', context).val() + '"]', context).html() });
});
}
};
})(jQuery);
<?php
/**
* @file
*
* Documentation for Panelizer's hooks.
*/
/**
* Allow panelizer_defaults_override to be customized.
*
* Primarily for use by Features Overrides.
*/
function hook_panelizer_defaults_override_alter(&$items) {
}
/**
* Add operations to Panelizer objects.
*
* Operations can be performed on panelizer defaults as well as entities.
* Panelizer provides the 4 default operations, but modules can add
* additional operations to add additional functionality.
*
* Data can be stored in $panelizer->extra which is a serialized array.
* Modules should be sure to namespace their keys in this extra to avoid
* collisions.
*
* Each operation supports the following keys:
* - 'menu title': The title to use in menu tab entries. This will be
* translated by the menu system, so do not t() it.
* - 'link title': The title to use in links. This will not be translated by
* the menu system, so t() it. In Drupal, the link title is typically in
* lower case when the tab would be in upper case, so this will not quite
* match the menu title.
* - 'entity callback': If not using the normal operation hook on the object,
* put this may be a function callback. It will receive the following args:
* $handler, $js, $input, $entity, $view_mode.
* - 'admin callback': The callback to use when editing a panelizer default.
* It will receive the following arguments: $handler, $bundle, $name,
* $view_mode.
* - 'file path': A 'file path' entry to be used for hook_menu entries.
* - 'file': A 'file' entry to be used for hook_menu entries.
*/
function hook_panelizer_operations_alter(&$operations) {
$operations['example'] = array(
'menu title' => 'Example',
'link title' => t('example'),
'entity callback' => 'mymodule_panelizer_example_entity_page',
'admin callback' => 'mymodule_panelizer_example_admin_page',
);
}
/**
* Allow panelizer_entity_plugin_process to be customized.
*/
function hook_panelizer_entity_plugin_process_alter(&$plugin, $info) {
}
/**
* Allow the links on the Overview page to be customized.
*/
function hook_panelizer_overview_links_alter(&$links_array, $entity_type, $context) {
}
/**
* Act on default objects just before they're deleted.
*
* @param object $panelizer
* The panelizer default object.
*/
function hook_panelizer_delete_default($panelizer) {
db_delete('example_something')
->condition('name', $panelizer->name)
->execute();
}
/**
* Adjust access to the Panelizer administrative interface beyond the standard
* permissions options.
*
* @param string $op
* The operation currently being performed.
* @param string $entity_type
* The type of entity to which the operation is related.
* @param string|object $bundle
* Either the entity's bundle name or the entity object itself, will vary
* depending upon how it is called.
* @param string $view_mode
* The view mode of the entity related to this operation.
*
* @return bool
* Whether or not the user has permission to perform this $op.
*/
function hook_panelizer_access($op, $entity_type, $bundle, $view_mode) {
}
/**
* Allow modules to alter the defined panelizer access definitions.
*
* @param array $panelizer_access
* An array of panelizer access options. If any are true, this will return
* true. Set $panelizer_access equal to an empty array to return false.
* @param $options
* drupal_alter() can only handle so many parameters. In order to pass the
* same parameters that are passed in hook_panelizer_access, the params are
* placed into an $options array. Expected keys are:
* op
* entity_type
* bundle
* view_mode
*/
function hook_panelizer_access_alter(&$panelizer_access, $options) {
}
name = Panelizer
description = Allow any node type to have custom panel displays, similar to the panel node type.
package = "Panels"
dependencies[] = panels (>= 3.6)
dependencies[] = ctools
dependencies[] = page_manager
core = 7.x
configure = admin/structure/panelizer
; Master class for handling entities.
files[] = plugins/entity/PanelizerEntityDefault.class.php
; SearchAPI integration.
files[] = plugins/search_api/PanelizerSearchApiAlterCallback.class.php
; Views integration.
files[] = plugins/views/panelizer_handler_field_link.inc
files[] = plugins/views/panelizer_handler_panelizer_status.inc
files[] = plugins/views/panelizer_handler_filter_panelizer_status.inc
files[] = plugins/views/panelizer_plugin_row_panelizer_node_view.inc
; Tests: Basic functionality using core.
files[] = tests/panelizer.helper.test
files[] = tests/panelizer.admin_settings.test
; Tests: Standard core entities.
files[] = tests/panelizer.node.test
files[] = tests/panelizer.term.test
files[] = tests/panelizer.user.test
; Tests: Node workflows.
files[] = tests/panelizer.node_revisions.test
; Tests: Standard node translations.
files[] = tests/panelizer.node_content_translation.test
; Tests: Exportables.
files[] = tests/panelizer.exportables.test
; Tests: Panels IPE.
files[] = tests/panelizer.with_panels_ipe.test
; Todo: Tests: Pathauto integration.
test_dependencies[] = pathauto
files[] = tests/panelizer.with_pathauto.test
; Todo: Tests: Revisioning integration.
test_dependencies[] = revisioning
files[] = tests/panelizer.with_revisioning.test
; Todo: Tests: Views integration.
test_dependencies[] = views
files[] = tests/panelizer.with_views.test
; Todo: Tests: Workbench Moderation integration.
test_dependencies[] = workbench_moderation (>= 3.x)
files[] = tests/panelizer.with_workbench_moderation.test
; Information added by Drupal.org packaging script on 2016-08-19
version = "7.x-3.4"
core = "7.x"
project = "panelizer"
datestamp = "1471635552"
This diff is collapsed.
This diff is collapsed.
<?php
$plugin = array(
'title' => t('Panelizer context'),
'cache get' => 'panelizer_context_cache_get',
'cache set' => 'panelizer_context_cache_set',
'cache clear' => 'panelizer_context_cache_clear',
'cache finalize' => 'panelizer_context_cache_set',
);
<?php
/**
* Plugins are described by creating a $plugin array which will be used
* by the system that includes this file.
*/
$plugin = array(
'single' => TRUE,
'icon' => 'icon_panelizer_form.png',
'title' => t('Panelizer form default settings'),
'description' => t('Panelizer default options on the Node form.'),
'required context' => new ctools_context_required(t('Form'), 'node_form'),
'category' => t('Form'),
);
function panelizer_panelizer_form_default_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
$block->module = t('node_form');
$block->title = t('Panelizer defaults');
$block->delta = 'panelizer-default';
if (isset($context->form)) {
if (isset($context->form['panelizer'])) {
$block->content['panelizer'] = $context->form['panelizer'];
unset($block->content['panelizer']['#pre_render']);
unset($block->content['panelizer']['#theme_wrappers']);
$block->content['panelizer']['#type'] = '';
if (isset($block->content['panelizer']['path']['#size'])) {
$block->content['panelizer']['path']['#size'] /= 2;
}
// Set access to false on the original rather than removing so that
// vertical tabs doesn't clone it. I think this is due to references.
$context->form['panelizer']['#access'] = FALSE;
}
}
else {
$block->content = t('Panelizer default options.');
}
return $block;
}
function ctools_panelizer_form_default_content_type_admin_title($subtype, $conf, $context) {
return t('"@s" Panelizer form default options', array('@s' => $context->identifier));
}
function ctools_panelizer_form_default_content_type_edit_form($form, &$form_state) {
// provide a blank form so we have a place to have context setting.
return $form;
}
<?php
/**
* @file
* Class for the Panelizer comment entity plugin.
*/
/**
* Panelizer Entity comment plugin class.
*
* Handles comment specific functionality for Panelizer.
*/
class PanelizerEntityComment extends PanelizerEntityDefault {
public $views_table = 'comment';
public $uses_page_manager = FALSE;
public function entity_access($op, $entity) {
if ($op == 'edit') {
return comment_access($op, $entity);
}
// The view operation is not implemented by core.
if ($op == 'view') {
return TRUE;
}
return FALSE;
}
/**
* Implement the save function for the entity.
*/
public function entity_save($entity) {
comment_save($entity);
}
public function settings_form(&$form, &$form_state) {
parent::settings_form($form, $form_state);
}
public function entity_identifier($entity) {
return t('This comment');
}
public function entity_bundle_label() {
return t('Comment node type');
}
function get_default_display($bundle, $view_mode) {
// For now we just go with the empty display.
// @todo come up with a better default display.
return parent::get_default_display($bundle, $view_mode);
}
/**
* Implements a delegated hook_page_manager_handlers().
*
* This makes sure that all panelized entities have the proper entry
* in page manager for rendering.
*/
public function hook_default_page_manager_handlers(&$handlers) {
$handler = new stdClass;
$handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
$handler->api_version = 1;
$handler->name = 'comment_view_panelizer';
$handler->task = 'comment_view';
$handler->subtask = '';
$handler->handler = 'panelizer_node';
$handler->weight = -100;
$handler->conf = array(
'title' => t('Comment panelizer'),
'context' => 'argument_entity_id:comment_1',
'access' => array(),
);
$handlers['comment_view_panelizer'] = $handler;
return $handlers;
}
}
<?php
/**
* @file
* Class for the Panelizer node entity plugin.
*/
/**
* Panelizer Entity node plugin class.
*
* Handles node specific functionality for Panelizer.
*/
class PanelizerEntityNode extends PanelizerEntityDefault {
public $entity_admin_root = 'admin/structure/types/manage/%panelizer_node_type';
public $entity_admin_bundle = 4;
public $views_table = 'node';
public $uses_page_manager = TRUE;
public $supports_revisions = TRUE;
public function entity_access($op, $entity) {
// This must be implemented by the extending clas.
return node_access($op, $entity);
}
/**
* Implement the save function for the entity.
*/
public function entity_save($entity) {
node_save($entity);
}
public function entity_identifier($entity) {
return t('This node');
}
public function entity_bundle_label() {
return t('Node type');
}
/**
* Determine if the entity allows revisions.
*/
public function entity_allows_revisions($entity) {
$retval = array();
list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
$node_options = variable_get('node_options_' . $bundle, array('status', 'promote'));
// Whether or not the entity supports revisions.
$retval[0] = TRUE;
// Whether or not the user can control if a revision is created.
$retval[1] = user_access('administer nodes');
// Whether or not the revision is created by default.
$retval[2] = in_array('revision', $node_options);
return $retval;
}
/**
* {@inheritdoc}
*/
function get_default_display($bundle, $view_mode) {
$display = parent::get_default_display($bundle, $view_mode);
// Add the node title to the display since we can't get that automatically.
$display->title = '%node:title';
// Add the node links, they probably would like these.
$pane = panels_new_pane('node_links', 'node_links', TRUE);
$pane->css['css_class'] = 'link-wrapper';
$pane->configuration['build_mode'] = $view_mode;
$pane->configuration['context'] = 'panelizer';
// @todo -- submitted by does not exist as a pane! That's v. sad.