Multiple post pagination on same page with Timber - wordpress

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

Related

How to change "if" condition related to a page

I would like to include tab_system.twig file in two differents files : archive.twig and blog_list.twig to have the same html in those two files.
{% include "tab_system.twig" %}
In this tab_system.twig file I have a condition to add the active class :
{% if XXX %}active{% endif %}
But this condition must be different depending on which page the user is.
For blog_list.twig :
{% if loop.first %}active{% endif %}
For archive.twig :
{% if item.term_id == term_page.term_id %}active{% endif %}
I wrote this without success :
{% set addclass = '' %}
{% if is_blog_list %}
{% set addclass = '{% if loop.first %}active{% endif %}' %}
{% elseif is_archive %}
{% set addclass = '{% if item.term_id == term_page.term_id %}active{% endif %}' %}
{% endif %}
In tab_system.twig I have a tab system with menu from a part and content to the other part. I wrote a js loop to display the corresponding content. I need to add active class on the first link and first content tab in blog_list.twig file and to add active class to the link and content tab depending on which category the user is.
<div class="tab-menu-list">
{% for item in all_posts %}
<a href="#" class="tab-menu {{ addclass }}"</a>
{% endfor %}
</div>
<div class="tab-content-list">
{% for item in all_posts %}
<div href="#" class="tab-content {{ addclass }}"</div>
{% endfor %}
</div>
is_archive and is_blog_list are variables defined elsewhere. They work
How can I create a condition ? Thank you in advance.
As I'm assuming you are looping the records, I'd say don't overcomplicate things,
single.twig
{% for i in 1..5 %}
{% include 'article.twig' with { 'active' : loop.first, } %}
{% endfor %}
template_blog.twig
{% for item in items %}
{% include 'article.twig' with { 'active' : item.term_id == term_page.term_id, } %}
{% endfor %}
article.twig
<div class="articles__list tab-content{{ active ? ' active'}}">
foo
</div>
demo - just change the main template
If you really wanted to keep that for inside the article template, which I think is not a great idea, you could still use the variables is_archive and is_blog_list inside article, e.g.
article.twig
{% for item in items %}
{% if is_archive %}
{% set active = loop.first %}
{% elseif is_blog_list %}
{% set active = item.term_id == term_page.term_id %}
{% endif %}
<div class="articles__list tab-content{{ active ? ' active'}}">
{% endfor %}

How to access peekAll() in base.html.twig to check for messages/flashes

In symfony 4.1
In the controler:
$this->addFlash(
'notice',
'Your changes were saved!'
);
return $this->render(...);
Twig base template:
{% for message in app.flashes('notice') %}
<div class="flash-notice">
{{ message }}
</div>
{% endfor %}
That works fine, but I want to wrap ALL messages in a div. The below does not work:
{% if app.flashes is not empty %}
<div id="messageBox" class="overlay">
<div class="message" onclick="slide(document.querySelector('#messageBox')); this.classList.add('fadeAway');">
{% for label, messages in app.flashes %}
<section class="{{ label }}">
<p><b>{{ label }}</b></p>
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</section>
{% endfor %}
</div>
</div>
{% endif %}
The problem is that the line {% if app.flashes is not empty %} erases the messages, so the following for loops and empty result.
How do I use peekAll() for the if logic?
The correct way to check with peekAll() is {% if app.session.flashbag.peekAll() is not empty %} This will not clear the flashBag as per documentation.
I do not know if this is the best way to do this, but the following is my solution.
In the base.html.twig:
{% set flashes = app.flashes %}
{% if flashes is not empty %}
<div id="messageBox" class="overlay">
<div class="message" onclick="slide(document.querySelector('#messageBox')); this.classList.add('fadeAway');">
{% for label, messages in flashes %}
<section class="{{ label }}">
<p><b>{{ label }}</b></p>
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</section>
{% endfor %}
</div>
</div>
{% endif %}
Basically, set the returned value of app.flashes to flashes and handle that.

Recursive parsing of hierarchical Twig layout with parents, children, grandchildren

In my SF2 project I have an entity (Category) which I am representing in a hierarchical format with a parent at the top, followed by children, grandchildren etc.
The Category entity has a getChildren method, which works and returns Category entity objects.
I'm trying to work out a way to make this layout more dynamic, rather than having to explicitly set children and grandchildren variables within the template.
Is there a better way to do this?
<ul class="sortable">
{% for cat in cats %}
{% set children = cat.getChildren %}
<li id="menuItem_{{ cat.id }}">
<div data-id="{{ cat.id }}">
<span>{{ cat.name }}</span>
</div>
{% for child in children %}
{% set grandchildren = child.getChildren %}
<ul>
<li id="menuItem_{{ child.id }}">
<div data-id="{{ child.id }}">
{{ child.name }}
</div>
{% for grandchild in grandchildren %}
<ul>
<li id="menuItem_{{ grandchild.id }}">
<div data-id="{{ grandchild.id }}">
{{ grandchild.name }}
</div>
</li>
</ul>
{% endfor %}
</li>
</ul>
{% endfor %}
</li>
{% endfor %}
</ul>
so what you are trying to achieve is recursive parsing of a tree in twig right?
If so, have a look at macros
.
{% import _self as macros %}
{% macro showChild(object) %}
{% import _self as macros %}
<ul>
{% for child in object.children %}
{{ macros.showChild(child) }}
{% endfor %}
<li id="menuItem_{{ object.id }}">
<div data-id="{{ object.id }}">
{{ object.name }}
</div>
</li>
</ul>
{% endmacro %}
<ul class="sortable">
{% for cat in cats %}
{{ macros.showChild(cat) }}
{% endfor %}
</ul>
that's all :)
let me know if you need help
EDIT 1:
If you want to use the macro in another file, remove the "import _self" line and just import it with an alias in another file:
index.html.twig:
{% import 'macro_file_name.html.twig' as macros %}
then you can use the same notation to call it

Is it possible to style posts in octopress according to its tags?

I need to style all the posts in Octopress which have the tag 'old' differently. Like, show only the title and no image in archives and keep them separated! How can I do this? (Note : There are nearly 1,500 posts with the old tag)
You could simply use the tags as css classes:
<ul>
{% for post in site.posts %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
That way you can style the link easily via css for any tag.
I'll assume you have a old class that differentiates the posts or that you can style a list of old posts with a old_posts class. You can create two separate lists:
<ul class="old_posts">
{% for post in site.tags.old %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
<ul class="new_posts">
{% for post in site.posts %}
{% unless post.tags contains 'old' %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
Or you can create one list with the old posts receiving a special class old:
<ul>
{% for post in site.posts %}
{% if post.tags contains 'old' %}
<li>{{ post.title }}</li>
{% else %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
Basically, site.posts, post.tags and site.tags.TAGNAME, together with Liquid's if-else, for and contains are able to do most of the tasks related to styling specifically tagged posts.

Is a Twig block empty? - Symfony 2

I have a twig template with the following block:
{% block dashboard %}
{% include "::user_dashboard.html.twig" %}
{% endblock dashboard %}
Later in that template, I want to set a class on a div based on whether or not there is anything in that block (i.e., by default, it will have the include above, but children of this template may override it and empty it out).
What I had (that somewhat worked) was ...
{% set _dashboard = block('dashboard') %}
{% set _mainWidth = ( _dashboard|trim is empty ? "no-dashboard" : "with-dashboard" ) #}
<div id="main" class="{{ _mainWidth }}">
The problem here is that whole dashboard block gets called twice. This wouldn't bother me too much except that block renders a few controller actions, i.e. ...
{% render "UserWidget:userAppMenu" %}
... and the code in that action is being called twice. For various reasons, not the least of which is performance, this messes with some of the stuff in that dashboard block.
So, my question is ... is there any way to tell if that block is empty without loading it twice? Is there something really simple I'm missing or is this even possible?
Thanks!
EDIT:
Here is my full template if it helps clarify things:
{% extends '::base.html.twig' %}
{% block layout %}
{% block header %}
{% include "::header.html.twig" %}
{% endblock header %}
<div id="container" class="row-fluid">
{% block dashboard %}
{% include "::user_dashboard.html.twig" %}
{% endblock dashboard %}
{% set _dashboard = block('dashboard') %}
{% set _mainWidth = ( _dashboard|trim is empty ? "no-dashboard" : "with-dashboard" ) %}
<div id="main" class="{{ _mainWidth }}">
<h1 class="page-title">{% block page_title %}{% endblock %}</h1>
{% block main_filters %}{% endblock %}
{% if app.session.flashbag.has('message') %}
<div class="alert alert-block alert-success">
<ul>
{% for flashMessage in app.session.flashbag.get('message') %}
<li>{{ flashMessage }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if app.session.flashbag.has('warning') %}
<div class="alert alert-block alert-success">
<ul>
{% for flashWarning in app.session.flashbag.get('warning') %}
<li>{{ flashWarning }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% block body %}{% endblock %}
{% block footer %}
{% include "::footer.html.twig" %}
{% endblock footer %}
</div>
</div>
{% endblock layout %}
Here you can see on lines 11 and 15 - both of those actually seem to include and process what is in that include.
What about this? This way the block should only be rendered once, when you call block('dashboard').
{# at top of twig #}
{% set _dashboard = block('dashboard') %}
{# where ever you include your block #}
<div>
{{ _dashboard|raw }}
</div>
{# and your main #}
{% set _mainWidth = ( _dashboard|trim is empty ? "no-dashboard" : "with-dashboard" ) #}
<div id="main" class="{{ _mainWidth }}">

Resources