diff --git contextual_links_example/contextual-links-example-object.tpl.php contextual_links_example/contextual-links-example-object.tpl.php
new file mode 100644
index 0000000..60afc81
--- /dev/null
+++ contextual_links_example/contextual-links-example-object.tpl.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Default theme implementation to display a sample object with contextual links.
+ *
+ * Available variables:
+ * - $title: The sanitized title of the object.
+ * - $content: The sanitized content of the object.
+ * These are defined in template_preprocess_contextual_links_example_object()
+ * and represent whichever variables you might actually use to display the
+ * main content of your module's object.
+ *
+ * Standard variables (required for contextual links):
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS.
+ * - $title_prefix (array): An array containing additional output populated by
+ *   modules, intended to be displayed in front of the main title tag that
+ *   appears in the template.
+ * - $title_suffix (array): An array containing additional output populated by
+ *   modules, intended to be displayed after the main title tag that appears in
+ *   the template.
+ * The above variables are a subset of those which Drupal provides to all
+ * templates, and they must be printed in your template file in order for
+ * contextual links to be properly attached. For example, the core Contextual
+ * Links module adds the renderable contextual links themselves inside
+ * $title_suffix, so they will appear immediately after the object's title in
+ * the HTML. (This placement is for accessibility reasons, among others.)
+ */
+?>
+<div class="<?php print $classes; ?>">
+  <?php print render($title_prefix); ?>
+  <h2><?php print $title; ?></h2>
+  <?php print render($title_suffix); ?>
+  <?php print $content; ?>
+</div>
diff --git contextual_links_example/contextual_links_example.info contextual_links_example/contextual_links_example.info
new file mode 100644
index 0000000..7319108
--- /dev/null
+++ contextual_links_example/contextual_links_example.info
@@ -0,0 +1,5 @@
+name = Contextual links example
+description = Demonstrates how to use contextual links for enhancing the user experience.
+package = Example modules
+core = 7.x
+files[] = contextual_links_example.test
diff --git contextual_links_example/contextual_links_example.module contextual_links_example/contextual_links_example.module
new file mode 100644
index 0000000..bd22ba8
--- /dev/null
+++ contextual_links_example/contextual_links_example.module
@@ -0,0 +1,376 @@
+<?php
+
+/**
+ * @file
+ * Shows how to use Drupal's contextual links functionality.
+ */
+
+/**
+ * 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-overview-page'] = array(
+    'title' => 'Contextual links example overview',
+    'page callback' => 'contextual_links_overview_page',
+    'access callback' => TRUE,
+  );
+
+  return $items;
+}
+
+/**
+ * Menu loader callback for the object defined by this module.
+ *
+ * @param $id
+ *   The ID of the object to load.
+ *
+ * @return
+ *   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'])));
+}
diff --git contextual_links_example/contextual_links_example.test contextual_links_example/contextual_links_example.test
new file mode 100644
index 0000000..ffa9c10
--- /dev/null
+++ contextual_links_example/contextual_links_example.test
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Tests for the contextual links example module.
+ */
+class ContextualLinksExampleTestCase extends DrupalWebTestCase {
+  protected $web_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Contextual links example functionality',
+      'description' => 'Tests the behavior of the contextual links provided by the Contextual links example module.',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Enable modules and create user with specific permissions.
+   */
+  public function setUp() {
+    parent::setUp('contextual', 'contextual_links_example');
+    $this->web_user = $this->drupalCreateUser(array('access contextual links', 'administer blocks'));
+    $this->drupalLogin($this->web_user);
+  }
+
+  /**
+   * Test the various contextual links that this module defines and displays.
+   */
+  function testContextualLinksExample() {
+    // Create a node and promote it to the front page. Then view the front page
+    // and verify that the "Example action" contextual link works.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
+    $this->drupalGet('');
+    $this->clickLink(t('Example action'));
+    $this->assertUrl('node/' . $node->nid . '/example-action', array('query' => array('destination' => 'node')));
+
+    // Visit our example overview page and click the third contextual link.
+    // This should take us to a page for editing the third object we defined.
+    $this->drupalGet('examples/contextual-links-overview-page');
+    $this->clickLink('Edit object', 2);
+    $this->assertUrl('examples/contextual-links/3/edit', array('query' => array('destination' => 'examples/contextual-links-overview-page')));
+
+    // Enable our module's block, go back to the front page, and click the
+    // "Edit object" contextual link that we expect to be there.
+    $edit['blocks[contextual_links_example_example][region]'] = 'sidebar_first';
+    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+    $this->drupalGet('');
+    $this->clickLink('Edit object');
+    $this->assertUrl('examples/contextual-links/1/edit', array('query' => array('destination' => 'node')));
+  }
+}
diff --git examples.index.php examples.index.php
index beab81a..bf00d67 100644
--- examples.index.php
+++ examples.index.php
@@ -8,6 +8,7 @@
  * - @link ajax_example.module Using AJAX forms @endlink
  * - @link batch_example.module Using the batch API @endlink
  * - @link block_example.module Defining blocks @endlink
+ * - @link contextual_links_example.module Defining contextual links @endlink
  * - @link dbtng_example.module Database examples (DBTNG) @endlink
  * - @link email_example.module Sending e-mail @endlink
  * - @link field_example.module Defining fields in the field API @endlink
@@ -28,4 +29,4 @@
  * - @link trigger_example.module Implementing triggers and actions @endlink
  * - @link vertical_tabs_example.module Using vertical tabs @endlink
  * - @link xmlrpc_example.module XML-RPC example @endlink
- */
\ No newline at end of file
+ */
