I have tested the functionality of table grouping and found this bug (or missing feature ?)

Create a view
Format: table
Add some fields
Check "Exclude from Display" for one field (i.e. Field1)
View Format / Table Settings: Group by => Field1

In D7/Views 7.3.x the hidden field is used as table caption (unfortunately with no css class)

In D8/Views there is no table caption !!

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because the missing caption is a regression
Prioritized changes The main goal of this issue is fixing a normal bug.
Disruption None
CommentFileSizeAuthor
#62 After patch.png31.61 KBgreggmarshall
#62 Before patch.png20.83 KBgreggmarshall
#60 missing_caption_if-2302319-60.patch3.64 KBLendude
#57 missing_caption_if-2302319-57.patch3.64 KBLendude
#57 interdiff-2302319-54-57.txt756 bytesLendude
#54 missing_caption_if-2302319-54.patch3.63 KBLendude
#54 interdiff-2302319-48-54.txt2.08 KBLendude
#48 missing_caption_if-2302319-48.patch4.65 KBgeertvd
#48 missing_caption_if-2302319-48-test.patch3.01 KBgeertvd
#48 interdiff-2302319-44-48.txt2.28 KBgeertvd
#44 missing_caption_if-2302319-44.patch3.87 KBgeertvd
#44 interdiff-2302319-40-44.txt1.69 KBgeertvd
#40 missing_caption_if-2302319-40-complete.patch3.47 KBgeertvd
#40 missing_caption_if-2302319-40-test.patch2.34 KBgeertvd
#40 interdiff-2302319-36-40.txt2.18 KBgeertvd
#36 2302319-36-complete.patch3.1 KBgeertvd
#36 2302319-36-test.patch2.2 KBgeertvd
#36 interdiff-2302319-32-36.txt1.29 KBgeertvd
#32 2302319-32-complete.patch3.37 KBgeertvd
#32 2302319-32-test.patch2.46 KBgeertvd
#32 interdiff-2302319-29-32.txt1.29 KBgeertvd
#29 interdiff-2302319-17-29.txt2.99 KBgeertvd
#29 2302319-29-complete.patch3.45 KBgeertvd
#29 2302319-29-test.patch2.55 KBgeertvd
#17 2302319-17-complete.patch2.52 KBgeertvd
#17 interdiff.txt1.21 KBgeertvd
#14 views_d8_grouping_errors.JPG82.84 KBMicha1111
#11 2302319-11-complete.patch2.25 KBgeertvd
#11 2302319-11-test.patch1.62 KBgeertvd
#11 interdiff.txt1.22 KBgeertvd
#8 2302319-8-complete.patch2.24 KBgeertvd
#8 2302319-8-test.patch1.62 KBgeertvd
#7 2302319-d8.png27.72 KBAnonymous (not verified)
#6 2302319-d7.png23.65 KBAnonymous (not verified)
#4 2302319-4.patch644 bytesgeertvd
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Micha1111’s picture

Same problem with D8-beta

Anonymous’s picture

Version: 8.0-alpha13 » 8.0.x-dev

I can reproduce this on 8.0.x and I also verified on a D7 install that this is a regression.

dawehner’s picture

Issue tags: -#views +VDC, +Needs tests

.

geertvd’s picture

Status: Active » Needs review
FileSize
644 bytes

Something like this adds the caption.

geertvd’s picture

Status: Needs review » Needs work

Still needs test coverage though.

Anonymous’s picture

Issue summary: View changes
FileSize
23.65 KB

Re #4: I tried the grouping in D7 with the created field iso the title field, which resulted in:

It seems to me your patch doesn't handle that use case?

Anonymous’s picture

FileSize
27.72 KB

Correction to #6 after manually retesting this issue. The use case is handled by the patch:

geertvd’s picture

Status: Needs work » Needs review
FileSize
1.62 KB
2.24 KB

Added test.

The last submitted patch, 8: 2302319-8-test.patch, failed testing.

Lendude’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests +Needs beta evaluation

Fix and test looks go to me. Bit of nitpicking:

  1. +++ b/core/modules/views/src/Tests/Plugin/StyleTableTest.php
    @@ -109,4 +109,36 @@ public function testFieldInColumns() {
    +    // Clear the caption text, the rendered job field will be used a caption.
    

    'will be used as a' (missing as)

  2. +++ b/core/modules/views/src/Tests/Plugin/StyleTableTest.php
    @@ -109,4 +109,36 @@ public function testFieldInColumns() {
    +    // Ensure tht all expected captions are found.
    

    tht => that

Also needs a beta evaluation added.

geertvd’s picture

Status: Needs work » Needs review
FileSize
1.22 KB
1.62 KB
2.25 KB

Fixed nitpicks

The last submitted patch, 11: 2302319-11-test.patch, failed testing.

Anonymous’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs beta evaluation

Added a beta eval.

Tested manually and looks good to me.

Micha1111’s picture

FileSize
82.84 KB

New test with D8-beta10 after clean installation:

My view has two grouped fields, both are entity_reference fields. They are excluded from display.

First grouped field "Veranstaltung" is now used for table caption, but not right displayed as link to its content.

Second grouped field "Turnier" is not used for table caption (second level)

Have a look at attached screenshot.

alexpott’s picture

Assigned: Unassigned » dawehner
Status: Reviewed & tested by the community » Needs review
+++ b/core/modules/views/src/Tests/Plugin/StyleTableTest.php
@@ -109,4 +109,36 @@ public function testFieldInColumns() {
+    $display['display_options']['style']['options']['caption'] = '';
+    $display['display_options']['style']['options']['summary'] = '';
+    $display['display_options']['style']['options']['description'] = '';

How does the views ui let you know that you're still going to get a caption?

Assigning to @dawehner to get an opinion.

dawehner’s picture

First I tried to understand how this actually works in Drupal 7:

This is the table template code we talk about.

   <?php if (!empty($title) || !empty($caption)) : ?>
     <caption><?php print $caption . $title; ?></caption>
  <?php endif; ?>

So even if $caption is empty, it $title is set, we use it. This is set, when we group by a specific field, see http://cgit.drupalcode.org/views/tree/plugins/views_plugin_style.inc#n344

Alright, let's have a look at the situation in Drupal 8.

The grouping code itself looks still pretty much the same, see http://cgit.drupalcode.org/drupal/tree/core/modules/views/src/Plugin/vie...
I'm curious as it seems to be that the fix is not the right thing to do. The template still prints out the {{ title }} in case {{ caption_needed }},
but we simply set it up wrong. This is some code from HEAD:

  // Add the caption to the list if set.
  if (!empty($handler->options['caption'])) {
    $variables['caption'] = Xss::filterAdmin($handler->options['caption']);
    $variables['caption_needed'] = TRUE;
  }
  else {
    $variables['caption'] = '';
    $variables['caption_needed'] = FALSE;
  }

  $variables['caption_needed'] |= !empty($variables['summary']) || !empty($variables['description']);

so all we need is $variables['caption_needed'] = !empty($variables['summary']) || !empty($variables['description']) || !empty($variables['title']);.

So let's clarify things a bit. The option in the UI is for manual hand-crafted captions, which might be useful for additional accessibility on the site. In case you
group the view, the title is coming directly from the grouping. As additional accessibility features we support to add a summary and a description, but we don't take
into account {{ caption }} or {{ title }} so I guess #843708: Add option to set caption & remove summary in the html table (Accessibility) was simply not entirely correct.

  1. +++ b/core/modules/views/views.theme.inc
    @@ -651,6 +651,10 @@ function template_preprocess_views_view_table(&$variables) {
    +    $variables['title'] = Xss::filterAdmin($variables['title']);
    

    Do we really need the escaping here? Don't we autoescape now? In case we have to, why can't we do that in the template itself? Is there something like Xss::filterAdmin() in twig?

  2. +++ b/core/modules/views/views.theme.inc
    @@ -651,6 +651,10 @@ function template_preprocess_views_view_table(&$variables) {
    +    $variables['caption_needed'] = TRUE;
    

    So yeah as written above I think we better encapsulate this into the line coming below.

geertvd’s picture

FileSize
1.21 KB
2.52 KB
  1. It seems to be already escaped, we do need to set it as SafeMarkup though.
  2. Done
geertvd’s picture

We could also use the raw filter in the template, not sure what's best.

Status: Needs review » Needs work

The last submitted patch, 17: 2302319-17-complete.patch, failed testing.

Status: Needs work » Needs review

geertvd queued 17: 2302319-17-complete.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 17: 2302319-17-complete.patch, failed testing.

Status: Needs work » Needs review

geertvd queued 17: 2302319-17-complete.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 17: 2302319-17-complete.patch, failed testing.

geertvd’s picture

No clue why the testbot keeps failing on this one. Seems unrelated to the patch.

Status: Needs work » Needs review

geertvd queued 17: 2302319-17-complete.patch for re-testing.

pjbaert’s picture

Status: Needs review » Reviewed & tested by the community

It seems like all feedback from #16 is processed.
It looks like this is RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/views.theme.inc
@@ -656,9 +656,13 @@ function template_preprocess_views_view_table(&$variables) {
+  if (!empty($variables['title'])) {
+    $variables['title'] = SafeMarkup::set($variables['title']);
+  }

We shouldn't be using SafeMarkup::set(). Why are we?

Anonymous’s picture

We shouldn't be using SafeMarkup::set(). Why are we?

If you choose to group by title, then the title is by default a link which is html. Without marking it safe, it is not rendered properly. Judging from the CR on SafeMarkup::set() here, I'd say we can use SafeMarkup::format() instead. I tested this manually, and it works. We will need to update the test coverage to cover such a use case.

geertvd’s picture

Assigned: dawehner » Unassigned
Status: Needs work » Needs review
FileSize
2.55 KB
3.45 KB
2.99 KB

Changed SafeMarkup::set() to SafeMarkup::format() and added some extra test coverage.

The last submitted patch, 29: 2302319-29-test.patch, failed testing.

Anonymous’s picture

Status: Needs review » Needs work

I tested this manually and it looks good overall. One remark though:

+++ b/core/modules/views/src/Tests/Plugin/StyleTableTest.php
@@ -109,4 +111,57 @@ public function testFieldInColumns() {
+      $filtered_caption = Xss::filterAdmin($raw_caption);

This filters away the script tags. I think we should explicitly check for them.

geertvd’s picture

Yup, missed that.
I changed Xss::filterAdmin() for SafeMarkup::escape()
I also changed the xpath select for a assertRaw because I had trouble finding the escaped markup with the xpath selector.

The last submitted patch, 32: 2302319-32-test.patch, failed testing.

Anonymous’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me. I think it's ready now.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/views.theme.inc
@@ -658,9 +658,13 @@ function template_preprocess_views_view_table(&$variables) {
+  if (!empty($variables['title'])) {
+    $variables['title'] = SafeMarkup::format($variables['title']);
+  }

This is wrong what is this trying to do?

+++ b/core/modules/views/src/Tests/Plugin/StyleTableTest.php
@@ -109,4 +111,56 @@ public function testFieldInColumns() {
+      $filtered_caption = SafeMarkup::escape($raw_caption);
+      $this->assertRaw($filtered_caption, 'Found caption containing "' . $filtered_caption . '"');

$this->assertEscaped() instead I think.

geertvd’s picture

  1. Just trying to avoid double escaping, changed this to a #markup array now
  2. $this->assertEscaped() fixes that nicely indeed

The last submitted patch, 36: 2302319-36-test.patch, failed testing.

geertvd’s picture

bump

Aki Tendo’s picture

Status: Needs review » Needs work

Overall looks good, but there's this in the test.

+  public function testGrouping() {
+    $view = \Drupal::entityManager()->getStorage('view')->load('test_table');
+    $display = &$view->getDisplay('default');
+    // Set job as the grouping field.

The test goes on to modify display and use the passage by reference to modify the view object without using the normal setters. This is unusual, and I'd discourage such in production code but sometimes tests have to do things in an unorthodox manner. Some commentary as to why a pass by reference here is being used instead of using the setters would be good I think.

Note: If $display is an ArrayObject then the pass by reference is redundant - objects are always passed by reference in PHP.

geertvd’s picture

Had to reroll this.

+++ b/core/modules/views/views.theme.inc
@@ -658,9 +658,13 @@ function template_preprocess_views_view_table(&$variables) {
+    $variables['title'] = ['#markup' => $variables['title']];

This was also not working anymore due to the recent SafeMarkup changes I guess. I changed it to use ViewsRenderPipelineSafeString.

The test goes on to modify display and use the passage by reference to modify the view object without using the normal setters.

getDisplay() doesn't return an object there, it returns an array reference to the display configuration (so I need the &).
Including /** @var \Drupal\views\ViewEntityInterface $view */ already explains this better I think but I also added an extra comment to be clear on this matter.

The last submitted patch, 40: missing_caption_if-2302319-40-test.patch, failed testing.

koence’s picture

Status: Needs review » Reviewed & tested by the community

Did some manual and automated tests.
Looks good to me.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/views.theme.inc
@@ -660,9 +661,13 @@ function template_preprocess_views_view_table(&$variables) {
+  if (!empty($variables['title'])) {
+    $variables['title'] = ViewsRenderPipelineSafeString::create($variables['title']);
+  }

This does look right - how is $variables['title'] being set? This looks like it is user input and therefore this would be very unsafe.

geertvd’s picture

Status: Needs work » Needs review
FileSize
1.69 KB
3.87 KB

After looking into this again I noticed $variables['title'] actually turned out to be a SafeString object so ViewsRenderPipelineSafeString::create() was not necessary there anymore.
While I was testing this I did bump into another issue in StylePluginBase::renderGrouping() which was using that same SafeString object as an array key which caused a fatal error.
I'm not completely sure why this wasn't picked up by our tests though.

For now, this patch fixes that but maybe we need to expand our test coverage there.

Status: Needs review » Needs work

The last submitted patch, 44: missing_caption_if-2302319-44.patch, failed testing.

geertvd’s picture

The fatal error was not appearing because the grouping field in our has a label.
StylePluginBase::renderGrouping() is doing this:

if ($this->view->field[$field]->options['label']) {
  $group_content = $this->view->field[$field]->options['label'] . ': ' . $group_content;
}

So the string cast is happening there.

The reason that the test is failing is because the grouping string is not marked as safe in combination with the label.

geertvd’s picture

Priority: Normal » Major

Setting this to Major since this is a Fatal Error that I can reproduce on HEAD

geertvd’s picture

This should demonstrate the problem.
The complete patch should fail on the unsafe markup with a label.

Status: Needs review » Needs work

The last submitted patch, 48: missing_caption_if-2302319-48.patch, failed testing.

The last submitted patch, 48: missing_caption_if-2302319-48-test.patch, failed testing.

geertvd’s picture

Issue tags: +SafeMarkup
geertvd’s picture

geertvd’s picture

Looked into this issue a bit more.

The reason the group label is being double escaped is because of the string casting happening in StylePluginBase::renderGrouping():

if ($this->view->field[$field]->options['label']) {
  $group_content = $this->view->field[$field]->options['label'] . ': ' . $group_content;
}

I would have thought the label would have been added in theme_views_view_field() but it's actually being added in theme_views_view_fields().

So either we need to move the caption label logic to a preprocess function or template, which I don't want to do since then we're just copying logic from theme_views_view_fields() or just mark the string safe somehow.

Lendude’s picture

Manually tested this, and this is still an issue.

Since the fix for the fatal error was fixed in #2546924: Views fatal error when grouping on a field without a label set, we can take that bit out.
Also a lot of other safe markup stuff and theming has changed since this was last rolled. Setting the caption to markup with the escaped title in it does the trick to pass the tests.

Lendude’s picture

Priority: Major » Normal
Status: Needs work » Needs review

Since the fatal error has been fixed elsewhere, I think we can move this back to normal.

dawehner’s picture

+++ b/core/modules/views/src/Tests/Plugin/StyleTableTest.php
@@ -136,4 +136,80 @@ public function testNumericFieldVisible() {
+    $view = \Drupal::entityManager()->getStorage('view')->load('test_table');

let's use the entity type manager directly

Lendude’s picture

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Yeah, thanks for that!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 57: missing_caption_if-2302319-57.patch, failed testing.

Lendude’s picture

reroll, didn't apply anymore.

Lendude’s picture

Status: Needs work » Needs review
greggmarshall’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
20.83 KB
31.61 KB

Confirmed the re-rolled patch applied correctly against 8.0.x-DEV and correctly displays the caption after being applied.

Before and after screen shots attached.

  • catch committed 561b42c on 8.1.x
    Issue #2302319 by geertvd, Lendude: Missing caption, if view (format...

  • catch committed 0172e3f on
    Issue #2302319 by geertvd, Lendude: Missing caption, if view (format...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.1.x and cherry-picked to 8.0.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.