contextual_links_example.module 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. <?php
  2. /**
  3. * @file
  4. * Shows how to use Drupal's contextual links functionality.
  5. *
  6. * @see http://drupal.org/node/1089922
  7. */
  8. /**
  9. * @defgroup contextual_links_example Example: Contextual Links
  10. * @ingroup examples
  11. * @{
  12. * Example of implementing contextual links.
  13. */
  14. /**
  15. * Implements hook_menu().
  16. *
  17. * Drupal's menu system allows you to indicate that particular menu items
  18. * should be displayed as contextual links. If you hover over a block or node
  19. * while logged in as an administrator (and with the Contextual Links module
  20. * enabled) you'll see a small gear icon appear. Click on this icon, and the
  21. * list of items that appears in the exposed menu are what Drupal calls
  22. * "contextual links".
  23. *
  24. * Contextual links allow site administrators to quickly perform actions
  25. * related to elements on a page, without having to hunt through the
  26. * administrative interface. As such, you should usually attach them to objects
  27. * that appear on the main part of a Drupal site and limit them to a few common
  28. * tasks that are frequently performed (for example, "edit" or "configure").
  29. * Do not rely on contextual links being present for your module to work
  30. * correctly, since they are a convenience feature only. Within Drupal core,
  31. * the Contextual Links module must be enabled (and the user viewing the page
  32. * must have the "access contextual links" permission) in order for the
  33. * contextual links corresponding to actions that the user can perform to
  34. * actually be injected into the page's HTML.
  35. *
  36. * Three examples of contextual links are provided here. Although none are
  37. * difficult to implement, they are presented in order of increasing
  38. * complexity:
  39. * - Attaching contextual links to a node.
  40. * - Attaching contextual links to a block.
  41. * - Attaching contextual links to an arbitrary piece of content defined by
  42. * your module.
  43. *
  44. * @see contextual_links_example_block_info()
  45. * @see contextual_links_example_block_view()
  46. * @see contextual_links_overview_page()
  47. */
  48. function contextual_links_example_menu() {
  49. // First example (attaching contextual links to a node):
  50. //
  51. // Many modules add tabs to nodes underneath the node/<nid> path. If the path
  52. // you are adding corresponds to a commonly performed action on the node, you
  53. // can choose to expose it as a contextual link. Since the Node module
  54. // already has code to display all contextual links underneath the node/<nid>
  55. // path (such as "Edit" and "Delete") when a node is being rendered outside
  56. // of its own page (for example, when a teaser of the node is being displayed
  57. // on the front page of the site), you only need to inform Drupal's menu
  58. // system that your path is a contextual link also, and it will automatically
  59. // appear with the others. In the example below, we add a contextual link
  60. // named "Example action" to the list.
  61. $items['node/%node/example-action'] = array(
  62. 'title' => 'Example action',
  63. 'page callback' => 'drupal_get_form',
  64. 'page arguments' => array('contextual_links_example_node_action_form', 1),
  65. 'access callback' => TRUE,
  66. // To be displayed as a contextual link, a menu item should be defined as
  67. // one of the node's local tasks.
  68. 'type' => MENU_LOCAL_TASK,
  69. // To make the local task display as a contextual link, specify the
  70. // optional 'context' argument. The most common method is to set both
  71. // MENU_CONTEXT_PAGE and MENU_CONTEXT_INLINE (shown below), which causes
  72. // the link to display as both a tab on the node page and as an entry in
  73. // the contextual links dropdown. This is recommended for most cases
  74. // because not all users who have permission to visit the "Example action"
  75. // page will necessarily have access to contextual links, and they still
  76. // need a way to get to the page via the user interface.
  77. 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  78. // If we give the item a large weight, we can make it display as the last
  79. // tab on the page, as well as the last item inside the contextual links
  80. // dropdown.
  81. 'weight' => 80,
  82. );
  83. // Second example (attaching contextual links to a block):
  84. //
  85. // If your module provides content that is displayed in a block, you can
  86. // attach contextual links to the block that allow actions to be performed on
  87. // it. This is useful for administrative pages that affect the content
  88. // wherever it is displayed or used on the site. For configuration options
  89. // that only affect the appearance of the content in the block itself, it is
  90. // better to implement hook_block_configure() rather than creating a separate
  91. // administrative page (this allows your options to appear when an
  92. // administrator clicks the existing "Configure block" contextual link
  93. // already provided by the Block module).
  94. //
  95. // In the code below, we assume that your module has a type of object
  96. // ("contextual links example object") that will be displayed in a block. The
  97. // code below defines menu items for this object using a standard pattern,
  98. // with "View" and "Edit object" as the object's local tasks, and makes the
  99. // "Edit object" item display as a contextual link in addition to a tab. Once
  100. // the contextual links are defined here, additional steps are required to
  101. // actually display the content in a block and attach the contextual links to
  102. // the block itself. This occurs in contextual_links_example_block_info() and
  103. // contextual_links_example_block_view().
  104. $items['examples/contextual-links/%contextual_links_example_object'] = array(
  105. 'title' => 'Contextual links example object',
  106. 'page callback' => 'contextual_links_example_object_page',
  107. 'page arguments' => array(2),
  108. 'access callback' => TRUE,
  109. );
  110. $items['examples/contextual-links/%contextual_links_example_object/view'] = array(
  111. 'title' => 'View',
  112. 'type' => MENU_DEFAULT_LOCAL_TASK,
  113. 'weight' => -10,
  114. );
  115. $items['examples/contextual-links/%contextual_links_example_object/edit'] = array(
  116. 'title' => 'Edit object',
  117. 'page callback' => 'drupal_get_form',
  118. 'page arguments' => array('contextual_links_example_object_edit_form', 2),
  119. 'access callback' => TRUE,
  120. 'type' => MENU_LOCAL_TASK,
  121. // As in our first example, this is the line of code that makes "Edit
  122. // "object" display as a contextual link in addition to as a tab.
  123. 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  124. );
  125. // Third example (attaching contextual links directly to your module's
  126. // content):
  127. //
  128. // Sometimes your module may want to display its content in an arbitrary
  129. // location and attach contextual links there. For example, you might
  130. // display your content in a listing on its own page and then attach the
  131. // contextual links directly to each piece of content in the listing. Here,
  132. // we will reuse the menu items and contextual links that were defined for
  133. // our example object above, and display them in a listing in
  134. // contextual_links_overview_page().
  135. $items['examples/contextual-links'] = array(
  136. 'title' => 'Contextual Links Example',
  137. 'page callback' => 'contextual_links_overview_page',
  138. 'access callback' => TRUE,
  139. );
  140. return $items;
  141. }
  142. /**
  143. * Menu loader callback for the object defined by this module.
  144. *
  145. * @param int $id
  146. * The ID of the object to load.
  147. *
  148. * @return object|FALSE
  149. * A fully loaded object, or FALSE if the object does not exist.
  150. */
  151. function contextual_links_example_object_load($id) {
  152. // In a real use case, this function might load an object from the database.
  153. // For the sake of this example, we just define a stub object with a basic
  154. // title and content for any numeric ID that is passed in.
  155. if (is_numeric($id)) {
  156. $object = new stdClass();
  157. $object->id = $id;
  158. $object->title = t('Title for example object @id', array('@id' => $id));
  159. $object->content = t('This is the content of example object @id.', array('@id' => $id));
  160. return $object;
  161. }
  162. else {
  163. return FALSE;
  164. }
  165. }
  166. /**
  167. * Implements hook_block_info().
  168. */
  169. function contextual_links_example_block_info() {
  170. // Define the block that will display our module's content.
  171. $blocks['example']['info'] = t('Contextual links example block');
  172. return $blocks;
  173. }
  174. /**
  175. * Implements hook_block_view().
  176. */
  177. function contextual_links_example_block_view($delta = '') {
  178. if ($delta == 'example') {
  179. // Display our module's content inside a block. In a real use case, we
  180. // might define a new block for each object that exists. For the sake of
  181. // this example, though, we only define one block and hardcode it to always
  182. // display object #1.
  183. $id = 1;
  184. $object = contextual_links_example_object_load($id);
  185. $block['subject'] = t('Contextual links example block for object @id', array('@id' => $id));
  186. $block['content'] = array(
  187. // In order to attach contextual links, the block's content must be a
  188. // renderable array. (Normally this would involve themed output using
  189. // #theme, but for simplicity we just use HTML markup directly here.)
  190. '#type' => 'markup',
  191. '#markup' => filter_xss($object->content),
  192. // Contextual links are attached to the block array using the special
  193. // #contextual_links property. The #contextual_links property contains an
  194. // array, keyed by the name of each module that is attaching contextual
  195. // links to it.
  196. '#contextual_links' => array(
  197. 'contextual_links_example' => array(
  198. // Each element is itself an array, containing two elements which are
  199. // combined together to form the base path whose contextual links
  200. // should be attached. The two elements are split such that the first
  201. // is the static part of the path and the second is the dynamic part.
  202. // (This split is for performance reasons.) For example, the code
  203. // below tells Drupal to load the menu item corresponding to the path
  204. // "examples/contextual-links/$id" and attach all this item's
  205. // contextual links (which were defined in hook_menu()) to the object
  206. // when it is rendered. If the contextual links you are attaching
  207. // don't have any dynamic elements in their path, you can pass an
  208. // empty array as the second element.
  209. 'examples/contextual-links',
  210. array($id),
  211. ),
  212. ),
  213. );
  214. // Since we are attaching our contextual links to a block, and the Block
  215. // module takes care of rendering the block in such a way that contextual
  216. // links are supported, we do not need to do anything else here. When the
  217. // appropriate conditions are met, the contextual links we have defined
  218. // will automatically appear attached to the block, next to the "Configure
  219. // block" link that the Block module itself provides.
  220. return $block;
  221. }
  222. }
  223. /**
  224. * Menu callback; displays a listing of objects defined by this module.
  225. *
  226. * @see contextual_links_example_theme()
  227. * @see contextual-links-example-object.tpl.php
  228. * @see contextual_links_example_block_view()
  229. */
  230. function contextual_links_overview_page() {
  231. $build = array();
  232. // For simplicity, we will hardcode this example page to list five of our
  233. // module's objects.
  234. for ($id = 1; $id <= 5; $id++) {
  235. $object = contextual_links_example_object_load($id);
  236. $build[$id] = array(
  237. // To support attaching contextual links to an object that we are
  238. // displaying on our own, the object must be themed in a particular way.
  239. // See contextual_links_example_theme() and
  240. // contextual-links-example-object.tpl.php for more discussion.
  241. '#theme' => 'contextual_links_example_object',
  242. '#object' => $object,
  243. // Contextual links are attached to the block using the special
  244. // #contextual_links property. See contextual_links_example_block_view()
  245. // for discussion of the syntax used here.
  246. '#contextual_links' => array(
  247. 'contextual_links_example' => array(
  248. 'examples/contextual-links',
  249. array($id),
  250. ),
  251. ),
  252. );
  253. }
  254. return $build;
  255. }
  256. /**
  257. * Implements hook_theme().
  258. *
  259. * @see template_preprocess_contextual_links_example_object()
  260. */
  261. function contextual_links_example_theme() {
  262. // The core Contextual Links module imposes two restrictions on how an object
  263. // must be themed in order for it to display the object's contextual links in
  264. // the user interface:
  265. // - The object must use a template file rather than a theme function. See
  266. // contextual-links-example-object.tpl.php for more information on how the
  267. // template file should be structured.
  268. // - The first variable passed to the template must be a renderable array. In
  269. // this case, we accomplish that via the most common method, by passing a
  270. // single renderable element.
  271. return array(
  272. 'contextual_links_example_object' => array(
  273. 'template' => 'contextual-links-example-object',
  274. 'render element' => 'element',
  275. ),
  276. );
  277. }
  278. /**
  279. * Process variables for contextual-links-example-object.tpl.php.
  280. *
  281. * @see contextual_links_overview_page()
  282. */
  283. function template_preprocess_contextual_links_example_object(&$variables) {
  284. // Here we take the object that is being themed and define some useful
  285. // variables that we will print in the template file.
  286. $variables['title'] = filter_xss($variables['element']['#object']->title);
  287. $variables['content'] = filter_xss($variables['element']['#object']->content);
  288. }
  289. /**
  290. * Menu callback; displays an object defined by this module on its own page.
  291. *
  292. * @see contextual_links_overview_page()
  293. */
  294. function contextual_links_example_object_page($object) {
  295. // Here we render the object but without the #contextual_links property,
  296. // since we don't want contextual links to appear when the object is already
  297. // being displayed on its own page.
  298. $build = array(
  299. '#theme' => 'contextual_links_example_object',
  300. '#object' => $object,
  301. );
  302. return $build;
  303. }
  304. /**
  305. * Form callback; display the form for editing our module's content.
  306. *
  307. * @ingroup forms
  308. * @see contextual_links_example_object_edit_form_submit()
  309. */
  310. function contextual_links_example_object_edit_form($form, &$form_state, $object) {
  311. $form['text'] = array(
  312. '#markup' => t('This is the page that would allow you to edit object @id.', array('@id' => $object->id)),
  313. '#prefix' => '<p>',
  314. '#suffix' => '</p>',
  315. );
  316. $form['object_id'] = array(
  317. '#type' => 'value',
  318. '#value' => $object->id,
  319. );
  320. $form['actions'] = array('#type' => 'actions');
  321. $form['actions']['submit'] = array(
  322. '#type' => 'submit',
  323. '#value' => t('Submit'),
  324. );
  325. return $form;
  326. }
  327. /**
  328. * Submit handler for contextual_links_example_object_edit_form().
  329. */
  330. function contextual_links_example_object_edit_form_submit($form, &$form_state) {
  331. drupal_set_message(t('Object @id was edited.', array('@id' => $form_state['values']['object_id'])));
  332. }
  333. /**
  334. * Form callback; display the form for performing an example action on a node.
  335. *
  336. * @ingroup forms
  337. * @see contextual_links_example_node_action_form_submit()
  338. */
  339. function contextual_links_example_node_action_form($form, &$form_state, $node) {
  340. $form['text'] = array(
  341. '#markup' => t('This is the page that would allow you to perform an example action on node @nid.', array('@nid' => $node->nid)),
  342. '#prefix' => '<p>',
  343. '#suffix' => '</p>',
  344. );
  345. $form['nid'] = array(
  346. '#type' => 'value',
  347. '#value' => $node->nid,
  348. );
  349. $form['actions'] = array('#type' => 'actions');
  350. $form['actions']['submit'] = array(
  351. '#type' => 'submit',
  352. '#value' => t('Submit'),
  353. );
  354. return $form;
  355. }
  356. /**
  357. * Submit handler for contextual_links_example_node_action_form().
  358. */
  359. function contextual_links_example_node_action_form_submit($form, &$form_state) {
  360. drupal_set_message(t('The example action was performed on node @nid.', array('@nid' => $form_state['values']['nid'])));
  361. }
  362. /**
  363. * @} End of "defgroup contextual_links_example".
  364. */