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 the Save configuration
button.
- Go to
/en/admin/config/development/performance
and click Clear 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, run document.querySelectorAll('.region-content a[href^="/en/tags/"]').length
in the browser console to verify).
- 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
- Breakfast
- Carrots
- Cocktail party
- Dessert
- Drinks
- Grow your own
- Herbs
- Learn to cook
- Mushrooms
- Oats
- Party
- Seasonal
- Shopping
- Soup
- Supermarkets
- Vegan
- Vegetarian
- Go to
/en/admin/config/development/performance
and click Clear 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.
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.
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
- Write a patch
- Review and feedback
- RTBC and feedback
- Commit
- Release
User interface changes
To be determined.
API changes
To be determined.
Data model changes
To be determined; likely none.