About this talk
This talk, presented by Amani Mansour, focuses on utilizing the Views module in Drupal to create dynamic content listings. With over ten years of experience in Drupal, the speaker highlights how Views enables site builders to generate customizable lists of various entities, such as nodes, media, and users, without code. The session explains the process of setting up Views, including configuring filters, sorting, and displaying content as pages or blocks. Amani demonstrates how to implement features like exposed filters for user interactivity and contextual filters for dynamically changing content. By leveraging Views, users can enhance content discoverability and improve user engagement on their Drupal sites.
Full transcript
Uh thank you all for coming to my session. Uh no code queries dynamic content with views. I'll be going over how we can use the views module to build dynamic lists of content on our Drupal sites. My name is Amani Mansour. I'm a technical architect at Debug Academy. I've been working in Drupal for a little over 10 years now. So through that time, I've learned there's a
lot you can do with Drupal out of the box. So by just being an experienced site builder, you can build dynamic and flexible sites using Drupal. And understanding and learning the views module is important to being able to do just that. So what are views? Views is a module that allows us to create dynamic lists of content typically used to list our entities like our nodes, media,
users, taxonomy terms. And these lists can be filterable, searchable, and sortable. So when you create a view, you're essentially specifying a set criteria that determines what content gets included in your listing. And this is a dynamic list because even as you create new content, if it meets that specified criteria, it'll automatically get added to your listing. So why should we learn views? because it allows us to
reuse and display our existing content in meaningful ways across our site. So if you for example have a blog website and have a lot of blog posts, in order for your end user to be aware of that content and engage with it, it would be useful to have a page that lists all of your blog posts. And with the views module, you can easily set that up.
You can also make it a filterable list so that the user can filter uh based off of author or topic. Another example would be if a user clicks on a specific blog post and they're taken to its page, you can have a small listing in the sidebar region that is a related blog post section. So you provide a short list of blog posts that they may be
interested in and that uh relationship could be based off of uh the related blog posts being written by the same author as the current blog post they're reading or that share a same topic as the current blog post they're reading. So in that sense you're creating a dynamic list based off of a relevant context. Uh, and so the reason the views module is very powerful and useful
is you're able to do all of this using the user interface. So you're essentially querying your site data and choosing how you want to display your content all through the user interface. You do not have to write custom code. So this is an example of a view. It's a list of press briefings. You can see that it shows the press briefing title and the date. And like
I mentioned before, your list can be sortable. So if we pay attention to the dates, you can see it's sorted to show the most recent press briefings first. Uh this is a list of nonprofit logos. So we built a site for a Syrian humanitarian organization uh that is a coalition of multiple nonprofit organizations. and they wanted to show all of the nonprofits that are part of their
coalition by having a list uh of nonprofit logos that are part of their coalition. So, we use the views module to build that. And then this is a view taken from Debug Academyy's website. Uh Debug Academy offers training courses. So, this is a view on our courses page that lists all of our course offerings. So with the views module, you're creating a list of dynamic a dynam
dynamic list of content based off of what all content that exists on your site. Your view does not create content itself. You can create your view as a page or a block, but the contents of that page or block come from uh content already existing on your site. So this is an example of a view as a page. So in your view, you can select uh to
have a page display and you'll be given a URL, an optional menu link. So when users access the URL, they're taken to your listing. So this is an example of an events page. Uh this is an example of a view block. And a view block is helpful if you want to display your view on many pages throughout your site. So in my earlier example, if you have
a related blog post section in the sidebar region for your blog post pages, you would create that as a block because you want it to display on all of your blog post pages, not just one. This is the views configuration form. Um, so it may look overwhelming, but honestly half the battle is just knowing what your options are. And we'll go through it step by step. So
first you can select the format of your listing. So you can choose an unforatted list which would be an unordered list or an ordered an HTML list which would be an ordered list. You could do grid or responsive grid. So there you can select how many columns you want. So you could do a three column layout or a two column layout. Uh or you can choose to
uh do a table format. Next is your field section. So this allows you to choose which of the entities fields you want to display. So if you're creating a list of uh nodes, you would have access to the field data from your nodes. If you're doing a list of media entities, then you would have access to all the fields from your media entities. So, if you're creating
um a blog post listing, you can add title uh the title field, an image field, a short description field, and maybe the author. So, you can choose like a subset of fields that you want to display in your And then the next section is your filters. So, your filters allow you to specify the criteria for what content you want to include in your listing. So for example,
you can add published and set it equal to true so that you only display published content in your listing. You can add content type as a filter and set it equal to blog so you're creating a list of published blog You can also have exposed filters. Uh so exposed filters allow your end user to filter your listing. So, um you know, you can have a recipe website
and have a listing um that shows all of the recipes that are on your website and then you can add an expose filter so the end user can filter that listing um based off of a field like a difficulty level field. So, they can filter to see which recipes are easy, which ones are medium. So, you can add any field uh from your entity as an exposed
filter. So, this is what it would an example of what it could look like if you add exposed filters to your view. It's a way to let the end user interact with your listing and filter it. To set up an exposed filter, you would go to the filter section of your view and you would click add and select the field that you want to filter by. Um,
and then you would check the checkbox expose this filter to visitors to allow them to change it. And that at a minimum is what you would need to do. The default settings uh for the exposed filter uh are very intuitive and I would say like at least 90% of the time you would keep it as such. The only thing I would change is for the label I
would remove the machine name and just have it say difficulty. Um but just so you're aware of the options. So for filter type you can choose uh for it to be single which is a single filter type means you choose one value to filter by. A grouped filter allows a choice between predefined operator and value pairs. So the best way to explain that is through an example.
Um, if you have a blog travel and every time you create a blog post, you have a country field on there. So, you can categorize your blog post based off of what country they're about. Uh, and then you create a view uh to list all the blog posts on your site and you add country as an exposed filter so that when a user filters by Japan, they
see blog posts that are about Japan. Um, if they filter by France, they'll see blog posts that are about France. Now, the more that you travel, the more countries uh that will be in that exposed filter. So, if you've been to a 100 countries, it may get difficult for the end user to search through the filter options. So, you think to yourself, oh, I wish I can
have an exposed filter where they get to filter by geographic area. So, if they filter by Asia, they'll see blog posts that are about Japan, Vietnam, Thailand, and so on and so forth. Now the issue is on your blog entity you only have the country field. You don't have anything that's storing the geographic area of each of your blog posts. So a way to a workaround. So
if you added the geographic area field to track it, you would have to go edit all of your blog post to give it a value which could be very time consuming. So a workaround for that would be add country as the exposed filter but make it a grouped filter type so that you can predefine the operator and value pairs. So you can make the operator Asia and
the value pairs Japan, Vietnam, Thailand and so on and so forth. You can have an operator uh be Europe and the value pairs be France, Italy, Ireland and so on and so forth. And then when a user is using that exposed filter to filter by geographic area, they're shown the blog posts that match where the country matches that geographic area. So that's an example of when a
grouped filter type can be useful in terms of your operator. So your operator is how the filter decides what data to render based on the value chosen. If you're creating an exposed filter, is one of is the most intuitive operator. Uh and that is the default setting. It's basically like the value is is one of that. So if you have a recipe website uh and a user
filters by easy, they're shown recipes that are easy. If they're shown uh if they select medium, they're showing shown recipes uh where the difficulty level is medium. Is none of would mean is none of that value. So, if they filter by easy, they're not shown any of the easy recipes. Instead, they're shown the medium and hard recipes. Uh, again, that wouldn't really be intuitive for an exposed
filter. These other operators are more useful for you uh if you're the admin or content editor um to see to be able to see the type of content you have on your website. So, for example, is empty would mean the difficulty level field is empty. So if you wanted to create a list of recipes and see all the ones that have an empty value for that field,
so you can say, "Oh, I need to go and edit these and give them a value." Then that's an easy way to figure that Okay. So with your views, you have um options in terms of permissions. So you can uh determine who has access to view your listing. By default, the permission is set to view published content. So that means uh any user including your logged out
anonymous users can view your You can make the permission stricter. You can also instead of basing it off of permission, base it off user role and determine what user roles roles have access to your listing. Uh the header and footer allow you to add markup or text above or below your view. And then the no results behavior is what happens when there are no results in your
listing. So if you have a a listing that includes exposed filters and the end user is filtering by certain values and it leads to no results being available that lets you determine what happens in that case. So usually in that um section you can add some text that says sorry there are no results for your search. Uh and then you have a pager section to determine how
many items you want to list per page. So you can include a full pager or mini pager to say um you know put 10 items per page or you can just specify the number of items in the view. So you could say I only want to display three items and that's useful if you're doing like a related blog post section that needs to be really short in
the sidebar region. You can limit it to three items. Um, so now we're in that third column with the more advanced section of your view. A contextual filter allows you to filter the results of your view based off of a dynamic changing value. So before when we talked about filters, those were static values. So content type equals article or content type equals blog, that's a filter value
that's not going to change. It's going to stay the same. Published equals true, that's a static value. a contextual filter. You're filtering your view results based off of a dynamic changing value that usually comes from the surrounding context of the page or user session. Uh, and I'll go through an example of this after the presentation. Your relationships allow you to pull in related data from another entity.
So, if you're creating a list of blog posts and let's say your blog content type has an entity reference field to another entity and you want to access that other entity's field data, you would have to create a relationship between your view and that other entity to have access to its field data. Uh, your exposed form allows you to configure your form information and elements. So, it
provides some options for if you have exposed filters, how you want it to display. Uh, an example would be if you want to include a reset button. So, if you have a lot of exposed filters on your view, it's useful for the end user to have a reset button to reset them all at once. Ajax allows you to reload content without a full page refresh. So, with
a full page refresh, the user will be taken back to the top of the page, which can be annoying. Um, if you don't want that to happen, you would turn on Ajax. And this is helpful when you have an exposed filter or you're including a pager in your view. The aggregation settings allow you to group view results together based off of a common shared value. And then
your query settings. Um, most notably is the display only distinct items to help remove any duplicate results. I will say early on in my Drupal career, I did use this setting. Um, I wouldn't say very often, but it did come in handy. I think the views module has just improved so much over the years that I I have not had to touch that setting in a really
long time. And then you do um have caching options like the default is tag based caching but you can change it to timebased caching. Uh again this is a setting I don't play around with. Um you know Drupal has improved so much in terms of caching. I would just leave the default setting unless you run into issues. And then you can add a CSS class if you
want to you know target this view for styling purposes. And then lastly, the hide block if the view output is empty. So this allows you to hide the entirety of your view block if there are no results. Uh so this is helpful if you do have an exposed filter or you have header or footer text above or below your view. If for some reason you haven't created
content that is getting included in your listing, you can just hide the entire view um the the entire view block so that because if you didn't then you would see the header text which would look awkward to the end user. Um okay so that has taken us uh to pretty much the end of the presentation. There's just a couple more slides, but I think the best way
to understand views is by looking at some of the views on an actual website. So, I did install uh Drupal using the Umami installation profile, which is a recipe website. If we click on the recipes page and scroll down a little bit, you'll see a list of recipes. And this is created using views. If I click here, I can edit the view. I do want to show
you that if you go to structure and we click on views here, you'll see all the views that are on your website. So you can also access your views from here. And you can add a view using this button. But let's go back to the recipes view. So we can see that the format is a responsive grid. And if we click the settings here, it's set to
have a num number of columns of four. The minimum grid cell width is 240 pixels. The spacing between uh the grid cells is 14 pixels and the alignment is horizontal. And if we look here, we do see a four Um, in terms of our filter criteria, we have published equals yes. So, we'll only show published content. The content type is equal to recipe. So, it will only
show us uh published recipes. And you can actually see here all of the filters have a checkbox to give you the option to expose it so that it could be an exposed filter. Um and then there is an additional filter criteria of default translation. Um this is just because this uh the Umami profile has both English and Spanish. So it's going to give you the results that
match the default translate translation. So we're looking at the website in English. It's going to show you the recipes that are in English. In terms of our sort criteria, uh we are sorting it so that it uh based off of date and time that the content was created and it's sorted in descending order. So, it's going to show us the most recent content first and the granularity
is by the second. Uh the second sort criteria serves as a tiebreaker. So I doubt that two recipes would be created at the exact same time given that the granularity is by the second. But just in case if it were, the tiebreaker is content ID sorted in ascending order. So that just means ID1 comes before ID2. And we can see here that our display is a page.
So this list, this view is created as a page. We have a path recipes. There is a menu link to we created a menu link, a recipes menu link with the parent menu being the main navigation. So if we scroll up here, you do see our recipes menu link for the access. It's permission view publish content. So again, that makes sense because we do want anonymous users
visiting our site to see all the recipes on our site and be able to interact with the content. Uh we have a mini pager which is set to display 12 items per page. Um so definitely if you expect to have a lot of results in your view, it's good to enable a pager for performance reasons. You don't want hundreds of items to be trying to render them
on the page. But if you notice here, we actually don't see a pager. And the reason is we only have here's four, eight, 10 items. So your pager only gets enabled once it surpasses the number of items per page. So once you have 13 recipes on your website, then you'll see that pager because we have it set to display 12 And then in the advanced section of
our view, um it's actually has the default settings. So there's nothing really to to look at here. Um but what we can do is we can add an additional filter criteria. We can add an exposed filter. So you know even in the presentation you saw this difficulty level field. So we can add it and expose it to uh so it's Like I said, I would remove the
field and I would keep the operator as one of. We'll apply it and save the view. And now we have an exposed filter. So you can pair um you uh you can pair this with the better exposed filters module. It's a contrib module. Uh and that'll give you more options to customize your filters. So if I >> part of core now though >> Oh, okay. Yeah, it
is part of core. So that's great. That means it's even more of a site builder tool because you don't have to use anything to download it. Thank you for that. That shows how old how many years I've spent [laughter] in the Drupal community. So I filtered by easy and so we see the easy recipes. Um, but if you notice when I used it, it took me to
the top of the page. That's really annoying. So, I want to go back to the view. Sometimes it's hard to like to use this to get the edit view. So, I'm actually just going to go back to the um Okay. So, in order to fix that problem, I had mentioned turning Ajax on so that we can reload our content without a full page refresh. So, I've turned
on Ajax. I'm going to click save. I'm going to go back to the recipes page. So, now let's filter by easy. And so, now it doesn't take me to the top of the page. So, again, this is like super easy to implement. like the views module has so much that you can do out of the box that used to require custom code. Um, and now once you're
aware of the options, you realize you're just clicking a few buttons and improving the user experience significantly. Um, okay. So, the next thing actually I think I want Let's go. I'm going to add the reset button uh because I wanted to get rid of the filter value, which I guess in hindsight it would just make me go to any. But um did I save this? Yeah. But
I felt that was easier. So now we go back to our full listing. Uh, if I click on a recipe, you see we're taken to the full recipe page. Um, and if I scroll down, we do have a related recipes block. go to the view, um, this is very similar to the view we were looking at, except it's a block because it's going to display on all
recipe pages. Uh but in terms of the you know format and the filter criteria, it does have all of the same options. Even the sort criteria is the same. It just doesn't have the tiebreaker. Um one thing I do want to mention, and this also existed in the first view we were looking at, instead of fields, we're actually uh setting it to show content view mode. So
in your view you have the option to either display fields or the content view mode. Uh and you can select which view mode you want to display. So in this case it's displaying the card. So in Drupal for your entities you have display mode options and these allow you to create different presentation formats of your content. So in your view mode, you can select which fields you
want to display. Um, and it's useful because if that view mode is already styled and themed properly, then in your view, you can just reuse the view mode instead of um picking and choosing what fields you want to display. And I can quickly show you uh what that looks like. So if we go content types and for your recipe content type, we would go to manage display.
You could see it has multiple uh view modes and this is the card one which is being used by uh the view. So it's showing two fields the difficulty field and the image field. The title of your ent entity will will display automatically. So it's not a field listed here like all the other fields are disabled. Title just shows by default. So it's not something you have
to enable here. So instead of uh picking and choosing what fields you have the option to select a view mode instead. Um so one difference in this view is that instead of including a pager it's just specifying the number of items to be four items. So here uh you have you're displaying published recipes. You're sorting it to show the most recent recipes first and then you're going
to limit it to four items. So even if you have fight five items that could be in your related blog post list, it'll limit it to the four most recent. And I meant to say related recipes listing. It'll limit it to the four four most recent ones. Now the reason I want to go over this view is because it's actually doing some interesting stuff in your advanced
section. So it has two contextual filters. The first filter is um the and it's saying provide the default value which would be content ID from URL. And if we scroll down here it says exclude. So if we go back to our view um you see this related recipes listing and our contextual filter is a filter that is filtering our results based off of a dynamic value that
can change. And so in that contextual filter, it's saying get the content ID from the URL. So whatever, so get the ID from the current page you're on. And even though you don't see an ID in this URL, Drupal can track it automatically. So every entity has an ID. So this is has an ID of uh 10. So, it's saying get that ID and exclude it from
your listing because you don't want the current page the user is looking at to be in your related recipe section. It doesn't make sense. If I were to click on this recipe and I'm going to click edit so we see what the ID is. It's ID 7. It has a content ID of seven. So, get that ID and exclude it from this listing. So, the curry recipe
is not in this, but now the ribs recipe is. Whereas, if we went on the wait, where where did my other recipe go? But if we went on the ribs page, uh the curry recipe is in it, but the ribs recipe is not. So, whatever page you're on, so we're taking a surrounding context of the page. It's the ID from the current page, and we're saying exclude
it. So depending on the page you're on, that ID value is going to change. On this page, it's ID 10 that we're excluding, but on the Curry page, it was ID7 that we're changing. So that's what I mean by a filter that can be a dynamic changing value. Sorry, I I have too many tabs. I just have to keep going back. Um, there is a second contextual
filter. So, what we know from the first one is how we're excluding the current recipe from being included in the related recipe section. But what we still don't know is how are what is that relationship? like why are these the related recipes to the current recipe? So this comes from this second contextual filter which is it's adding a field uh from the recipe content type as a
contextual filter. So it's adding recipe category as a contextual filter and the default value is get the taxonomy term ID from uh load the default filter from node page which is good for related taxonomy taxonomy taxonomy blocks and then filter to items that share all terms. So, what this is saying is get the value of the recipe category from the recipe we're currently on and then in
our related recipes block show other recipes that share that same value. Um, so if we go to this recipe, we see that the recipe category is main courses and the recipe category is an entity reference field to the taxonomy vocabulary recipe category. So main courses is a taxonomy term. So if we click on main courses, so it's saying get the value of recipe category from the recipe
we're currently on. So the value for us is main courses which is the taxonomy term. If I click edit, you'll see the taxonomy term ID which is 31. So Drupal can track like it knows we're ref referencing another entity and it can grab the ID from its URL. So it's saying get this taxonomy term ID and only show us value. So, if I click I'm going to
open all of these. So, if we go to Thai green curry, it has a recipe category of main courses. If we go to the pizza recipe main courses, pasta bake main courses. So, that's how we're creating we're creating a listing that is related by a taxonomy And if we go to the recipes page, uh let me click on this one. So this has a recipe category of
dessert. It has one other recipe that in the related recipe section that also has a recipe category of dessert. So if I open up dessert, you can see that now the contextual filter is 30. Um I don't remember what it was before, but the point is is it was a different number. I'm going to click on this one to see. So this starter, this has a recipe
category of start starter. And I just wanted to show you like it doesn't have a related recipes at the bottom. And if go to our view, if I could find the yeah, I think this is it. It's actually using the set setting hide block if the view output is empty. So, if we didn't have that turned on, then the related recipes title would show, but we would
have no results. So, that's an example of where it could be useful. Okay. So, let's go back to this recipe. Um, one thing I did want to show is, so I can tell this page is using layout builder because it has a layout tab here. Uh, so I'm going to click on it. When you click on the layout tab from a specific content item, you're only editing
the template for that specific item. You're not editing the template for all recipes. I'm not making edits. I just want to show you that how the view is being added to the page. So, it is added via layout builder. So, you could see it here. And if I click add block and scroll down, there is a view se a list view section. So, you can see um
all the views we have available. And here's the related recipes. So, you would just click on it and add it to the layout builder. So it's very easy to add your block. Another way to add your view block to your page is to go to structure block layout. So with layout builder that controls the content region of your page, but block layout controls all the regions of
your web page. So here you do have a content region, but you also have the sidebar region. So if you wanted to add a view to the sidebar region, you could. And actually, this does have a view um that's added to the sidebar region. You can tell it's a view because it's categorized as list views. So, it's an articles aside. So, let's go to this articles. Uh
so, this is a list of all articles. And if we click on an individual article, you can see that uh we have a short listing in the I just want to quickly go to back to the block layout. So if I click configure, you can restrict your blocks through block layout to display only on the pages you want. So here it's being restricted to only display on
article pages. Uh if you wanted to specify a particular set of pages, you could put in you can enter a path per line. Okay. So I am ready for for questions if anybody has any. Yes. >> I was curious if you had a specific reason other than this presentation to put your um the That was your recipe. Uh, you had a recipes view, but then you had
a separate view for the block. >> Yeah. >> Why did you not put that block display in the main recipes? You can have multiple. >> Yeah, that's a good question. So, I'm just going to repeat it for the recording. So, the question was, uh, why didn't I reuse the recipes block on the main recipe listing page, right? >> In the recipes view, you can have more than
one display. >> Oh, yeah. In the recipes view, you can >> You created a completely new view for >> I did not create a completely new view. That came from Drupal. >> No, I'm just I'm just being funny. I basically like uh Drupal provides the umami installation profile to give you an example website. So you can definitely add another display and make it a block display. So
you can have a page and a block display in the same >> Uh and that that definitely works >> to group your like we should suggest it and contribute back >> to the thing. Um yes. >> Yeah. So on my site, the original developers, they opted to use React app with GraphQL instead of a view. I mean besides asking them directly, which I could do that, but
why [clears throat] would you why would they do that? Why would they use React appl? >> Why would they use a React app with GraphQL instead of a view? >> So I guess with GraphQL, that's how they're pulling the data. And are you asking why they wouldn't use views to provide that data? So that would be your your back end. >> I mean >> your best >>
my best guess. >> Personal preference. >> Yeah. I think [laughter] yeah personal personal preference. Um so one other thing that I do just want to go to the presentation for. Um, everything that I've talked about applies to both Drupal core and Drupal CMS. So, they both have the views module. Uh, it's very useful to use. Uh, I do want to say if anything that I mentioned uh,
didn't make sense like entity types, fields, uh, display modes. Last year, I did a talk on mastering Drupal site building features that covered all of that. So, I think that would be helpful. It does touch on the views module, but this was more of a deep dive focused talk solely on the views module. Um, but if you want, you can go back to that talk just to
help you understand the structured data behind Drupal because that's why the views module can exist and be so powerful in Drupal. Um, and then I do want to mention that if you do want to spin up your own Drupal site and be able to fully build a Drupal site as a site builder, you can use uh, Dupedo. Uh, so Dupedo was launched by the founder of Debug
Academy. You can spin up a Drupal CMS site with the click of a button. It provides managed hosting that's very costfriendly, but we also launched a marketplace. So you can start your site from a like a dripyard theme or a Drupal association starter. Um people are welcome to create their own starters and list it in the marketplace. Uh and one of the cool features is it does
help you with environments. It makes it super easy. You have your live site. You can create your own prototype, test out content changes and configuration changes. So, if you want to build a view and you don't want to do it on the live site, you could do it in the prototype and then once it's ready, you can just promote it to your live site. Um, so like
I spun up a site and I created a prototype, you would just click the button and whenever I'm happy with the prototype and want to replace the live site with the prototype, you would first promote to next, which would take you to staging and then you would Thank you guys. Oh, there also [applause] sorry, there is a thank you. It does have a QR code. They asked
us to put these QR codes so that if you want to give feedback, you definitely can. I definitely welcome good feedback. No, I'm just kidding. [laughter]