4

I have a parent category page in WordPress that displays a single post and four sub categories below it. The four sub category pages will share the same HTML and logic, but are different from the parent category. The parent category is using category.php and category.twig to handle the display of its HTML and content. See code below. How can I tell WordPress and Timber to use category-child.php and category-child.twig (example names) for children of the parent category (slug: stories). I know I can use category-slug.php or category-id.php for each child slug or ID, but that would require adding the same code to four (or more) different PHP and Twig files, which is not ideal.

category.php

/**
 * @package  WordPress
 * @subpackage  gerryfeehan
 * @since   1.0.0
 */

$templates = array( 'category.twig', 'index.twig' );

$context = Timber::context();

$args = array(
    'cat' => '7,5,3,4,6',
    'numberposts' => 1,
    'orderby' => 'date',
    'order' => 'DESC',
);
$context['stories'] = Timber::get_posts($args);

$context['categories'] = Timber::get_terms('category');

$categories = get_categories(
    array(
        'hide_empty' => '0',
        'parent'     => 7,
        'orderby'    => 'id',
        'order'      => 'ASC'
    )
);

// $context['categories'] = $categories;

// Updated code with suggestions from Tomek

$category = get_queried_object(); // will give you current WP_Term

if( $category->parent == 0 ) {
    // parent category
    $templates = array( 'category.twig' );
    $context['categories'] = $categories;
} else {
    // child category
    $templates = array( 'category-map.twig' );
    $context['categories'] = $categories;
}

// Timber::render( array( 'category.twig', 'index.twig' ), $context );
Timber::render( $templates, $context );

category.twig

{% extends "base.twig" %}

{% block content %}
<section class="stories">
    <h2>Stories</h2>
    {% for story in stories %} 
    <article class="story" id="story-{{ story.ID }}">
        {% if story.thumbnail.src %}
            <figure>
                <img src="{{ story.thumbnail.src }}" class="" alt="{{ story.thumbnail.alt }}" />
                {% if story.thumbnail.caption %}
                    <figcaption>{{ story.thumbnail.caption }}</figcaption>
                {% endif %}
            </figure>
        {% endif %} 
        <h3 class="story__heading">
            <a href="{{ story.link }}">
                {{ story.title }}
            </a>
        </h3>
        <div class="story__meta">
            <time class="">{{ story.date }}</time>
        </div>
        <div class="story__content">
            {{ story.preview.read_more(false) }}
        </div>
    </article>
    {% endfor %}
</section>
{% if function(cat_is_ancestor_of(7, 5)) %}yolo{% endif %}
{% for category in categories %}
<div class="category">
    <figure>
        <figcaption>
            {{ category.name }}
        </figcaption>
        {{ category.description }}
    </figure>
</div>
{% endfor %}
{% endblock %}

The following code could be added to the archive.php file, but I am not sure how it could be expanded to meet my needs.

else if ( is_category() ) {
    $term = new Timber\Term( get_queried_object_id() );

    $context['term']  = $term;
    $context['title'] = single_cat_title( '', false );

    array_unshift( $templates, 'archive-' . $term->slug . '.twig' );
}

Full parent and child category structure

Parent: Stories Children: Camping America, Canada, United States, and World.

Any ideas?

Mike Hermary
  • 346
  • 7
  • 22

2 Answers2

4

As a solution, you could create the template file for sub categories and include the template via functions.php

Steps by steps

Create your template file, e.g template-sub-category.php

Add the code to your functions.php

add_filter( 'template_include', 'your_prefix_set_template', 10, 1 );

function your_prefix_set_template( $template_path ) {
    if ( ! is_category() ) {
        return $template_path;
    }

    $parent_category = get_term_by( 'slug', 'stories', 'category' ); // parent category

    if ( empty( $parent_category ) ) {
        return $template_path;
    }

    $term = get_queried_object();
    if ( $term->parent !== $parent_category->term_id ) { // check if is the parent category
        return $template_path;
    }

    return locate_template( 'template-sub-category.php' );
}
123
  • 2,169
  • 3
  • 11
  • 35
  • Thanks for the code. It does work when the child category is displayed in the URL like this: **domain.com/child-category**, but when it is displayed as **domain.com/parent-category/child-category**, the template cannot be found. Any ideas? – Mike Hermary Nov 25 '19 at 23:15
  • Could you specify structure for your categories? As I understood your structure is **domain.com/stories** - main category? And **domain.com/stories/sub-category** - sub category? – 123 Nov 26 '19 at 01:06
  • Yes, that is the correct category structure. I have edited my question to include the complete category structure. When I click a child category link, WordPress displays the 404 page instead of the child category page. – Mike Hermary Nov 26 '19 at 16:22
  • I didn't read the whole (massive) question, but is it maybe possible to include one of 2 files from the same file that WordPress will already include? – Joel M Nov 27 '19 at 04:38
  • @JoelM The code Andrii posted was working when the child category was included directly after the domain name. For example, domain.com/child-category. When it is used in the proper structure of domain.com/parent/child-category, the template override fails to work and a 404 is displayed. – Mike Hermary Nov 27 '19 at 21:22
  • @MikeHermary, maybe the problem with permalinks structure. Could you test by replacing my code snippet part `is_category()` - with `if ( ! is_category() ) { ob_clean(); var_dump( 'is-not-category' ); exit; return $template_path; }` Then go to your sub-category (404 page). Then do you see 'is-not-category'? If do - the problem with your permalinks structure. And you could debug the structure with plugin (monkeyman-rewrite-analyzer) – 123 Dec 01 '19 at 07:04
1

Leave logic in category.php. Add something like this (sudo code):

$category = get_queried_object(); // will give you current WP_Term

if($category->parent == 0) {

// parent category
$templates = array( 'parent-category.twig' );
$context['dataForParentCategory'] = array( ... );

} else {

// child category
$templates = array( 'child-category.twig' );
$context['dataForChildCategory'] = array( ... );

}

Timber::render( $templates, $context );

Tomek Dura
  • 146
  • 3
  • I have commented out the code in the functions file, and added your suggested code to the category.php logic file, but still no success. A 404 is still loaded for the child category pages. – Mike Hermary Nov 28 '19 at 16:22
  • So, it's rather permalink problem than differentiation between parent / child ... Usually in such cases people use pattern (Settings -> Permalinks): 1. Custom Structure: /%category%/%postname%/ 2. Category Base: . (dot) 3. Save settings hope, it will help – Tomek Dura Nov 28 '19 at 21:29
  • I am already using those settings in my Permalinks configuration. Any other ideas? – Mike Hermary Nov 28 '19 at 22:15
  • Just launched clean WP, added 'Parent' category, two children categories (Child 01, Child 02) and added one post for every category. Permalinks works well with pattern: /category/parent/ (for Parent), /category/parent/child-1/ and /category/parent/child-2/ (for chidren categories). So I guess, in your case I would return to default settings from clean installation (empty 'Category base' in Permalink settings) ... unless you are not ok with '/category/' in permalinks. Then I would suggest creating custom taxonomy for posts. You can define rewrite pattern in register_taxonomy() function – Tomek Dura Nov 29 '19 at 10:55
  • Reverting the permalink settings to the default has solved the issue. I am not a big fan of having "category" in my links, so I will look into custom taxonomy. Thanks for your tips. – Mike Hermary Nov 29 '19 at 18:10