CMS Development

Woodsy
Top Contributor

Create a blog filter for resource type

How can I create a filter for resource type that can be used as well as a topic filter? I have set up a custom field in my blog post that captures the resource type:
{% choice "resource_type" label='Choose the resource type', value='type', choices='eBook, Case Study, Infographic, Technical, Video, White Paper', export_to_template_context=True %}

 

How do I use this info to be able to filter the blog posts in a dropdown?
This is what I am currently using for the topic filter:
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Filter resources by &#x25BC;</button>
<div id="myDropdown" class="dropdown-content">
{% post_filter "posts_by_topic" select_blog='5124593000', expand_link_text='see all', overrideable=False, filter_type='topic', label='Posts by Topic' %}
</div>
</div>

 

Can I write something similar for the resource type?

0 Upvotes
13 Replies 13
Jsum
Key Advisor

Create a blog filter for resource type

@Woodsy,

 

This article is really helpful. 

 

The way I do it is on the same track to what you are doing.

 

First, I create a custom field on the post page like you did with your choice module:

{% choice "resource_type" label='Choose the resource type', value='type', choices='eBook, Case Study, Infographic, Technical, Video, White Paper', export_to_template_context=True %}

You then want to reference this choice field's choices as your drop down:

<ul>
{% for choice in content.widgets.resource_type.body.choices %}
    <li><a href="{{ group.absolute_url }}?q={{ choice|lower }}">{{ choice }}</a></li>
{% endfor %}
</ul>

Notice I looped throug the choices from the choice field, creating a list item and link for each one, and the link is the group absolute url with a query at the end which is unique to the choice.

 

** this next part is done on the listing page **

 

Now you need to grab your query:

{% set query = request.query_dict.q|lower %}

Then filter Your content based on the query:

{% if query is defined %}

	{% for content in contents %}
                            
    		{% set type = content.widgets.resource_type.body.value|lower %}
                            
    		{% if query equals type %}
                                
        		{# blog item markup for filtered results #}	
                                
     		{% endif %}
                            
	{% endfor %}
                    
{% else %}

	{% for content in contents %}
    
		{# blog item markup for regular listing #}

	{% endfor %}

{% endif %}

 

tlow87
Participant

Create a blog filter for resource type

@Jsum would you be willing to work with my team to put together a resource library? Feel free to email me if you're interested tannie@mavenlink.com 

0 Upvotes
anjalijain
Participant

Create a blog filter for resource type

what does this query do and what is query_dict?

 

{% set query = request.query_dict.q|lower %}

  

0 Upvotes
anjalijain
Participant

Create a blog filter for resource type

{% if query is defined %}
{% for content in contents %}
{% set type = content.widgets.type_of_category.body.value|lower %}

{% if query equals type %}

 

 

 

Above conditions are not working for me

0 Upvotes
Woodsy
Top Contributor

Create a blog filter for resource type

Thanks, where do I put the part of the code that goes on the listing page?

0 Upvotes
Jsum
Key Advisor

Create a blog filter for resource type

in the listing page section of your blog module...

0 Upvotes
Woodsy
Top Contributor

Create a blog filter for resource type

This is the current code I have in the listing page section:

 

<div class="blog-section portfolio">
<div class="blog-listing-wrapper cell-wrapper">
<div class="row same-height-parent isotope" style="display:flex; flex-wrap:wrap;">
{% for content in contents %}
<div class="span4 resource-listing-thumb original inspire-site {{ content.widgets.filter.body.value }} {{ content.widgets.resource_type.body.value }}">
<!--<a href="{{ content.absolute_url }}" class="inspire-block"> -->
<a href="{{ content.widgets.resource_link.body.value }}" class="inspire-block">
<div class="portfolio-image-wrapper">
<img class="portfolio-image" src="{{ content.widgets.thumbnail_image.body.src }}" alt="{{ content.widgets.listingimage.body.alt }}" />
<!--<span class="cta orange">See More</span> -->
</div>
<!--<span class="portfolio-title same-height"> {{ content.name}} </span> -->
<h4>{{content.name }}</h4
</a>
</div>
{% endfor %}

</div>

<hr >
<div class="blog-pagination">
{% if contents.total_page_count > 0 %}
{% if widget.range == 10 %}
{% set base = 10 %}
{% set loop_ = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] %}
{% else %}
{% set base = 5 %}
{% set loop_ = ['1', '2', '3', '4', '5'] %}
{% endif %}

{% set current_pg_index = last_page_num + 1 %}
{% set range_start = ((1 - current_pg_index) % base) + current_pg_index %}

{# EXTRA: calculate start of previous range and end of next
{% set range_end = range_start + (base)-1 %}

{% set previous_range_start = ((6 - current_pg_index) % base) + current_pg_index - base %}
{% if previous_range_start < 1 %}
{% set previous_range_start = 1 %}
{% endif %}
#}
<ul>
<li class="first-posts-link {% if current_pg_index <= 1 %}hide{% endif %}"><a href="{{ blog_page_link(1) }}"><i class="fa fa-angle-double-left"></i></a></li>
<li class="previous-posts-link {% if !last_page_num %}hide{% endif %}"><a href="{{ blog_page_link(last_page_num) }}"><i class="fa fa-angle-left"></i></a></li>
<span class="pg">
{% set i = range_start %}
{% for pg in loop_ %} {# effectively, for i=1 to i=base #}
{% if i <= contents.total_page_count %}
<li{% if i == current_pg_index %} class="active"{% endif %}><a href="{{ blog_page_link(i) }}">{{ i }}</a></li>

{% set i = i + 1 %}
{% endif %}
{% endfor %}
</span>
<li class="next-posts-link {% if current_pg_index == contents.total_page_count %}hide{% endif %}"><a href="{{ blog_page_link(next_page_num) }}"><i class="fa fa-angle-right"></i></a></li>
<li class="last-posts-link {% if current_pg_index == contents.total_page_count %}hide{% endif %}"><a href="{{ blog_page_link(contents.total_page_count) }}"><i class="fa fa-angle-double-right"></i></a></li>
</ul>
{% endif %}
</div>
</div>
</div>


Could you advise on where both parts of the code should be placed?

Thanks

0 Upvotes
Jsum
Key Advisor

Create a blog filter for resource type

Could you format this and use the </> insert code function? there is a lot to look at here and it is a mess when not formatted propery. 

 

Also, what is the issue that you are having?

0 Upvotes
Woodsy
Top Contributor

Create a blog filter for resource type

This is the current code I have in the listing page section:

 

<div class="blog-section portfolio"> 
  <div class="blog-listing-wrapper cell-wrapper"> 
    <div class="row same-height-parent isotope" style="display:flex; flex-wrap:wrap;"> 
   {% for content in contents %} 
   <div class="span4 resource-listing-thumb original inspire-site {{ content.widgets.filter.body.value }} {{ content.widgets.resource_type.body.value }}"> 
      <!--<a href="{{ content.absolute_url }}" class="inspire-block"> -->
      <a href="{{ content.widgets.resource_link.body.value }}" class="inspire-block">
        <div class="portfolio-image-wrapper"> 
           <img class="portfolio-image" src="{{ content.widgets.thumbnail_image.body.src }}" alt="{{ content.widgets.listingimage.body.alt }}" /> 
           <!--<span class="cta orange">See More</span> -->
        </div> 
        <!--<span class="portfolio-title same-height"> {{ content.name}} </span> -->
        <h4>{{content.name }}</h4
      </a> 
   </div> 
  {% endfor %} 
 

 </div> 
 
 <hr >
        <div class="blog-pagination">
        {% if contents.total_page_count > 0 %}
            {% if widget.range == 10 %}
                {% set base = 10 %}
                {% set loop_ = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] %}
            {% else %}
                {% set base = 5 %}
                {% set loop_ = ['1', '2', '3', '4', '5'] %}
            {% endif %}
            
            {% set current_pg_index = last_page_num + 1 %}
            {% set range_start = ((1 - current_pg_index) % base) + current_pg_index %}
            
            {# EXTRA: calculate start of previous range and end of next
                {% set range_end = range_start + (base)-1 %}
            
                {% set previous_range_start = ((6 - current_pg_index) % base) + current_pg_index - base  %}
                {% if previous_range_start < 1 %}
                    {% set previous_range_start = 1 %}
                {% endif %}
            #}
            <ul>
                <li class="first-posts-link {% if current_pg_index <= 1 %}hide{% endif %}"><a href="{{ blog_page_link(1) }}"><i class="fa fa-angle-double-left"></i></a></li>
                <li class="previous-posts-link {% if !last_page_num %}hide{% endif %}"><a href="{{ blog_page_link(last_page_num) }}"><i class="fa fa-angle-left"></i></a></li>
                <span class="pg">
                    {% set i = range_start %}
                    {% for pg in loop_ %} {# effectively, for i=1 to i=base #}
                        {% if i <= contents.total_page_count %}
                            <li{% if i == current_pg_index %} class="active"{% endif %}><a href="{{ blog_page_link(i) }}">{{ i }}</a></li>
                        
                        {% set i = i + 1 %}
                        {% endif %}
                    {% endfor %}
                </span>
                <li class="next-posts-link {% if current_pg_index == contents.total_page_count %}hide{% endif %}"><a href="{{ blog_page_link(next_page_num) }}"><i class="fa fa-angle-right"></i></a></li>
                <li class="last-posts-link {% if current_pg_index == contents.total_page_count %}hide{% endif %}"><a href="{{ blog_page_link(contents.total_page_count) }}"><i class="fa fa-angle-double-right"></i></a></li>
            </ul>
        {% endif %}
        </div>  
</div> 
</div>

 

Could you advise on where both parts of the code should be placed?

 

I have already got a dropdown for 'by topics' working and would like a second dropdown that you can select 'by resource type'.

0 Upvotes
Jsum
Key Advisor

Create a blog filter for resource type

@Woodsy,

 

Just so you know, this is pretty heavy. I'll try to break it down for you. 

 

In your post template code You want to place the choice module for your custom topic:

{% choice "resource_type" label='Choose the resource type', value='type', choices='eBook, Case Study, Infographic, Technical, Video, White Paper', export_to_template_context=True %}

In outer blog template, not in your post template or your listing template but the main template holding the blog module, you want to place your dropdown:

<ul>
{% for choice in content.widgets.resource_type.body.choices %}
    <li><a href="{{ group.absolute_url }}?q={{ choice|lower }}">{{ choice }}</a></li>
{% endfor %}
</ul>

In your listing template code you want to set up the logic to filter your posts if there is a query, and use a basic contents for loop if there isn't a query. Like this:

{% if query is defined %}

	{% for content in contents %}
                            
    		{% set type = content.widgets.resource_type.body.value|lower %}
                            
    		{% if query equals type %}
                                
        		{# blog item markup for filtered results #}	
                                
     		{% endif %}
                            
	{% endfor %}
                    
{% else %}

	{% for content in contents %}
    
		{# blog item markup for regular listing #}

	{% endfor %}

{% endif %}

Check out the comment code between the {# #}. It tells you which loop works for which. The top for loops is for if there is a query, the bottom for loop is for if there isn't a query. Your mark up will probably be pretty much the same unless you want your layout to be different based on whether or not a query exists. 

 

Where to put your this code is going to depend on where you want your blog list. In your case, it looks like your current for loop is at the top of your code: 

<div class="blog-section portfolio"> 
  <div class="blog-listing-wrapper cell-wrapper"> 
    <div class="row same-height-parent isotope" style="display:flex; flex-wrap:wrap;"> 
   {% for content in contents %} 
   <div class="span4 resource-listing-thumb original inspire-site {{ content.widgets.filter.body.value }} {{ content.widgets.resource_type.body.value }}"> 
      <!--<a href="{{ content.absolute_url }}" class="inspire-block"> -->
      <a href="{{ content.widgets.resource_link.body.value }}" class="inspire-block">
        <div class="portfolio-image-wrapper"> 
           <img class="portfolio-image" src="{{ content.widgets.thumbnail_image.body.src }}" alt="{{ content.widgets.listingimage.body.alt }}" /> 
           <!--<span class="cta orange">See More</span> -->
        </div> 
        <!--<span class="portfolio-title same-height"> {{ content.name}} </span> -->
        <h4>{{content.name }}</h4
      </a> 
   </div> 
  {% endfor %} 
 </div> 

 

So modify this part of your code. Specifically you want to do this:

<div class="blog-section portfolio">
	<div class="blog-listing-wrapper cell-wrapper">
		<div class="row same-height-parent isotope" style="display:flex; flex-wrap:wrap;">
   			{% if query is defined %}
   				{% for content in contents %}
   					{% set type = content.widgets.resource_type.body.value|lower %}
   					{% if query equals type %}
   						{# blog item markup for filtered results #}
   						<div class="span4 resource-listing-thumb original inspire-site {{ content.widgets.filter.body.value }} {{ content.widgets.resource_type.body.value }}">
      							<!--<a href="{{ content.absolute_url }}" class="inspire-block"> -->
      							<a href="{{ content.widgets.resource_link.body.value }}" class="inspire-block">
         							<div class="portfolio-image-wrapper">
            								<img class="portfolio-image" src="{{ content.widgets.thumbnail_image.body.src }}" alt="{{ content.widgets.listingimage.body.alt }}" /> 
            								<!--<span class="cta orange">See More</span> -->
         							</div>
         							<!--<span class="portfolio-title same-height"> {{ content.name}} </span> -->
         							<h4>{{content.name }}</h4>
      							</a>
   						</div>
					{% endif %}
   				{% endfor %} 
			{% else %}
				{% for content in contents %}
					{# blog item markup for regular listing #}
					<div class="span4 resource-listing-thumb original inspire-site {{ content.widgets.filter.body.value }} {{ content.widgets.resource_type.body.value }}">
      						<!--<a href="{{ content.absolute_url }}" class="inspire-block"> -->
      						<a href="{{ content.widgets.resource_link.body.value }}" class="inspire-block">
         						<div class="portfolio-image-wrapper">
            							<img class="portfolio-image" src="{{ content.widgets.thumbnail_image.body.src }}" alt="{{ content.widgets.listingimage.body.alt }}" /> 
            							<!--<span class="cta orange">See More</span> -->
         						</div>
         						<!--<span class="portfolio-title same-height"> {{ content.name}} </span> -->
         						<h4>{{content.name }}</h4>
      						</a>
   					</div>
				{% endfor %}
			{% endif %}
		</div>
	</div>
        <hr >
        <div class="blog-pagination">
        	{% if contents.total_page_count > 0 %}
            		{% if widget.range == 10 %}
                		{% set base = 10 %}
                		{% set loop_ = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] %}
            		{% else %}
                		{% set base = 5 %}
                		{% set loop_ = ['1', '2', '3', '4', '5'] %}
            		{% endif %}
            
            		{% set current_pg_index = last_page_num + 1 %}
            		{% set range_start = ((1 - current_pg_index) % base) + current_pg_index %}
            
            		{# EXTRA: calculate start of previous range and end of next
                		{% set range_end = range_start + (base)-1 %}
            
                		{% set previous_range_start = ((6 - current_pg_index) % base) + current_pg_index - base  %}
                		{% if previous_range_start < 1 %}
                    			{% set previous_range_start = 1 %}
                		{% endif %}
            		#}
            		<ul>
                		<li class="first-posts-link {% if current_pg_index <= 1 %}hide{% endif %}"><a href="{{ blog_page_link(1) }}"><i class="fa fa-angle-double-left"></i></a></li>
                		<li class="previous-posts-link {% if !last_page_num %}hide{% endif %}"><a href="{{ blog_page_link(last_page_num) }}"><i class="fa fa-angle-left"></i></a></li>
                		<span class="pg">
                    			{% set i = range_start %}
                    			{% for pg in loop_ %} {# effectively, for i=1 to i=base #}
                        			{% if i <= contents.total_page_count %}
                            				<li{% if i == current_pg_index %} class="active"{% endif %}><a href="{{ blog_page_link(i) }}">{{ i }}</a></li>
                        
                        				{% set i = i + 1 %}
                        			{% endif %}
                    			{% endfor %}
                		</span>
                		<li class="next-posts-link {% if current_pg_index == contents.total_page_count %}hide{% endif %}"><a href="{{ blog_page_link(next_page_num) }}"><i class="fa fa-angle-right"></i></a></li>
                		<li class="last-posts-link {% if current_pg_index == contents.total_page_count %}hide{% endif %}"><a href="{{ blog_page_link(contents.total_page_count) }}"><i class="fa fa-angle-double-right"></i></a></li>
            		</ul>
        	{% endif %}
        </div>  
</div>

Notice that it is the same exact mark up in bloth for loops. You can customize it if you would like. I like to add some text at the top of the filtered loop that states the query the list is filtered by. You can also add "no results" or "end of list" messages. 

 

0 Upvotes
Woodsy
Top Contributor

Create a blog filter for resource type

Thank you for your detailed response.

 

I can't get the dropdown to display which may be down to me needing to add further code around the follow:

<ul> {% for choice in content.widgets.resource_type.body.choices %} <li><a href="{{ group.absolute_url }}?q={{ choice|lower }}">{{ choice }}</a></li> {% endfor %} </ul>


Currently, I have the topic dropdown which uses the following code:

<div class="dropdown" style="float: left; padding:0px 10px">
    <button onclick="myFunction()" class="dropbtn">Filter by topic &#x25BC;</button>
    <div id="topicDropdown" class="topic-dropdown-content">
    {% post_filter "posts_by_topic" select_blog='5124593000', expand_link_text='see all', overrideable=False, filter_type='topic', label='Posts by Topic' %}
    </div>
</div>
<script>/* When the user clicks on the button, 
toggle between hiding and showing the dropdown content */
function myFunction() {
    document.getElementById("topicDropdown").classList.toggle("show");
}

// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {

    var dropdowns = document.getElementsByClassName("topic-dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
</script>

Can I recycle the above code for the new resource type dropdown? For example:

<div class="dropdown" style="float: left; padding:0px 10px">
    <button onclick="myFunction()" class="dropbtn">Filter by topic &#x25BC;</button>
    <div id="typeDropdown" class="type-dropdown-content">
    <ul> {% for choice in content.widgets.resource_type.body.choices %} <li><a href="{{ group.absolute_url }}?q={{ choice|lower }}">{{ choice }}</a></li> {% endfor %} </ul>
    </div>
</div>

I have changed the id and class used in the second dropdown so I would also need to call these in the script.

 

If this is possible what is the best way to rewrite the script so that both dropdowns don't conflict with each other?

0 Upvotes
Jsum
Key Advisor

Create a blog filter for resource type

@Woodsy,

 

That shouldn't be a problem.

 

You might want to go to your listing page, click the Hubspot "sprocket" in the top right corner, click developer info, and on the page that opens find your choice module by searching with ctrl (or cmd) + F for the module system name. There you will see:

1. if the module is available on the listing page outside of the contents loop

2. the structure if the module to see if you are targeting the choices correctly

 

You may need to just set an array with the same value as the choices in the module:

{% set choicearray = ['option 1', 'option 2', 'option 3'] %}

and loop through this to create your drop down menu:

<ul>
    {% for choice in choicearray %} 
        <li><a href="{{ group.absolute_url }}?q={{ choice|lower }}">{{ choice }}</a></li> 
    {% endfor %}
 </ul>

because you can't access content items outside of the contents loop. If you need to update or change this list of choices you will need to do it to both the choicearray and the choice module. This should create your list though.

nicolebrenner
HubSpot Employee
HubSpot Employee

Create a blog filter for resource type

Hi @Woodsy, thanks for posting! It looks like the HubL correctly matches the format ourlined in our Designer's documentation for for creating a choice module so I'm wondering if the issue is perhaps related to the HTML. 

Is the topic filter HTML something that you've customized, or is that the standard filter module from a HubSpot Template? Is it working for the topic? 

Lastly, have you tried to adjust that code so you can use resource_type instead of topic? What did that code look like and what was the result? 

 

@ndwilliams3 @Jsum @Gonzalo @stefen @DaniellePeters any insight here?

0 Upvotes