|
|
|
@@ -0,0 +1,388 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @file
|
|
|
|
|
* Shows how to use Drupal's contextual links functionality.
|
|
|
|
|
*
|
|
|
|
|
* @see http://drupal.org/node/1089922
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @defgroup contextual_links_example Example: Contextual Links
|
|
|
|
|
* @ingroup examples
|
|
|
|
|
* @{
|
|
|
|
|
* Example of implementing contextual links.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Implements hook_menu().
|
|
|
|
|
*
|
|
|
|
|
* Drupal's menu system allows you to indicate that particular menu items
|
|
|
|
|
* should be displayed as contextual links. If you hover over a block or node
|
|
|
|
|
* while logged in as an administrator (and with the Contextual Links module
|
|
|
|
|
* enabled) you'll see a small gear icon appear. Click on this icon, and the
|
|
|
|
|
* list of items that appears in the exposed menu are what Drupal calls
|
|
|
|
|
* "contextual links".
|
|
|
|
|
*
|
|
|
|
|
* Contextual links allow site administrators to quickly perform actions
|
|
|
|
|
* related to elements on a page, without having to hunt through the
|
|
|
|
|
* administrative interface. As such, you should usually attach them to objects
|
|
|
|
|
* that appear on the main part of a Drupal site and limit them to a few common
|
|
|
|
|
* tasks that are frequently performed (for example, "edit" or "configure").
|
|
|
|
|
* Do not rely on contextual links being present for your module to work
|
|
|
|
|
* correctly, since they are a convenience feature only. Within Drupal core,
|
|
|
|
|
* the Contextual Links module must be enabled (and the user viewing the page
|
|
|
|
|
* must have the "access contextual links" permission) in order for the
|
|
|
|
|
* contextual links corresponding to actions that the user can perform to
|
|
|
|
|
* actually be injected into the page's HTML.
|
|
|
|
|
*
|
|
|
|
|
* Three examples of contextual links are provided here. Although none are
|
|
|
|
|
* difficult to implement, they are presented in order of increasing
|
|
|
|
|
* complexity:
|
|
|
|
|
* - Attaching contextual links to a node.
|
|
|
|
|
* - Attaching contextual links to a block.
|
|
|
|
|
* - Attaching contextual links to an arbitrary piece of content defined by
|
|
|
|
|
* your module.
|
|
|
|
|
*
|
|
|
|
|
* @see contextual_links_example_block_info()
|
|
|
|
|
* @see contextual_links_example_block_view()
|
|
|
|
|
* @see contextual_links_overview_page()
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_menu() {
|
|
|
|
|
// First example (attaching contextual links to a node):
|
|
|
|
|
//
|
|
|
|
|
// Many modules add tabs to nodes underneath the node/<nid> path. If the path
|
|
|
|
|
// you are adding corresponds to a commonly performed action on the node, you
|
|
|
|
|
// can choose to expose it as a contextual link. Since the Node module
|
|
|
|
|
// already has code to display all contextual links underneath the node/<nid>
|
|
|
|
|
// path (such as "Edit" and "Delete") when a node is being rendered outside
|
|
|
|
|
// of its own page (for example, when a teaser of the node is being displayed
|
|
|
|
|
// on the front page of the site), you only need to inform Drupal's menu
|
|
|
|
|
// system that your path is a contextual link also, and it will automatically
|
|
|
|
|
// appear with the others. In the example below, we add a contextual link
|
|
|
|
|
// named "Example action" to the list.
|
|
|
|
|
$items['node/%node/example-action'] = array(
|
|
|
|
|
'title' => 'Example action',
|
|
|
|
|
'page callback' => 'drupal_get_form',
|
|
|
|
|
'page arguments' => array('contextual_links_example_node_action_form', 1),
|
|
|
|
|
'access callback' => TRUE,
|
|
|
|
|
// To be displayed as a contextual link, a menu item should be defined as
|
|
|
|
|
// one of the node's local tasks.
|
|
|
|
|
'type' => MENU_LOCAL_TASK,
|
|
|
|
|
// To make the local task display as a contextual link, specify the
|
|
|
|
|
// optional 'context' argument. The most common method is to set both
|
|
|
|
|
// MENU_CONTEXT_PAGE and MENU_CONTEXT_INLINE (shown below), which causes
|
|
|
|
|
// the link to display as both a tab on the node page and as an entry in
|
|
|
|
|
// the contextual links dropdown. This is recommended for most cases
|
|
|
|
|
// because not all users who have permission to visit the "Example action"
|
|
|
|
|
// page will necessarily have access to contextual links, and they still
|
|
|
|
|
// need a way to get to the page via the user interface.
|
|
|
|
|
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
|
|
|
|
// If we give the item a large weight, we can make it display as the last
|
|
|
|
|
// tab on the page, as well as the last item inside the contextual links
|
|
|
|
|
// dropdown.
|
|
|
|
|
'weight' => 80,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Second example (attaching contextual links to a block):
|
|
|
|
|
//
|
|
|
|
|
// If your module provides content that is displayed in a block, you can
|
|
|
|
|
// attach contextual links to the block that allow actions to be performed on
|
|
|
|
|
// it. This is useful for administrative pages that affect the content
|
|
|
|
|
// wherever it is displayed or used on the site. For configuration options
|
|
|
|
|
// that only affect the appearance of the content in the block itself, it is
|
|
|
|
|
// better to implement hook_block_configure() rather than creating a separate
|
|
|
|
|
// administrative page (this allows your options to appear when an
|
|
|
|
|
// administrator clicks the existing "Configure block" contextual link
|
|
|
|
|
// already provided by the Block module).
|
|
|
|
|
//
|
|
|
|
|
// In the code below, we assume that your module has a type of object
|
|
|
|
|
// ("contextual links example object") that will be displayed in a block. The
|
|
|
|
|
// code below defines menu items for this object using a standard pattern,
|
|
|
|
|
// with "View" and "Edit object" as the object's local tasks, and makes the
|
|
|
|
|
// "Edit object" item display as a contextual link in addition to a tab. Once
|
|
|
|
|
// the contextual links are defined here, additional steps are required to
|
|
|
|
|
// actually display the content in a block and attach the contextual links to
|
|
|
|
|
// the block itself. This occurs in contextual_links_example_block_info() and
|
|
|
|
|
// contextual_links_example_block_view().
|
|
|
|
|
$items['examples/contextual-links/%contextual_links_example_object'] = array(
|
|
|
|
|
'title' => 'Contextual links example object',
|
|
|
|
|
'page callback' => 'contextual_links_example_object_page',
|
|
|
|
|
'page arguments' => array(2),
|
|
|
|
|
'access callback' => TRUE,
|
|
|
|
|
);
|
|
|
|
|
$items['examples/contextual-links/%contextual_links_example_object/view'] = array(
|
|
|
|
|
'title' => 'View',
|
|
|
|
|
'type' => MENU_DEFAULT_LOCAL_TASK,
|
|
|
|
|
'weight' => -10,
|
|
|
|
|
);
|
|
|
|
|
$items['examples/contextual-links/%contextual_links_example_object/edit'] = array(
|
|
|
|
|
'title' => 'Edit object',
|
|
|
|
|
'page callback' => 'drupal_get_form',
|
|
|
|
|
'page arguments' => array('contextual_links_example_object_edit_form', 2),
|
|
|
|
|
'access callback' => TRUE,
|
|
|
|
|
'type' => MENU_LOCAL_TASK,
|
|
|
|
|
// As in our first example, this is the line of code that makes "Edit
|
|
|
|
|
// "object" display as a contextual link in addition to as a tab.
|
|
|
|
|
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Third example (attaching contextual links directly to your module's
|
|
|
|
|
// content):
|
|
|
|
|
//
|
|
|
|
|
// Sometimes your module may want to display its content in an arbitrary
|
|
|
|
|
// location and attach contextual links there. For example, you might
|
|
|
|
|
// display your content in a listing on its own page and then attach the
|
|
|
|
|
// contextual links directly to each piece of content in the listing. Here,
|
|
|
|
|
// we will reuse the menu items and contextual links that were defined for
|
|
|
|
|
// our example object above, and display them in a listing in
|
|
|
|
|
// contextual_links_overview_page().
|
|
|
|
|
$items['examples/contextual-links'] = array(
|
|
|
|
|
'title' => 'Contextual Links Example',
|
|
|
|
|
'page callback' => 'contextual_links_overview_page',
|
|
|
|
|
'access callback' => TRUE,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Menu loader callback for the object defined by this module.
|
|
|
|
|
*
|
|
|
|
|
* @param int $id
|
|
|
|
|
* The ID of the object to load.
|
|
|
|
|
*
|
|
|
|
|
* @return object|FALSE
|
|
|
|
|
* A fully loaded object, or FALSE if the object does not exist.
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_object_load($id) {
|
|
|
|
|
// In a real use case, this function might load an object from the database.
|
|
|
|
|
// For the sake of this example, we just define a stub object with a basic
|
|
|
|
|
// title and content for any numeric ID that is passed in.
|
|
|
|
|
if (is_numeric($id)) {
|
|
|
|
|
$object = new stdClass();
|
|
|
|
|
$object->id = $id;
|
|
|
|
|
$object->title = t('Title for example object @id', array('@id' => $id));
|
|
|
|
|
$object->content = t('This is the content of example object @id.', array('@id' => $id));
|
|
|
|
|
return $object;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Implements hook_block_info().
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_block_info() {
|
|
|
|
|
// Define the block that will display our module's content.
|
|
|
|
|
$blocks['example']['info'] = t('Contextual links example block');
|
|
|
|
|
return $blocks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Implements hook_block_view().
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_block_view($delta = '') {
|
|
|
|
|
if ($delta == 'example') {
|
|
|
|
|
// Display our module's content inside a block. In a real use case, we
|
|
|
|
|
// might define a new block for each object that exists. For the sake of
|
|
|
|
|
// this example, though, we only define one block and hardcode it to always
|
|
|
|
|
// display object #1.
|
|
|
|
|
$id = 1;
|
|
|
|
|
$object = contextual_links_example_object_load($id);
|
|
|
|
|
$block['subject'] = t('Contextual links example block for object @id', array('@id' => $id));
|
|
|
|
|
$block['content'] = array(
|
|
|
|
|
// In order to attach contextual links, the block's content must be a
|
|
|
|
|
// renderable array. (Normally this would involve themed output using
|
|
|
|
|
// #theme, but for simplicity we just use HTML markup directly here.)
|
|
|
|
|
'#type' => 'markup',
|
|
|
|
|
'#markup' => filter_xss($object->content),
|
|
|
|
|
// Contextual links are attached to the block array using the special
|
|
|
|
|
// #contextual_links property. The #contextual_links property contains an
|
|
|
|
|
// array, keyed by the name of each module that is attaching contextual
|
|
|
|
|
// links to it.
|
|
|
|
|
'#contextual_links' => array(
|
|
|
|
|
'contextual_links_example' => array(
|
|
|
|
|
// Each element is itself an array, containing two elements which are
|
|
|
|
|
// combined together to form the base path whose contextual links
|
|
|
|
|
// should be attached. The two elements are split such that the first
|
|
|
|
|
// is the static part of the path and the second is the dynamic part.
|
|
|
|
|
// (This split is for performance reasons.) For example, the code
|
|
|
|
|
// below tells Drupal to load the menu item corresponding to the path
|
|
|
|
|
// "examples/contextual-links/$id" and attach all this item's
|
|
|
|
|
// contextual links (which were defined in hook_menu()) to the object
|
|
|
|
|
// when it is rendered. If the contextual links you are attaching
|
|
|
|
|
// don't have any dynamic elements in their path, you can pass an
|
|
|
|
|
// empty array as the second element.
|
|
|
|
|
'examples/contextual-links',
|
|
|
|
|
array($id),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
// Since we are attaching our contextual links to a block, and the Block
|
|
|
|
|
// module takes care of rendering the block in such a way that contextual
|
|
|
|
|
// links are supported, we do not need to do anything else here. When the
|
|
|
|
|
// appropriate conditions are met, the contextual links we have defined
|
|
|
|
|
// will automatically appear attached to the block, next to the "Configure
|
|
|
|
|
// block" link that the Block module itself provides.
|
|
|
|
|
return $block;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Menu callback; displays a listing of objects defined by this module.
|
|
|
|
|
*
|
|
|
|
|
* @see contextual_links_example_theme()
|
|
|
|
|
* @see contextual-links-example-object.tpl.php
|
|
|
|
|
* @see contextual_links_example_block_view()
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_overview_page() {
|
|
|
|
|
$build = array();
|
|
|
|
|
|
|
|
|
|
// For simplicity, we will hardcode this example page to list five of our
|
|
|
|
|
// module's objects.
|
|
|
|
|
for ($id = 1; $id <= 5; $id++) {
|
|
|
|
|
$object = contextual_links_example_object_load($id);
|
|
|
|
|
$build[$id] = array(
|
|
|
|
|
// To support attaching contextual links to an object that we are
|
|
|
|
|
// displaying on our own, the object must be themed in a particular way.
|
|
|
|
|
// See contextual_links_example_theme() and
|
|
|
|
|
// contextual-links-example-object.tpl.php for more discussion.
|
|
|
|
|
'#theme' => 'contextual_links_example_object',
|
|
|
|
|
'#object' => $object,
|
|
|
|
|
// Contextual links are attached to the block using the special
|
|
|
|
|
// #contextual_links property. See contextual_links_example_block_view()
|
|
|
|
|
// for discussion of the syntax used here.
|
|
|
|
|
'#contextual_links' => array(
|
|
|
|
|
'contextual_links_example' => array(
|
|
|
|
|
'examples/contextual-links',
|
|
|
|
|
array($id),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $build;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Implements hook_theme().
|
|
|
|
|
*
|
|
|
|
|
* @see template_preprocess_contextual_links_example_object()
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_theme() {
|
|
|
|
|
// The core Contextual Links module imposes two restrictions on how an object
|
|
|
|
|
// must be themed in order for it to display the object's contextual links in
|
|
|
|
|
// the user interface:
|
|
|
|
|
// - The object must use a template file rather than a theme function. See
|
|
|
|
|
// contextual-links-example-object.tpl.php for more information on how the
|
|
|
|
|
// template file should be structured.
|
|
|
|
|
// - The first variable passed to the template must be a renderable array. In
|
|
|
|
|
// this case, we accomplish that via the most common method, by passing a
|
|
|
|
|
// single renderable element.
|
|
|
|
|
return array(
|
|
|
|
|
'contextual_links_example_object' => array(
|
|
|
|
|
'template' => 'contextual-links-example-object',
|
|
|
|
|
'render element' => 'element',
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Process variables for contextual-links-example-object.tpl.php.
|
|
|
|
|
*
|
|
|
|
|
* @see contextual_links_overview_page()
|
|
|
|
|
*/
|
|
|
|
|
function template_preprocess_contextual_links_example_object(&$variables) {
|
|
|
|
|
// Here we take the object that is being themed and define some useful
|
|
|
|
|
// variables that we will print in the template file.
|
|
|
|
|
$variables['title'] = filter_xss($variables['element']['#object']->title);
|
|
|
|
|
$variables['content'] = filter_xss($variables['element']['#object']->content);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Menu callback; displays an object defined by this module on its own page.
|
|
|
|
|
*
|
|
|
|
|
* @see contextual_links_overview_page()
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_object_page($object) {
|
|
|
|
|
// Here we render the object but without the #contextual_links property,
|
|
|
|
|
// since we don't want contextual links to appear when the object is already
|
|
|
|
|
// being displayed on its own page.
|
|
|
|
|
$build = array(
|
|
|
|
|
'#theme' => 'contextual_links_example_object',
|
|
|
|
|
'#object' => $object,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $build;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Form callback; display the form for editing our module's content.
|
|
|
|
|
*
|
|
|
|
|
* @ingroup forms
|
|
|
|
|
* @see contextual_links_example_object_edit_form_submit()
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_object_edit_form($form, &$form_state, $object) {
|
|
|
|
|
$form['text'] = array(
|
|
|
|
|
'#markup' => t('This is the page that would allow you to edit object @id.', array('@id' => $object->id)),
|
|
|
|
|
'#prefix' => '<p>',
|
|
|
|
|
'#suffix' => '</p>',
|
|
|
|
|
);
|
|
|
|
|
$form['object_id'] = array(
|
|
|
|
|
'#type' => 'value',
|
|
|
|
|
'#value' => $object->id,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$form['actions'] = array('#type' => 'actions');
|
|
|
|
|
$form['actions']['submit'] = array(
|
|
|
|
|
'#type' => 'submit',
|
|
|
|
|
'#value' => t('Submit'),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $form;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Submit handler for contextual_links_example_object_edit_form().
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_object_edit_form_submit($form, &$form_state) {
|
|
|
|
|
drupal_set_message(t('Object @id was edited.', array('@id' => $form_state['values']['object_id'])));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Form callback; display the form for performing an example action on a node.
|
|
|
|
|
*
|
|
|
|
|
* @ingroup forms
|
|
|
|
|
* @see contextual_links_example_node_action_form_submit()
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_node_action_form($form, &$form_state, $node) {
|
|
|
|
|
$form['text'] = array(
|
|
|
|
|
'#markup' => t('This is the page that would allow you to perform an example action on node @nid.', array('@nid' => $node->nid)),
|
|
|
|
|
'#prefix' => '<p>',
|
|
|
|
|
'#suffix' => '</p>',
|
|
|
|
|
);
|
|
|
|
|
$form['nid'] = array(
|
|
|
|
|
'#type' => 'value',
|
|
|
|
|
'#value' => $node->nid,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$form['actions'] = array('#type' => 'actions');
|
|
|
|
|
$form['actions']['submit'] = array(
|
|
|
|
|
'#type' => 'submit',
|
|
|
|
|
'#value' => t('Submit'),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $form;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Submit handler for contextual_links_example_node_action_form().
|
|
|
|
|
*/
|
|
|
|
|
function contextual_links_example_node_action_form_submit($form, &$form_state) {
|
|
|
|
|
drupal_set_message(t('The example action was performed on node @nid.', array('@nid' => $form_state['values']['nid'])));
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @} End of "defgroup contextual_links_example".
|
|
|
|
|
*/
|