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/ // 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' => '

', '#suffix' => '

', ); $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' => '

', '#suffix' => '

', ); $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". */