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

  1. Install DDEV
  2. Clone sitemap-8.x-2.x-dev:
    git clone https://git.drupalcode.org/project/sitemap.git ; cd sitemap
  3. 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
  4. Install Drupal with the Demo: Umami Food Magazine (Experimental) install profile:
    ddev drush -y si demo_umami
  5. Navigate to the web UI and log in:
    ddev launch $(ddev drush uli)
  6. Enable the sitemap module:
    ddev drush -y en sitemap
  7. 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.
  8. Go to /en/admin/config/development/performance and click Clear all caches.
  9. 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).
  10. 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.
  11. 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
  12. Go to /en/admin/config/development/performance and click Clear all caches.
  13. 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. 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

  1. Write a test to reproduce the problem - done in #3
  2. Write a patch - done in #5
  3. Review and feedback - done in #6
  4. RTBC and feedback - done in #6
  5. Commit - done in #8
  6. Release - released in version 8.x-2.1

User interface changes

None.

API changes

None.

Data model changes

None.

Issue fork sitemap-3540848

Command icon 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

mparker17 created an issue. See original summary.

mparker17’s picture

Issue summary: View changes
StatusFileSize
new320.76 KB

I'm attaching a screenshot showing the result of applying the patch in the issue summary to display the current value of the $currentDepth variable. I'll update the issue summary to link to it.

Anonymous’s picture

jernejmramor made their first commit to this issue’s fork.

Anonymous’s picture

Status: Active » Needs review

Hello,

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.

mparker17’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

@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!

mparker17’s picture

Issue summary: View changes

I'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.

  • mparker17 committed 2cafd9ed on 8.x-2.x
    [#3540848] fix: Vocabulary plugin stops outputting items in complex...
mparker17’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed
mparker17’s picture

@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!

mparker17’s picture

Update 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.

mparker17’s picture

Issue summary: View changes

Quick update: the changes in this issue have been released in version 8.x-2.1.

Status: Fixed » Closed (fixed)

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