How to get current page in pages Symfony 5 without duplicate code? - symfony

I want get the current page and give an active class without duplicate code in symfony 5.
Here is the code example :
<li class="{{ app.request.get('_route_')=='home' ? 'active':''}}">
Home
</li>
<li class="{{ app.request.get('_route_')=='contact' ? 'active':''}}">
Contact
</li>
</ul>

As an extension of the answer of #DhiaDjobbi
I've you really want to reduce "duplicate" code, I'd go with defining the menu in an array as well
{% set active_page = app.request.get('_route') %}
{% for page in pages %}
<li {% if page == active_page %} class="active" {% endif %} >
{{ page }}
</li>
{% endfor %}

U can create a twig variable in Template its better readable.
{% set page = app.request.get('_route') %}
Then use If Condition to test.
<li {% if page == 'home' %} class="active" {% endif %} >
Home
</li>
<li {% if page == 'contact' %} class="active" {% endif %} >
Contact
</li>

Related

Find on which item route from the menu I am

I'm currently working on a Symfony 4.4 web application.
The menu can be changed by the administrators of my app, so there is a table with these properties :
Because I got routes with some parameters (eg: a slug or an id, and the slug can change so it's not a great identifier).
The problem is that I want to know on which menu item I am, to keep the menu opened (to add an active class on < li > items) but I can't find a way to do it properly.
What I tried :
Identify the route with something like that :
<li>{% if app.request.get('_route') == 'foo_products_overview' and app.request.get('slug') in ["entityslug"] %} class="active" {% endif %}></li>
But parameters are not the same for each route of my app (mutliple entites using id or slug to find one).
Here is the way my menu items are displayed :
{% if child2.getMenuItems()|length > 0 %}
<ul class="collapse nav-sub" aria-expanded="false">
{% for child3 in child2.getMenuItems() if child2.getMenuItems()|length > 0 and child3.level == 4 and (is_granted(child3.roles) or child3.roles is empty) %}
<li class="{% if child3.getMenuItems()|length > 0 %}nav-dropdown{% endif %}">
<a class="{% if child3.getMenuItems()|length > 0 %}has-arrow{% endif %}"
href="{% if child3.route is not null %}{% if child3.routeParameters %}{{ path(child3.route, {'id': child3.routeParameters}) }}{% else %}{{ path(child3.route) }}{% endif %}{% else %}#{% endif %}"
aria-expanded="false">
<span>{% if "ROLE_ADMIN" in child3.roles %}<i class="la la-eye-slash text-danger mr-2"></i>{% endif %}{{ child3.name|raw }}</span>
</a>
</li>
{% endfor %}
</ul>
{% endif %}
Have you ever had this problem?
Maybe there's a way with KnpMenu? (https://symfony.com/bundles/KnpMenuBundle/current/index.html) I'm not using it for the moment.
Did you try this : replace "child.id" by your variable name, i think that's "child3.id" but not sure.
class="{% if app.request.attributes.get( '_route' ) starts with 'foo_products_overview' and app.request.attributes.get('id') == child.id %}active{% endif%}"

How to interpolate a variable in a twig loop to render a file?

I am looping through a list of social profiles to render the logo. Each social item has a field of svg_icon_code that looks like "twitter" or "facebook". I want to use this code to render the correct file. Currently I am just hardcoding in "twitter" resulting in all logos being the Twitter svg. How can I use the icon_code to render the correct svg?
{% for item in options.social_media_links %}
<li class="header__social-media-links__item">
<a href="{{item.link}}" target="_blank">
{% include 'component/svg-twitter-icon.twig' %}
</a>
</li>
{% endfor %}
You need to concat the icon like this,
{% for item in options.social_media_links %}
<li class="header__social-media-links__item">
<a href="{{item.link}}" target="_blank">
{% include 'component/svg-'~item.svg_icon_code~'-icon.twig' %}
</a>
</li>
{% endfor %}
If an icon doesn't have a template or the template is missing you can do this to render a default icon
{% for item in options.social_media_links %}
<li class="header__social-media-links__item">
<a href="{{item.link}}" target="_blank">
{% include [ 'component/svg-'~item.svg_icon_code~'-icon.twig', 'component/svg-default-icon.twig' ] %}
</a>
</li>
{% endfor %}

Setting current category to active

When on a category page I'm hoping to add an "active" class the current pages relevant link to show which category is selected in the menu.
Currently I'm listing all post categories and linking to their relevant pages via
{% for cat in categories %}
<li><a style="margin: 0;" href="{{ cat.link }}" class="">{{cat.name}}</a></li>
{% endfor %}
I have tried using if statements but can't seem to get it right.
Managed to solve this by setting the current category to active like this:
{% for cat in categories %}
<li><a style="margin: 0;" href="{{ cat.link }}" class="menu-item {% if category|capitalize == cat.name %}active{% endif %}">{{cat.name}}</a></li>
{% endfor %}

Multiple post pagination on same page with Timber

I recently implemented a blog that takes content from two post types and displays them in a tabbed navigation. The problem I encounter is that I can't seem to be able to create pagination links for each post type without one overriding the other.
<div id="view1">
{% block content %} {% for post in posts %} {% include ['tease-'~post.post_type~'.twig', 'tease.twig'] %} {% endfor %} {% endblock %}
<div class="tool-pagination">
<ul class="pages">
<li>
{% if pagination.prev %}
Prev
{% endif %}
</li>
{% for page in pagination.pages %}
<li>
{% if page.link %}
{{page.title}}
{% else %}
<span class="{{page.class}}">{{page.title}}</span>
{% endif %}
</li>
{% endfor %}
<li>Next
</li>
</ul>
{% if pagination.next %} {% endif %}
</div>
</div>
<!-- Workbench Tab -->
<div id="view2">
{% block workbench %} {% for post in workbench %} {% include ['tease-'~post.post_type~'.twig', 'tease.twig'] %} {% endfor %} {% endblock %}
<div class="tool-pagination">
<ul class="pages">
<li>
{% if pagination.prev %}
Prev
{% endif %}
</li>
{% for page in pagination.pages %}
<li>
{% if page.link %}
{{page.title}}
{% else %}
<span class="{{page.class}}">{{page.title}}</span>
{% endif %}
</li>
{% endfor %}
<li>Next
</li>
</ul>
{% if pagination.next %} {% endif %}
</div>
</div>
My index.php file looks like this:
$context['pagination'] = Timber::get_pagination();
I tried following the instructions on the timber site pagination but all I've managed to do is choose which category is paginated not both
Thanks in advance!!
Ivan
Multiple pagination wasn't something I really anticipated for. But here's how I think it could work:
$context['posts'] = Timber::get_posts();
$context['posts_pagination'] = Timber::get_pagination();
$query = array('post_type' => 'workbench');
$context['workbench'] = Timber::get_posts($query);
query_posts($query); //this forces WP to rerun query stuff
$context['workbench_pagination'] = Timber::get_pagination();
This is not tested, but based on what you got, this is the closest stab I can take

Django CMS Multi-Level Dropdown Menu

Im kinda new to Django CMS and im trying my best to avoid asking, but this one drives me crazy.
I made a Wiki app with a Topic, and Category model. I hooked it to a Site on my CMS and added it to my Menu. Now i would like to be able to show all Top-Level categories, their Child Categories & Topics, and the Child categories of these, and so on, on my menu.
Menu/Navigation should look like this:
Wiki
Category1
Category1.1
Topic
Category1.2
Topic
Category2
Topic
Category3
...
Right now i can only show the Top categories:
Wiki
Category1
Category2
Category3
I Already created a menu.py to get a Custom SubMenu on my Wiki (the one you see above):
menu.py
class WikiSubMenu(CMSAttachMenu):
name = _("Wiki Sub-Menu")
def get_nodes(self, request):
nodes = []
categories = Category.objects.filter(parent_id__isnull=True)
for c in categories:
node = NavigationNode(
mark_safe(c.name),
c.get_absolute_url(),
c.id,
)
nodes.append(node)
return nodes
menu_pool.register_menu(WikiSubMenu)
My Category Model:
class Category(models.Model):
''' Category model. '''
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
parent = models.ForeignKey(
'self',
null=True,
blank=True,
related_name='children'
)
sort = models.IntegerField(default=0)
class Meta:
ordering = ['sort', 'name']
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('topics:categories_category_detail', (), {'slug': self.slug})
def get_all_children(self):
return Category.objects.filter(parent=self)
Now, is it possible to create a Sub-SubMenu, for all Categories with Childs, and their Childs, and their Childs, and so on?
Thanks for help & sorry for bad english
-- EDIT : --
I just found that:
docs.django-cms.org/en/3.0.6/extending_cms/app_integration.html#integration-modifiers
(Removed direct link to add 2 new Links, sorry for that)
I think that is what im looking for, i was kinda blind that i didn't found it. I'll try it out and Post the Answer if it worked out.
-- EDIT (AGAIN): --
The modifier didn't worked for me, but i got a whole piece further,
i read the Docs again, and found that i can give the NavigationNodes an optional attr dictonary, which i filled with all Categories with parent=c, on that way i had the data i needed, then i found that real nice bootstrap dropdown menu, that does exacly what i wanted. So my code until now looks like that:
menu.py
class TopicsSubMenu(CMSAttachMenu):
name = _("Wiki Sub-Menu")
def get_nodes(self, request):
nodes = []
categories = Category.objects.filter(parent_id__isnull=True)
for c in categories:
node = NavigationNode(
mark_safe(c.name),
c.get_absolute_url(),
c.pk,
attr=dict(
subcategories=Category.objects.filter(parent=c),),
)
nodes.append(node)
return nodes
And my Template:
menu.html
{% for child in children %}
<li>
{% if child.children %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ child.get_menu_title }}
<span class="caret">
</span>
</a>
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
{% for child in child.children %}
{% if child.attr.subcategories.count %}
<li class="dropdown-submenu">
<a tabindex="-1" href="#">{{ child.get_menu_title }}</a>
<ul class="dropdown-menu">
{% for subcategory in child.attr.subcategories %}
<li>
<a tabindex="-1" href="{{ subcategory.get_absolute_url }}">{{ subcategory }}</a>
</li>
{% endfor %}
</ul>
</li>
{% else %}
<li>{{ child.get_menu_title }}</li>
{% endif %}
{% endfor %}
</ul>
{% else %}
<a href="{{ child.get_absolute_url }}">
<span>
{{ child.get_menu_title }}
</span>
</a>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}
{% endif %}
{% endfor %}
My next step will be to write the whole "for" loops from the template in a Method, make it recursive with a while loop or something and post the result as Answer.
I hope i can help someone with that stuff :)
WOHO! I finally did it!
base.html
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
{% show_menu 0 100 100 100 "menu.html" %}
</ul>
</div>
menu.html:
{% for child in children %}
<li class="child{% if child.selected %} selected{% endif %}{% if child.ancestor %} ancestor{% endif %}{% if child.sibling %} sibling{% endif %}{% if child.descendant %} descendant{% endif %}{% if child.children %} dropdown{% endif %}">
<a {% if child.children %}class="dropdown-toggle" data-toggle="dropdown"{% endif %} href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">
<span>{{ child.get_menu_title }}</span>{% if child.children|length %}<span class="caret"></span>{% endif %}
</a>
{% if child.children %}
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
{% show_menu from_level to_level extra_inactive extra_active "dropdownmenu.html" "" "" child %}
</ul>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %}
and my dropdownmenu.html:
(The recursive stuff starts here)
{% load i18n menu_tags cache mptt_tags %}
{% for child in children %}
<li {% if child.children %}class="dropdown-submenu"{% else %} {% endif %}>
<a tabindex="-1" href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">{{ child.get_menu_title }}</a>
{% if child.children %}
<ul class="dropdown-menu">
{% show_menu from_level to_level extra_inactive extra_active "dropdownmenu.html" "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
and the most important, menu.py:
class TopicsSubMenu(CMSAttachMenu):
name = _("Wiki Sub-Menu")
def get_nodes(self, request):
nodes = []
categories = Category.objects.all()
for c in categories:
node = NavigationNode(
mark_safe(c.name),
c.get_absolute_url(),
c.pk
)
if c.parent:
node.parent_id = c.parent_id
nodes.append(node)
topics = Topic.objects.all().exclude(category__isnull=True)
for t in topics:
node = NavigationNode(
mark_safe(t.title),
t.get_absolute_url(),
t.pk,
t.category.all()[0].id,
parent_namespace="TopicsSubMenu"
)
nodes.append(node)
return nodes
menu_pool.register_menu(TopicsSubMenu)
And thats it!

Resources