phpwordpresssortingtagstaglist

Display Tag List alphabetically with a sections for each letter, including the empty letters that have no terms


I would like to sort a tag list by alphabet with their corresponding letter. including the empty ones.

At the moment I'm listing only the letter that has tags but can't get them to display/sort alphabetically. Then I also have the issue of it not showing the empty letter in the alphabet. Also worth mentioning I added the asort() because it wasn't sorting correctly.

Working:

Not working:

This is what I have so far:

<?php
   $args = array(
     'taxonomy' => 'post_tag',
     'hide_empty' => false,
     'order' => 'ACS',
     'orderby' => 'slug'
    );
    $terms = get_terms($args);

                       
    $term_list = [];    
    foreach ( $terms as $term ){
      $first_letter = strtoupper($term->name[0]);
      $term_list[$first_letter][] = $term;
    }
    unset($term); 
    asort($term_list );?>
                    
   <div class="tag-wrap">

     <ul>
      <?php foreach ( $term_list as $key=>$value ) : ?>
         <li class="border-radius">
           <a href="#<?php echo $key; ?>"><h3><?php echo $key; ?></h3></a>
         </li>
      <?php endforeach; ?>
     </ul>
  </div>

 <div class="tag-list">
    <?php
      asort($term_list );

      foreach ( $term_list as $key=>$value ) : ?>
         <div class="term-row" id="<?php echo $key; ?>">
            <div class="term-letter">
                <h3><?php echo $key; ?></h3>
            </div>
                                
            <div class="tag-items">
               <?php foreach ( $value as $term ): ?>
                    <div class="tag-item">
                        <a href="<?php echo get_term_link( $term );?>"><?php echo $term->name;?></a>
                    </div>
               <?php endforeach;?>
             </div>
         </div>
      <?php endforeach;?>
 </div>

Its displaying like this at the moment: Tagwrap: Tagwrap output

Tag List: Same sorting order as the above, its pretty much using the same php.


Solution

  • Sorting the terms is not going to make a difference to what you are trying to do. If you want to include letters that are not in your results, then you can't use the results for your loop regardless of how it's sorted, because it can only loop through what's there.

    Instead, we can simply loop on the alphabet and use the letter as the key to get the terms from your array.

    First, loop through the alphabet to display the letters in your tag-wrap div:

    $alphabet = range('A', 'Z');   // 1. use range to get the alphabet
    
    <div class="tag-wrap">
       <ul>
         <?php
         // 2. display the regular alphabet instead of the letters from your results
         foreach ( $alphabet as $letter ) : ?>
             <li class="border-radius">
               <a href="#<?php echo $letter; ?>"><h3><?php echo $letter; ?></h3></a>
             </li>
        <?php endforeach; ?>
       </ul>
    </div>
    

    Now we will again loop through the alphabet, and this time get the results from your $term_list using the letter as the key. If there are no terms, then you can display a message, otherwise you can display the list as you were before.

    <div class="tag-list">
        <?php
          // 3. display the results by looping through the alphabet to ensure all letters are included
          foreach ( $alphabet as $letter) : ?>
             <div class="term-row" id="<?php echo $letter; ?>">
                <div class="term-letter">
                    <h3><?php echo $letter; ?></h3>
                </div>
                                    
                <div class="tag-items">
                   <?php
                        // 4. Get the terms for this letter, if there are none show a message
                        $termsforletter = $term_list[$letter];
                        if (empty($terms for letter)) { ?>
                             <p>No Results for this letter</p>
                        <?php } 
                        else {
                            foreach ( $termsforletter as $term  ): ?>
                                <div class="tag-item">
                                    <a href="<?php echo get_term_link( $termsforletter  );?>"><?php echo $term->name;?></a>
                               </div>
                           <?php endforeach;
                        } ?>
                 </div>
             </div>
          <?php endforeach;?>
     </div>
    

    (Note: This code is untested but the general idea is there)

    This also means that you don't have to worry about doing any sorts on your arrays because we are using the alphabet loop to sort thedisplay/