In Drupal 8, how do I add contextual edit links in a block template?
This is for block entities created at /block/add, not block plugins created by a class in a custom module.
I want an edit link to display on the front end. I want an edit link for the block, not for the block content type (bundle). For example, a link to /block/123.
I believe it's supposed to be output by
{{ title_prefix }}
But I don't see the links showing up and I'm not sure where to turn them on.
I was able to get them to render with this code, but then realized this only works for block plugins, not block entities:
function exampletheme_preprocess_block(&$variables) {
if (!empty($variables['elements']['#contextual_links'])) {
$variables['elements'] = ContextualLinks::preRenderLinks($variables['elements']);
$variables['links'] = array(
'#prefix' => '<div class="contextual-links-wrapper">',
'#suffix' => '</div>',
'#theme' => 'links__contextual',
'#links' => $variables['elements']['#links'],
'#attributes' => array('class' => array('contextual-links')),
'#attached' => array(
'library' => array(
'contextual/drupal.contextual-links',
),
),
'#weight' => -10,
);
$variables['attributes']['class'][] = 'contextual-links-region';
}
}
This added some links to edit the content type (although I never got them to render).
Finally, I just rolled my own:
$entity_view = $render_controller->view($block);
$entity_wrapper = [
'#type' => 'container',
'#attributes' => [
'id' => ['block-' . $block->id()],
'class' => ['example-container-class'],
],
];
$entity_wrapper['content'] = [];
$edit_link = $block->toLink()->toRenderable();
$edit_link['#title'] = t('Edit');
$edit_link['#attributes'] = [
'class' => ['edit-link'],
];
$entity_wrapper['content'][] = $edit_link;
$entity_wrapper['content'][] = $entity_view;
$build[] = $entity_wrapper;
After that, I dug around a little and found a way to render the built-in contextual links for block_content entities. You have to do a little legwork while building up your render array:
use Drupal\contextual\Element\ContextualLinks;
First load up your block_content entity:
In this case, I'm only expecting one of this bundle or type:
$blocks = \Drupal::entityManager()->getStorage('block_content')->loadByProperties(['type' => 'footer_middle']);
if (!empty($blocks)) {
$block = array_shift($blocks);
}
Now we render the entity using the entity manager:
$render_controller = \Drupal::entityManager()->getViewBuilder('block_content');
$footer_middle = $render_controller->view($block);
The really tricky part is that block_content entities don't have a theme function or template, so you have to add the contextual links to a parent item, such as a container:
$build['footer_middle'] = [
'#type' => 'container',
'#attributes' => [
'id' => 'footer-middle',
'class' => ['footer-container'],
],
];
$build['footer_middle']['#contextual_links'] = $footer_middle['#contextual_links'];
Now we need to generate the links:
$footer_middle = ContextualLinks::preRenderLinks($footer_middle);
Then set up the render array on the parent container, passing in the rendered links:
$build['footer_middle']['links'] = array(
'#prefix' => '<div class="contextual-links-wrapper">',
'#suffix' => '</div>',
'#theme' => 'links__contextual',
'#links' => $footer_middle['#links'],
'#attributes' => array('class' => array('contextual-links')),
'#attached' => array(
'library' => array(
'contextual/drupal.contextual-links',
),
),
'#weight' => -10,
);
And now add the rendered entity as a child of the container:
$build['footer_middle'][] = $footer_middle;
And now you have contextual links for your block_content entity!
Just make sure your container.html.twig is outputting
{{ title_suffix }}
Since that's where the contextual drupal module puts it.