Problem/Motivation
The Sitemap module has a "Vocabulary" plugin type to display the terms in a Taxonomy vocab. If the terms in the vocab have a hierarchy, it will display the terms as a set of nested unordered lists.
However, if the hierarchy is sufficiently complex, it will eventually stop outputting terms.
After outputting a term, \Drupal\sitemap\Plugin\Sitemap\Vocabulary::buildList() checks if ($maxDepth >= $currentDepth), and if TRUE, it renders the descendant terms. However, $currentDepth is only ever incremented: it isn't decremented when going back up a level, so if the hierarchy is complex enough, $currentDepth will eventually become larger than $maxDepth, i.e.: and it will stop outputting terms at that point.
Note that the code to output top-level terms (i.e.: terms with a NULL parent) is different, so those will always be output. As a result, $currentDepth will reset when a new top-level term is encountered. This may be why we haven't noticed the problem since it was introduced.
Steps to reproduce
- Install DDEV
- Clone
sitemap-8.x-2.x-dev:git clone https://git.drupalcode.org/project/sitemap.git ; cd sitemap - Set up the project with the ddev/ddev-drupal-contrib add-on:
ddev config --project-type=drupal --docroot=web --php-version=8.3 --corepack-enable ; ddev add-on get ddev/ddev-drupal-contrib ; ddev start ; ddev poser ; ddev symlink-project ; ddev config --update ; ddev restart - Install Drupal with the Demo: Umami Food Magazine (Experimental) install profile:
ddev drush -y si demo_umami - Navigate to the web UI and log in:
ddev launch $(ddev drush uli) - Enable the sitemap module:
ddev drush -y en sitemap - Display the Tags vocabulary on the sitemap: go to
/en/admin/config/search/sitemap, check Vocabulary: Tags, leave the configuration at their default values, and click theSave configurationbutton. - Go to
/en/admin/config/development/performanceand clickClear all caches. - View the sitemap by going to
/en/sitemap, and compare it with the list of terms in the vocabulary at/en/admin/structure/taxonomy/manage/tags/overview- All 28 terms in the Tags vocabulary should be visible on both pages.
(if you want, rundocument.querySelectorAll('.region-content a[href^="/en/tags/"]').lengthin the browser console to verify).
- All 28 terms in the Tags vocabulary should be visible on both pages.
- Go to View the sitemap by going to
/en/sitemap, and compare it with the list of terms in the vocabulary at/en/admin/structure/taxonomy/manage/tags/overview- All 28 terms in the Tags vocabulary should be visible on both pages.
- Run the following script with
drush -y php:
$tags = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['vid' => 'tags']); $firstTag = \reset($tags); $tagsSize = \count($tags); $previousTerm = NULL; for ($i = 1; $i <= $tagsSize; $i++) { $term = \array_shift($tags); if ($i === 1) { $previousTerm = $term; continue; } elseif (\in_array($i, \range(2, 16, 2), TRUE)) { $term->parent = [$firstTag]; $previousTerm = $term; } else { $term->parent = [$previousTerm]; } $term->save(); }Or, manually rearrange the items as follows:
- Alcohol free
- Baked
- Baking
- Breakfast
- Cake
- Carrots
- Chocolate
- Cocktail party
- Dairy-free
- Dessert
- Dinner party
- Drinks
- Egg
- Grow your own
- Healthy
- Herbs
- Learn to cook
- Mushrooms
- Oats
- Party
- Seasonal
- Shopping
- Soup
- Supermarkets
- Vegan
- Vegetarian
- Baked
- Alcohol free
- Go to
/en/admin/config/development/performanceand clickClear all caches. - View the sitemap by going to
/en/sitemap, and compare it with the list of terms in the vocabulary at/en/admin/structure/taxonomy/manage/tags/overview- Expected behavior:
- 28 terms in the Tags vocabulary should be visible on both pages in the above arrangement.
- Actual behavior:
- 16 terms in the Tags vocabulary are visible on the Sitemap. The terms under "Herbs" (i.e.: "Learn to cook", "Mushrooms", "Oats", "Party", "Pasta", "Pastry", "Seasonal", "Shopping", "Soup", "Supermarkets", "Vegan", "Vegetarian") are no longer visible on the sitemap.
- However, all 28 terms in the Tags vocabulary are visible on both pages in the above arrangement.
- Expected behavior:
Note that if I modify the code with the following patch...
diff --git a/src/Plugin/Sitemap/Vocabulary.php b/src/Plugin/Sitemap/Vocabulary.php
index 8f27238..94c3db3 100644
--- a/src/Plugin/Sitemap/Vocabulary.php
+++ b/src/Plugin/Sitemap/Vocabulary.php
@@ -328,13 +328,13 @@ public function view() {
* @return array|void
* Returns an array if the term display is TRUE.
*/
- protected function buildSitemapTerm($term) {
+ protected function buildSitemapTerm($term, string $currentDepth = '') {
$this->checkTermThreshold($term);
if ($term->display) {
return [
'#theme' => 'sitemap_taxonomy_term',
- '#name' => $term->name,
+ '#name' => \sprintf('%s [%s]', $term->name, $currentDepth),
'#url' => $this->buildTermLink($term) ?: '',
'#show_link' => $this->determineLinkVisibility($term),
'#show_count' => $this->determineCountVisibility($term),
@@ -449,7 +449,7 @@ protected function buildList(array &$list, $object, $vid, &$currentDepth, $maxDe
$children = $termStorage->loadTree($vid, $object->tid, 1);
if (!$children) {
$object->hasChildren = FALSE;
- if ($element = $this->buildSitemapTerm($object)) {
+ if ($element = $this->buildSitemapTerm($object, $currentDepth)) {
$list[$object->tid][] = $element;
}
return;
@@ -459,7 +459,7 @@ protected function buildList(array &$list, $object, $vid, &$currentDepth, $maxDe
// @todo That's not entirely accurate...
$object->display = TRUE;
$object->hasChildren = TRUE;
- $list[$object->tid][] = $this->buildSitemapTerm($object);
+ $list[$object->tid][] = $this->buildSitemapTerm($object, $currentDepth);
$list[$object->tid]['children'] = [];
$object_children = &$list[$object->tid]['children'];
}
... , then I can see the current value of the $currentDepth variable, which helps explain the behavior. See the attached screenshot named 3540848-2--screenshot-print-currentDepth.png showing the $currentDepth variable reaching the value 9.
Proposed resolution
Unknown at this time.
One possible way to fix this would be to find a way to $currentDepth-- when we go back up a level. However, I worry that the existing code in \Drupal\sitemap\Plugin\Sitemap\Vocabulary::view() may have yet-uncovered bugs.
I'd prefer to find a way to simplify the existing code (if possible) in \Drupal\sitemap\Plugin\Sitemap\Vocabulary::view()... in particular, if possible, it would be good to reuse/copy the logic for rendering the tree from the Taxonomy module, i.e.: the code used to display the "overview" list of terms in a vocab at /en/admin/structure/taxonomy/manage/tags/overview (i.e.: the code in \Drupal\taxonomy\Form\OverviewTerms::buildForm()).
Remaining tasks
Write a test to reproduce the problem- done in #3Write a patch- done in #5Review and feedback- done in #6RTBC and feedback- done in #6Commit- done in #8Release- released in version 8.x-2.1
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|
Issue fork sitemap-3540848
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mparker17I'm attaching a screenshot showing the result of applying the patch in the issue summary to display the current value of the
$currentDepthvariable. I'll update the issue summary to link to it.Comment #4
Anonymous (not verified) commentedjernejmramor made their first commit to this issue’s fork.
Comment #5
Anonymous (not verified) commentedHello,
I've taken a look into this issue and was able to replicate it locally. I found where we could add the currentDepth decrease so that all terms get correctly displayed in correct hierarchy. Test that OP added is now passing and I've also tested whether bigger vocabularies (200+) terms work and locally it looks good to me. Marking this as needs review.
Comment #6
mparker17@jernejmramor, awesome, thank you! I can also confirm it passes tests, works on my test site, and works on my client site.
(I had been working on refactoring the Vocabulary plugin, but I will move that effort to a different issue for now)
Thanks!
Comment #7
mparker17I've created #3541348: Clean up the Vocabulary::view() plugin logic as a follow-up to clean up the code and I'll move my changes there.
In the meantime, I've started a merge train.
Comment #9
mparker17Comment #10
mparker17@jernejmramor thanks again for your hard work!
I intend to give you credit for your work on this issue. I wanted to test out the new Contribution Records system, but I'm running into #3541362: I can't save contribution records for a project I maintain, which I think is a permissions problem.
It appears that I have a work-around, i.e.: I can access the old contribution records system. But I don't want to do anything with the old contribution system until I get a response on 3541362 from the Contribution Records project maintainers, i.e.: so they can see the issue themselves.
Thanks for your patience with me, and rest assured that I won't forget!
Comment #11
mparker17Update on #3541362: I can't save contribution records for a project I maintain, it's supposed to be read-only for now, so I'm going to assign credit the old way.. Thanks for your patience.
Comment #12
mparker17Quick update: the changes in this issue have been released in version 8.x-2.1.