• Resolved Buchanan Webmaster

    (@jeffsydor-bipc)


    I’m trying to add some sidebar content to my WordPress search results page where the top categories and tags, related to the current search query, are displayed. I have been able to generate the content, but there are a massive amount of duplicates also displaying. Click for my example page.

    I’ve tried two ways of doing this, both with no success. Both were pulled from previous threads with similar questions. I would prefer avoiding 3rd party plugins if possible. Any ideas would be appreciated. Thanks

    First Try:

    function list_search_cats() {
      // Start the Loop
      $uniqueCats = array();
      while ( have_posts() ) : the_post();
    
        $cats = get_the_category();
    
        if (! in_array($cats, $uniqueCats)) :
          $uniqueCats[] = $cats;
          foreach($cats as $cat) :
            echo '<li><a class="tag" href="'.get_category_link($cat->cat_ID).'">' . $cat->cat_name . '</a></li>';
          endforeach;
        endif;
    
      endwhile;
    
    }

    Second Try:

    function list_search_cats() {
      // Start the Loop
      $uniqueCats = array();
      while ( have_posts() ) : the_post();
    
        $cats = get_the_category();
        $cats = array_unique($cats, SORT_REGULAR);
    
        foreach($cats as $cat) :
          echo '<li><a class="tag" href="'.get_category_link($cat->cat_ID).'">' . $cat->cat_name . '</a></li>';
        endforeach;
    
      endwhile;
    
    }

    The page I need help with: [log in to see the link]

Viewing 9 replies - 1 through 9 (of 9 total)
  • Hi @jeffsydor-bipc,
    It seems that you are messing things with nested loops there.
    Let’s take your first attempt as example and make it work:

    function list_search_cats() {
      // First we set the empty array for unique categories in local scope
      $uniqueCats = array();
      // Then we loop through search results 
      while ( have_posts() ) : the_post();
    
        $cats = get_the_category();
    
        if (! in_array($cats, $uniqueCats)) :
          $uniqueCats[] = $cats;
        endif;
      endwhile;
      //Then when the loop is finished we loop through the unique cats array.
      foreach($uniqueCats as $cat) :
            echo '<li><a class="tag" href="'.get_category_link($cat->cat_ID).'">' . $cat->cat_name . '</a></li>';
      endforeach;
    }

    I haven’t tested this code, it may need some adjustment, but you can get the idea. Your foreach was executed several times and that’s why you got duplicated categories in the output.

    Hope this helps.
    Take care!

    • This reply was modified 5 years, 2 months ago by jjberry.
    Thread Starter Buchanan Webmaster

    (@jeffsydor-bipc)

    Hmm it seems like the variable $cat is no longer recognized after that.

    I get the following errors:
    Trying to get property ‘cat_ID’ of non-object … line 114
    Trying to get property ‘cat_name’ of non-object … line 114

    That line is the echo:
    echo '<li><a class="tag" href="'.get_category_link($cat->cat_ID).'">' . $cat->cat_name . '</a></li>';

    Thread Starter Buchanan Webmaster

    (@jeffsydor-bipc)

    So I’m probably way off here, but this is what I tried to do. I figured that I could create the empty array $uniqueCats first, start the loop to create the string for each list item and store that string into the empty array if it didn’t already exist in there.

    Then, I would separate new array of strings and output each as a unique item. Obviously this didn’t work, but I’m not sure if this was worth sharing or not.

    function list_search_cats() {
      // Start the Loop
      $uniqueCats = array();
      while ( have_posts() ) : the_post();
      
        $cats = get_the_category();
      
        foreach($cats as $cat) :
          $catLink = get_category_link($cat->cat_ID);
          $catName = $cat->cat_name;
          $newCat = '<li><a class="tag" href="'. $catLink .'">' . $catName . '</a></li>';
          
          if (!in_array($newCat, $uniqueCats)) : array_push($uniqueCats, $newCat);
          endif;
        endforeach;
      
        foreach($uniqueCats as $uniqueCat) :
          echo $uniqueCat;
        endforeach;
      
      endwhile;
    }
    Thread Starter Buchanan Webmaster

    (@jeffsydor-bipc)

    I don’t know if this helps or not, but after further tinkering, it looks like my array is actually an array with multiple arrays inside it. Could this be what’s causing the duplication? Can these arrays be pulled out into the root array?

    Moderator bcworkz

    (@bcworkz)

    Your initial attempts have duplicates because you have nested loops without any mechanism for discarding duplicates. get_the_category() returns an array of term objects. jjberry had the right idea in using not in_array() to check for duplicates. However, in_array() doesn’t work well in detecting duplicate objects. To be fair, jjberry did say their code needed adjustment ??

    Your last attempt is much better in that you’ve extracted the pertinent object data for use in not in_array(), but it involves more processing than necessary. You’re building links whether they will be used or not. I’m not sure where you’re getting arrays of arrays. In any case I would suggest a slightly different approach.

    You should maintain two arrays of unique data to get this to work well. One of only category term IDs to use in detecting duplicates with not in_array(), and a second of unique term objects that have passed the not in_array() test. Or directly output the term links instead of keeping an array of objects if that works within the context of your code. I would still keep an array anyway because we can then sort the term objects before beginning output.

    So in other words, first initialize two empty arrays.

    For each post, get its categories. You get an array of term objects.

    For each term, extract its ID and check if it is not in an array of unique IDs. The first time through the array is empty so the not in_array() test passes.

    If the not in_array() test passes, add the current term ID to the unique ID array and also add the entire term object to the other array.

    Rinse and repeat until all posts and post category terms have been processed.

    You don’t need the unique ID array any more now, you have an array of all unique term objects. You may sort this array if you like using usort().

    For each term in the unique array output the links.

    Dion

    (@diondesigns)

    Assuming the underlying logic of your function is correct, the following should do what you want. It uses a temporary array to store IDs that have been found, and that array is checked to determine whether to generate the link HTML. This will be an order of magnitude (if not more) faster than using in_array() since it must only check whether an array key exists. Code has not been tested.

    function list_search_cats() {
    	$catTmp = array();
    	$catLinks = '';
    
    	while (have_posts()) {
    		the_post();
    		$cats = get_the_category();
    
    		foreach ($cats as $cat) {
    			$catID = $cat->cat_ID;
    
    			if (empty($catTmp[$catID])) {
    				$catTmp[$catID] = 1;
    				$catLinks .= '<li><a class="tag" href="' . get_category_link($catID) . '">' . $cat->cat_name . '</a></li>';
    			}
    		}
    	}
    
    	echo $catLinks;
    }
    Thread Starter Buchanan Webmaster

    (@jeffsydor-bipc)

    @diondesigns thank you! This worked perfectly!

    Now I think I need to find a way to sort them by number of occurrences. But now I need to understand why yours works!

    Thank you!

    Thread Starter Buchanan Webmaster

    (@jeffsydor-bipc)

    @diondesigns I tried adapting this for my tags section too. But for some reason it’s not working here. Any ideas?

    function list_search_tags() {
       $tagTmp = array();
       $tagLinks = '';
      
       // Start The Loop
          while (have_posts()) : the_post();
             $post_tags = get_the_tags();
    
             foreach ($post_tags as $tag) : $tagID = $tag->term_id;
    
                if (empty($tagTmp[$tagID])) :
                   $tagTmp[$tagID] = 1;
                   $tagURL = get_tag_link($tagID);
                   $tagName = $tag->name;
                   $tagLinks .= '<li><a class="tag" href="' . $tagURL . '">' . $tagName . '</a></li>';
                endif;
      
          endforeach;
       endwhile;
    
       echo $tagLinks;
      
    }
    
    Thread Starter Buchanan Webmaster

    (@jeffsydor-bipc)

    Nope, nevermind! I just realized there weren’t any tags applied to the posts. Silly me. lol

Viewing 9 replies - 1 through 9 (of 9 total)
  • The topic ‘Need help removing duplicated results from a foreach loop’ is closed to new replies.