0
votes

I have the following WordPress query code working in my Timber theme, but am struggling with how to convert into the Timber/Twig format.

$args = array(
  'taxonomy' => 'category',
  'parent' => '7',
  'orderby' => 'name',
  'order' => 'ASC',
  'hide_empty' => false,
);
$terms = get_terms( $args );

foreach ( $terms as $term ) {
  $termId = $term->term_id;

  // Output first level of children of parent category ID 7
  echo '<p>' . $term->name . '</p>';

  $args = array(
    'taxonomy' => 'category',
    'child_of' => $termId,
    'orderby' => 'name',
    'order' => 'ASC',
    'hide_empty' => false,
  );
  $childTerms = get_terms( $args );

  foreach ( $childTerms as $childTerm ) {
    $childTermId = $childTerm->term_id;

    // Output second level of children of parent category ID 7
    echo '<p>' . $childTerm->name . '</p>';

    $args = array(
      'cat' => $childTermId,
      'orderby' => 'title',
      'order' => 'ASC',
      'posts_per_page' => -1,
    );

    $query = new WP_Query( $args );
    while( $query->have_posts() ) : $query->the_post();
      // Output posts assigned to second level children categories
      echo '<p><a href="' . get_the_permalink() . '">' . get_the_title() . '</a></p>';
    endwhile;
    wp_reset_postdata();

    // $posts = Timber::get_posts( $args );
  }
}

Example Timber/Twig code with incomplete functionality

{% for term in terms %}
<div class="category">
  <h3>
    {{ term.name }}
  </h3>
  {% for childTerm in terms %}
    {% if childTerm.parent == term.term_id %}
    <div class="category__child">
      <h4>{{ childTerm.name }}</h4>
      <!-- Output posts from child terms here -->
    </div>
    {% endif %}
  {% endfor %}
</div>
{% endfor %}

HTML nested output example

Parent Category

  • Child Category
    • Post Title and excerpt
    • Post Title and excerpt
    • Post Title and excerpt
  • Child Category
    • Post Title and excerpt
    • Post Title and excerpt
    • Post Title and excerpt

Parent Category

  • Child Category
    • Post Title and excerpt
    • Post Title and excerpt
    • Post Title and excerpt

Parent Category

  • Child Category
    • Post Title and excerpt
    • Post Title and excerpt
    • Post Title and excerpt

Any assistance is greatly appreciated.

2

2 Answers

1
votes

First you have to alter the data your are sending to the view. Group the children with the parents and groups the posts with the corresponding child. This could be achieved with something like this:

<?php
    $data = [];

    $terms = get_terms([
        'taxonomy' => 'category',
        'parent' => '7',
        'orderby' => 'name',
        'order' => 'ASC',
        'hide_empty' => false,
    ]);

    foreach ($terms as $term) {
        /**
        *  Assign parent term to array and initiate children array
        *  Use term id so you can match the children easier with their parent
        **/
        $data[$term->term_id] = [
            'name'      => $term->name,
            'children'  => [],
        ];

        $childTerms = get_terms([
            'taxonomy' => 'category',
            'child_of' => $term->term_id,
            'orderby' => 'name',
            'order' => 'ASC',
            'hide_empty' => false,
        ]);

        foreach ($childTerms as $childTerm) {
            /**
            *  Assign child term to parent inside array and initiate post array
            *  Use child term id so you can match the post easier with the correct child
            **/
            $data[$term->term_id]['children'][$childTerm->term_id] = [
                'name' => $childTerm->name,
                'posts' => [],
            ];

            $query = new WP_Query([
                'cat' => $childTerm->term_id,
                'orderby' => 'title',
                'order' => 'ASC',
                'posts_per_page' => -1,
            ]);

            while($query->have_posts()) {
                $query->the_post();
                $data[$term->term_id]['children'][$childTerm->term_id]['posts'][] = [
                    'url'   => get_the_permalink(),
                    'title' => get_the_title(),
                ];
            }
            wp_reset_postdata();
        }
    }

This will create a nested array which will be easier to use inside twig, e.g.

<ul>
{% for parent in data %}
    <li>
        {{ parent.name }}
        {% if parent.children|default %}
            <ul>
            {% for child in parent.children %}
                <li>
                    {{ child.name }}
                    {% if child.posts|default %}
                    <ul>
                    {% for post in child.posts %}
                        <li><a href="{{ post.url }}" title="{{ post.title }}">{{ post.title }}</a></li>
                    {% endfor %}
                    </ul>
                    {% endif %}
                </li>
            {% endfor %}
            </ul>
        {% endfor %}
    </li>
{% endfor %}
</ul>

demo


note: didn't test the wordpress part as I don't use wordpress

0
votes

Here is my working PHP and Twig code with the helpful solutions provided by @DarkBee. I hope this is helpful to anyone working with Timber for WordPress.

Page Stories PHP

$context = Timber::context();
$timber_post = new Timber\Post();

$data = [];

$terms = get_terms([
  'taxonomy' => 'category',
  'parent' => '7',
  'orderby' => 'name',
  'order' => 'ASC',
  'hide_empty' => false,
]);

foreach ( $terms as $term ) {  
  /**
   *  Assign parent term to array and initiate children array
   *  Use term id so you can match the children easier with their parent
   **/
  $data[$term->term_id] = [
    'name' => $term->name,
    'slug' => $term->slug,
    'children' => [],
  ];

  $childTerms = get_terms([
    'taxonomy' => 'category',
    'child_of' => $term->term_id,
    'orderby' => 'name',
    'order' => 'ASC',
    'hide_empty' => false,
  ]);

  foreach ( $childTerms as $childTerm ) {    
    /**
     *  Assign child term to parent inside array and initiate post array
     *  Use child term id so you can match the post easier with the correct child
     **/
    $data[$term->term_id]['children'][$childTerm->term_id] = [
      'name' => $childTerm->name,
      'posts' => [],
    ];

    $query = new WP_Query([
      'cat' => $childTerm->term_id,
      'orderby' => 'title',
      'order' => 'ASC',
      'posts_per_page' => -1,
    ]);

    while($query->have_posts()) {
      $query->the_post();
      $data[$term->term_id]['children'][$childTerm->term_id]['posts'][] = [
        'url' => get_the_permalink(),
        'title' => get_the_title(),
        'date' => get_the_date(),
      ];
    }
    wp_reset_postdata();
  }
}

$context['data'] = $data;
Timber::render( array( 'page-' . $timber_post->post_name . '.twig', 'page.twig' ), $context );

Page Stories Twig

{% for parent in data %}
<div class="category">
  <h3 id="{{ parent.slug }}">
    {{ parent.name }}
  </h3>
  {% if parent.children|default %}
    {% for child in parent.children %}
      <div class="category__child">
        <h4>
          {{ child.name }}
        </h4>
        {% if child.posts|default %}
          {% for post in child.posts %}
          <div class="story">
            <a href="{{ post.url }}" title="{{ post.title }}">
              {{ post.title }}
            </a>
            <span>
              {{ post.date }}
            </span>
          </div>
          {% endfor %}
        {% endif %}
      </div>
    {% endfor %}
  {% endif %}
</div>
{% endfor %}