Using isotope gallery in drupal 8 views

Using isotope gallery in drupal 8 views

Dimostrazione libreria isotope

At the time of writing the fancy module Isotope is not fully ported to drupal8. Waiting for a stable release for the new version of drupal, we can still build an isotope gallery with little customization in our theme.

Isotope by metafizzy is the well known javascript library that let you sort and filter content in a fancy and user-friendly way, improving user experience and giving some vivacity to our site.

So, let’s see it in action.

Requirements:

First step: integrating libraries to our theme.

First of all we have to include the isotope gallery we previously downloaded at metafizzy official website or github. If you don’t have one, create a new “js” folder in your theme and an “isotope” folder inside it, where we can put the downloaded isotope.pkgd.min.js file.
At the same time we will create a “custom” folder where we will put our custom javascript code (let’s call it “start-isotope.js) that will initialize the isotope function. The folder structure will look like:

my_theme/js/isotope
my_theme/js/custom

Now we need to include these libraries in our theme, editing the libraries.yml file of our theme (usually theme_name.libraries.yml):

isotope:
  version: 3.0.6
  js:
    js/isotope/isotope.pkgd.min.js: {}
  dependencies:
    - core/jquery

custom:
  version: VERSION
  js:
    js/custom/start-isotope.js: {}
  dependencies:
- core/jquery

Note that you may need to adjust the isotope version number with the actual version you downloaded. We also need to “inform” drupal that we will load these libraries, so we'll add some lines of code to our info.yml theme file (my_theme.info.yml), at the libraries section if we have one:

libraries: 
  - my_theme/custom
  - my_theme/isotope

Finally we will edit the .theme file (my_theme.theme) to attach the libraries to the view that we'll create in the next step:

function my_theme_preprocess_views_view__my_isotope_list (&$variables) {
$variables['#attached']['library'][] = 'my_theme/isotope'; 
$variables['#attached']['library'][] = 'my_theme/custom'; 
}

If you are familiar with drupal name convention, you have noticed I’ve used the view list template, because I found much easier to control both the isotope elements and filters by an HTML list. You can find more on Drupal API documentation.

Second step: building the view.

This was a little tricky, because I would like to be as much close as possible to the Isotope module’s way. Assume we already have some content tagged with some terms. Let’s create a new “My Isotope” page view, showing content of some type, tagged with terms from our vocabulary we will use as filters, set the HTML list format of fields.
Usually we would like to show all elements, but if you have a large number of elements, you may use pagination to not affect speed load.

Under “Format > Format: settings” we can include the row class(es) for the isotope elements. In this case I will suggest something like: “ isotope-item {{ field_term }} ”. You may add your custom classes or the bootstrap columns classes (if you use a bootstrap based theme) to present the elements in a more clean display.

What make difference here is the class that identify the element (isotope-item) and the token {{ field_term }}, that represent the field term ID used in the node. Note that you need to add this field in the fields settings to use it as replacement.

Under "Wrapper Class" that contain the element add something like: “ myIsotopeContainer ”.
Add all the fields you need to show, let’s say:

  • a link to the content (you may want to output just the link text);
  • an image field (in most cases you may want to show an image, but it’s not mandatory, it could be a body or something else);
  • a title (not much to say about it);
  • the taxonomy term field, formatted as Entity ID which we will use as isotope filter.

Hide all of them to make things simple (and we want to make things simple, right?).

In the taxonomy term field, we will also rewrite the result with something like “ tid-{{ field_term }} ”. Be careful about formatting the taxonomy term as Entity ID if you use this rewriting result, if you don’t, be sure to use some delta value to return the term ID as result. This is the most clean way I found to output classes that matches filters. Other ways are possible, but they may result in confusion if you have terms composed by two words, blank spaces and so.
Finally we will add a Global custom text field (the simple thing I was talking about) and fill it with the hidden content wrapped in a single div:

<div><h2><a href="{{ view_node }}">{{ title }}</a></h2>{{ field_image }}</div>

Anything here is up to you: you may add classes, overlay animations and so on... it’s just an example.

Now add a View Attachment, which we will use to show filters. If you are not familiar with drupal View module, be careful to apply all next changes to the View Attachment itself (mean "Overwrite this attachment" select option), otherwise changes will apply to all views.

This attachment is an HTML list like before. This time, in the Settings option under Format, we will leave blank the Row Class field, while we will add a Wrapper Class (for example “ myIsotopeFilter ”) and a Class in the List (for example “ filter ”).

Under Fields we will add our taxonomy term field from the node, this time shown as label, but we don't want it to be linked to the entity (uncheck the relative box). Then we will add a (Content) ID field and hide it from display: this is important for aggregation that we will use later and which make me lost some hours to make it work properly.

In the Sorting Criteria section add again “Content ID” field. I didn’t try a multiple filters isotope gallery, so I don’t know the exact behavior of the view in that case, but this should be the only sort filter you would have for the View attachment.

To reduce duplicates results you have to go under “Advanced” tab of the view and enable aggregation by clicking on “Use aggregation” and flagging the checkbox. Go back to Fields section, near to the “COUNT (Content ID)” field, click on Aggregation settings and select “Count”. Do the same thing under the Sorting Criteria: select “Count” for the aggregation settings. Save the view.

We are close to our goal, but there is still something missing. To be sure that our libraries will be loaded in the view page we need to add them in the view template.
Let's create a views-view--my_istope-list.html.twig template. There are several ways to override a view template, well documented in the Drupal API documentation I mentioned before. Maybe the best way is to copy the core view file you need and that you may find in the core/modules/views/templates folder. If you're using the HTML list like in this tutorial, you will copy the views-view-list.html.twig file in your theme templates folder (/themes/contrib/my_theme/templates) and rename it with the name of the view, like views-view--my_istope-list.html.twig. At the beginning of the twig file add

{{ attach_library(‘my_theme/isotope’) }}
{{ attach_library(‘my_theme/start-isotope’) }}

So the complete template file will look like:

{#
/**
 * @file
 * Default theme implementation for a view template to display a list of rows.
 *
 * Available variables:
 * - attributes: HTML attributes for the container.
 * - rows: A list of rows for this list.
 *   - attributes: The row's HTML attributes.
 *   - content: The row's contents.
 * - title: The title of this group of rows. May be empty.
 * - list: @todo.
 *   - type: Starting tag will be either a ul or ol.
 *   - attributes: HTML attributes for the list element.
 *
 * @see template_preprocess_views_view_list()
 *
 * @ingroup themeable
 */
#}
{{ attach_library(‘my_theme/isotope’) }}
{{ attach_library(‘my_theme/start-isotope’) }}

{% if attributes -%}
  <div{{ attributes }}>
{% endif %}
  {% if title %}
    <h3>{{ title }}</h3>
  {% endif %}

  <{{ list.type }}{{ list.attributes }}>

    {% for row in rows %}
      <li{{ row.attributes }}>{{ row.content }}</li>
    {% endfor %}

  <{{ list.type }}>

{% if attributes -%}
</div>  
{% endif %}

Third Step: initialize the isotope library with custom javascript.

This part depends on your needs and there are several ways to achieve your goal. To remain in the purpose of this tutorial edit the start-isotope.js file we created before and put a code like this:

jQuery(document).ready(function($){
     var masonryContainer = $(".myIsotopeContainer"),
  filtersMasonry = $(".myIsotopeFilter .filter");
  filtersMasonry.prepend( "<li class=\"active\"><a class=\"button\" href=\"#\" data-filter=\"*\"> All </a></li>" );
    
    $(".myIsotopeContainer").isotope({
        itemSelector: '.isotope-item',
        layoutMode: 'fitRows',
    });
    
    $('ul.filter a').click(function(){
        
      $("ul.filter a").removeClass("active");
      $(this).addClass("active");

      var selector = $(this).attr('data-filter');
      $(".myIsotopeContainer").isotope({
             filter: selector,
             animationOptions: {
                 duration: 750,
                 easing: 'linear',
                 queue: false,
             }
        });
       return false;
    });
      });

 

Save.

Flush all caches in order to make drupal known of all theme’s changes and you’re done!

To view this demo in action, you can visit my portfolio page.

Please, feel free to comment and improve this guide if you want.

Commenti

Inviato da Timmy (non verificato) Dom, 01/07/2018 - 20:50

This part starting "Now add a View Attachment..." up to the twig template is very hazy. Could you make it clearer? There is no "Number" option for aggregation and the description if fields is unclear at this stage.

Inviato da alberto Lun, 02/07/2018 - 11:58

In risposta a di Timmy (non verificato)

Hi Timmy, and thank you for posting.

I'm sorry if it was unclear, English is not my native language, but I would like to share this solution since it would be useful to everyone.

I edited the part you mentioned, both on the "View attachment" part and the "twig template" part. I hope it's much clear now.

You are right about the "Number" option, It's the "Count" option, which is translated as "Numero" (means Number) in Italian. I worked on an italian installation of drupal, so it was my fault wrongly re-translating that option ;-)

Aggiungi un commento

Solo a uso interno: questo campo non verrà mostrato.

HTML ristretto

  • Elementi HTML permessi: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Linee e paragrafi vanno a capo automaticamente.
  • Indirizzi web ed indirizzi e-mail diventano automaticamente dei link.
Dichiaro di aver preso visione dellaPrivacy Policy del sito e acconsento alle finalità ivi espresse.