On a recent project, I had to create a custom page which displays content by the logged in user, think of it as a “My articles” or “My blogs” page. I knew how to do it by writing code but I thought I’d try it with Views and see how far I could get without writing any custom code. Long story short, I was able to do it all by using just the Views module.
In this tutorial, you’ll learn how to create a page which will appear as a tab (local task) on the user profile page.
Getting Started
For once there are no extra modules to download and install. In Drupal 8, Views ships with core and will be automatically installed if you installed Drupal using the Standard installation profile.
If it’s not already installed, go to Extend and install Views and “Views UI”.
Create User Profile Page
The first bit of work we need to do is create an actual Views page.
This page will display a table of articles which is owned by the user, we’ll call it “My articles” and the URI to the page will be /user/%user/my-articles
the %user
argument will be the user ID which will be used by the contextual filter.
The owner of the content is defined by the user added to the “Authored by” field on the content edit page.
1. Go to Structure, Views and click on “Add view”.
2. Fill in the “Add view” form with the values defined in Table 1.0.
Table 1.0: Add view
Option | Value |
---|---|
View name | My Articles |
Machine name | my_articles |
Show | Content (default) |
Of Type | Article |
Create a page | Checked |
Page title | My Articles |
Path | user/%user/my-articles |
Display format | Table |
3. If you go to /user/%user/my-articles
replace %user
with any number, it should return a table of articles.
Create Contextual Filter
The %user
argument getting passed through the URI is not being used at this point. Let’s now add a contextual filter which will use the argument and only display articles which are authored by the user ID.
1. While on the Views edit page, click on Advanced then Add next to Contextual filters.
2. Search for “Authored by” in the Content category and click on Add.
3. Select the “Provide default value” radio button and choose “User Id from route context”
4. Further down the page:
- Check “Specify validation criteria”.
- Select “User ID” from Validator.
- Check “Validate user has access to the User”.
- Under “Access operation to check” select Edit.
5. Click on Apply to save the contextual filter, then click on Save to save the view.
Now if you go to the page, /user/%user/my-articles
make sure you change %user
with an actual user ID, you should only see their articles.
Page Access Control
Please make sure you’ve checked “Validate user has access to the User” and have chosen Edit under “Access operation to check”.
This means that only users who have edit access can access the page. This would be users accessing their own accounts or site administrators who can edit other user accounts.
If you do not then any user who knows the URI /user/%user/my-articles
could go directly to it and see which articles are owned by the user.
Display Page as Tab (Local Task)
At this point, we’ve created the page and added a contextual filter to only display articles owned by the user.
Now let’s create a menu for the page so it’s accessible via a tab on the user profile page.
1. While on the views edit page, click on “No menu” link in the “Page settings” section.
2. In the “Page: Menu item entry” window, complete the following:
- Select “Menu tab” from Type.
- Add “My articles” to “Menu link title”.
- Select “<User account menu>” from Parent. This is important if you don’t do this then the tab won’t appear.
- Add 5 to weight.
3. Now if you go to the “My articles” page it should go from this:
To this:
If you can’t see the tabs but have configured it properly then try rebuilding the site cache. Go to Configuration, Performance and click on “Clear all caches”.
Summary
The ability to create these types of pages is where Views really shines. Often a client will ask for a content specific page such as a “My blog” or “My articles” page and Views makes it very easy to create these types of pages.
FAQs
Q: “My Articles” tab is not appearing.
First, make sure you’ve chosen “<User account menu>” from the Parent drop-down. Second, try rebuilding the site cache (go to Configuration, Performance and click on “Clear all caches”) and see if that fixes it.
Rather than using Raw value from URL for the Contextual Filter it should be possible to use User ID from route context instead as that does require any additional configuration.
Hi Colin,
Yes you are correct and thanks for letting me know.
I mistakenly used
{user}
instead of%user
. If you use%user
then Views will automatically upcast it and pass a loaded user object which means you can use “User ID from route context”.I’ve updated the tutorial.
Cheers,
Ivan
Hello, how I can hide this tab for other users and display it only for the current user?
Hi Serhii,
If you want to remove/manage tabs look at using the hook_menu_local_tasks_alter (https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21menu.api.php/function/hook_menu_local_tasks_alter/8.4.x).
Cheers,
Ivan
Hello hello how are you?
Very good work.
I succeeded, on the other hand impossible to place a block on the page.
% user does not seem to fancy with the blocks.
Do you have an idea of the path to see the blocks on this page?
CORDIALLY
Hi Istang,
When you’re dealing with blocks, there is no “path”. The %user placeholder in the path is important because this tells Drupal to pass the user object into the view.
You’ll need to look at changing the “Contextual Filter”, but I’m not quite sure what needs to change, sorry.
Cheers,
Ivan
Hi Ivan,
I just want to put a block on the page.
How to do?
I only see blocks with no context filter;
Cheers,
If you want to add a block, go to the Block Layout page and assign it to a region.
I only see blocks with no context filter;
Sorry, I don’t understand what you mean.
Hi Ivan,
“If you want to add a block, go to the Block Layout page and assign it to a region.”
Okay. it’s here when I encounter the path problem.
When I use user /% user / xxx … the block does not appear on the page.
I tried all kinds of combinations with user /% user /. Nothing worked …
Cheers,
Hello Ivan, Excellent tutorial thank you.
ISTANG you can solve your contextual block problem by using a different contextual filter for your block on this page. If you used the path exactely as in Ivans tutorial. Add User ID as contextual filter to your block > provide default value > raw value from URL > 2. User ID from routing context does not seem to work.
Wowww why I always ended up finding your articles Ivan 🙂
Nice tutorial, I just realized now, apparently we do not really need some twig code for adding menu tab on user profile, and it’s only using with views!!
Well just like another solutions I got from you as before, Thanks again for saved my time and work.. Keep it up buddy!
Hello Ivan,
I was wondering if you know of a similar way, using views, to create sub-tabs on the user profile page? So far i have been unsuccessful. And thank you for your work.
Michael
Having a bit of a problem here. When I add the “menu” option to “menu tab” and select it’s not showing in the tabs within my account. When I add it to “Normal menu entry” and choose it’s showing my “my account/log out” – why isn’t it showing in the my account menu tabs?
Hi GC,
Make sure you select the correct menu type and parent, https://www.webwash.net/custom-tab-user-profile-page-views-drupal-8/#display-page-as-tab-local-task
Why it’s not working, I couldn’t tell you.
Cheers,
Ivan
Another great tutorial, thank you!
I do have one quick question:
How do I go about hiding the tab menu item from other users?
I currently have permissions set to allow people to view other users profiles, so that they can view their membership history, some personal info, and use the personal contact form.
Having followed your instructions above, the tab menu link of the newly created view is visible to everybody on user profiles, but throws a page not found error when they click on it.
The desired solution would be for the tab menu link to only be visible to the person whose profile it is.
Is this possible? Thanks
Hi David,
Good question. You could do it with custom code.
You could define custom permission in a module, then write an access service.
Something like this:
https://www.drupal.org/docs/8/api/routing-system/access-checking-on-routes/custom-route-access-checking
What I don’t know is how to integrate it with the View route.
Cheers,
Ivan