Problem/Motivation
The 'url' cache context for views block displays is sometimes missing when it shouldn't be because \Drupal\views\Plugin\views\display\DisplayPluginBase::buildRenderable() only bubbles the context cachablity metadata when it has been asked to create a render cache for the output.
This can lead to problems where empty view blocks get cached.
Steps to reproduce
This started out as a long adventure into why empty view blocks get cached, so here are some steps to reproduce:
Setup
(note that I exported and attached my test site's configuration in #2— this could save you time)
- Install Drupal 8.0.x using the minimal install profile.
- Enable
field_ui
,views
,views_ui
modules. - Go to
/admin/structure/types/add
, add a newcontent type:- Name =
Test
- Publishing options:
- Promoted to front page =
FALSE
- Promoted to front page =
- (leave the rest of the fields at their default value)
- Name =
- Go to
admin/structure/types/manage/test/display
and disable the body field (i.e.: set it's Format =- Hidden -
). - Go to
/node/add/test
, add a first new piece of content:- Title =
First test
- Body =
Lorem ipsum
- (leave the rest of the fields at their default value)
- Title =
- Go to
/node/add/test
, add a second new piece of content:- Title =
Second test
- Body =
Dolor sit
- (leave the rest of the fields at their default value)
- Title =
- Go to
/admin/structure/views/add
, add a new view:- View basic information:
- View name = "Tests"
- (leave the rest of the fields at their defaultvalue)
- View settings:
- Show
Content
of typeTest
sorted byUnsorted
- Show
- Page settings
- (leave the rest of the fields at their default value)
- Block settings
- Create a block =
TRUE
- Block title =
Tests
- Block display settings:
- Display format:
Unformatted list
ofFields
- Display format:
- Create a block =
- (leave the rest of the fields at their default value)
- Click
Save and edit
- Under Fields, remove the default
Content: Title
field, and add aContent: Body
field (the default settings are fine). - Under Advanced, add a Contextual Filter. Select
Node ID
, and clickApply (all displays)
:- When the filter value is NOT available:
- Default actions:
Provide default value
:- Type =
Content ID from URL
- Type =
- Default actions:
- (leave the rest of the fields at their default value)
- When the filter value is NOT available:
- Save the view.
- View basic information:
- Go to
admin/structure/block
- In Footer, click
Place block
. Find theTests
block from the categoryLists (Views)
, and clickPlace block
. Save using the default settings. - Click
Save blocks
- In Footer, click
Test 1
- Clear all caches:
drush -y cr
- Go to
/node
. - Go to
/node/1
.- Expcected behaviour: A block is displayed in the footer with the contents of the body field ("Lorem ipsum").
- Actual behaviour: No block is displayed.
- Go to
/node/2
.- Expcected behaviour: A block is displayed in the footer with the contents of the body field ("Dolor sit").
- Actual behaviour: No block is displayed.
Test 2
- Clear all caches:
drush -y cr
- Go to
/node/1
. Note the block is displayed in the footer with the contents of the body field ("Lorem ipsum"). - Go to
/node/2
. Note the block is displayed in the footer with the contents of the body field ("Dolor sit").
Test 3
- In
settings[.local].php
, disable the render cache by adding the following lines:$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml'; $settings['cache']['bins']['render'] = 'cache.backend.null';
- Clear all caches:
drush -y cr
- Go to
/node
. - Go to
/node/1
. Note the block is displayed in the footer with the contents of the body field ("Lorem ipsum"). - Go to
/node/2
. Note the block is displayed in the footer with the contents of the body field ("Dolor sit").
Test 4
- Remove the lines from
settings[.local].php
you added in step 3, if applicable. Re-run Test 1 to confirm the bug occurs. - Apply the following patch:
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlock.php b/core/modules/views/src/Plugin/Block/ViewsBlock.php
index 20dbace..530d9e3 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlock.php
@@ -127,4 +127,15 @@ public function getMachineNameSuggestion() {
return 'views_block__' . $this->view->storage->id() . '_' . $this->view->current_display;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheContexts() {
+ $contexts = parent::getCacheContexts();
+
+ $contexts[] = 'url';
+
+ return $contexts;
+ }
+
} - Clear all caches:
drush -y cr
- Go to
/node
. - Go to
/node/1
. Note the block is displayed in the footer with the contents of the body field ("Lorem ipsum"). - Go to
/node/2
. Note the block is displayed in the footer with the contents of the body field ("Dolor sit"). Figure out what's causing empty blocks to be cached.Write a patch- Review and feedback
- RTBC.
- Commit.
Proposed resolution
Always pass the cachablity metadata; but if we're not supposed to cache the view's output, remove the cache tags, leaving the rest of the metadata to bubble.
Remaining tasks
User interface changes
None.
API changes
None.
Data model changes
None.