Goal:
Custom block with dynamic non-entity content that varies with the URL.
Specifically, the block has a form with select
elements, and the selected
items should be determined by the current URL path.
Problem:
The rendered block intermittently displays incorrectly, as though it was rendered for another URL different than the current URL.
Code:
Plugin:
<?php
/**
* @file
* Contains \Drupal\my_module\Plugin\Block\ViewsFiltersResources.
*/
namespace Drupal\my_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a 'ViewsFiltersResources' block.
*
* @Block(
* id = "my_module_views_filters_resources",
* admin_label = @Translation("Resources: filters"),
* )
*/
class ViewsFiltersResources extends BlockBase implements ContainerFactoryPluginInterface {
/**
* Constructs a new ViewsFiltersResources.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param array $plugin_definition
* The plugin implementation definition.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition
);
}
public function getCacheContexts(){
return ['url.path'];
}
/**
* {@inheritdoc}
*/
public function build() {
$request_url = \Drupal::request()->getRequestUri();
$url_parts = explode('/', $request_url);
return array(
'#theme' => 'my_module_block_views_filters_resources',
'#issue_areas' => array(
'all' => 'All Issue Areas',
'area-one' => 'Area One',
'area-two' => 'Area Two',
),
'#resource_types' => array(
'all' => 'All Resource Types',
'news_story' => 'News Stories',
'press_release' => 'Press Releases',
),
'#active_area' => isset($url_parts[2]) ? strtolower($url_parts[2]) : NULL,
'#active_type' => isset($url_parts[3]) ? strtolower($url_parts[3]) : NULL,
'#active_keywords' => isset($url_parts[4]) ? urldecode(str_replace('+', ' ', $url_parts[4])) : NULL,
'#attached' => array(
'library' => array(
'my_module/my_module-resource-filters'
)
),
);
}
}
Theme function:
function my_module_theme() {
return array(
'my_module_block_views_filters_resources' => array(
'variables' => array('issue_areas' => NULL, 'resource_types' => NULL, 'active_area' => NULL, 'active_type' => NULL, 'active_keywords' => NULL),
'template' => 'my-module-block-views-filters-resources',
),
);
}
Template:
<section{{ attributes.addClass('filters resources-filters bg-light-80') }}>
{{ title_prefix }}
{{ title_suffix }}
{% block content %}
<div class="row">
<div class="column">
<form id="resources-filters-form" class="filters-form resources-filters-form clearfix views-exposed-form" method="get" accept-charset="UTF-8">
<fieldset class="filters-fields resources-filters-fields">
<label class="filters-label">Show Me</label>
<div class="filters-issue-area filters-item form-item">
<select class="filters-issue-area-select filters-select form-select" id="edit-area" name="area">
{% for value, name in issue_areas %}
<option value="{{ value }}"{% if value == active_area %} selected="selected"{%endif %}>{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="filters-resource-type filters-item form-item">
<select class="filters-resource-type-select filters-select form-select" id="edit-type" name="type">
{% for value, name in resource_types %}
<option value="{{ value }}"{% if value == active_type %} selected="selected"{%endif %}>{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="filters-keywords filters-item form-item">
<input type="text" class="filters-keywords-text filters-text form-text" id="edit-body-value" name="body_value" value="{{ active_keywords }}" maxlength="128" placeholder="Enter optional keywords...">
</div>
</fieldset>
<div class="filters-actions form-actions" id="edit-actions">
<input type="submit" class="button large filters-submit js-form-submit form-submit" id="edit-submit-resources" name="" value="Update">
</div>
</form>
</div><!-- column -->
</div><!-- row -->
{% endblock %}
</section>
Questions:
- Any thoughts on what could cause incorrect caching here? Could this be related to https://www.drupal.org/node/2529980?
- Is using
getCacheContexts()
supposed to result in the desired behavior? What's the difference between usinggetCacheContexts()
vs using'#cache'
in the render array?
I have searched and read the API docs ongetCacheContexts()
, but it's still not clear to me what exactly it does. - If
getCacheContexts()
is appropriate for this purpose, is it used correctly here?
In core, I've seen cases that look like this one, and other cases that merge a new value into the result ofparent::getCacheContexts()
.