Search code examples
woocommercetimber

Timber and WooCommerce loop problem not showing price


I'm using Timber + WooCommerce and trying to show custom query of products on the front page but the loop is missing the price but shows image and title. The archive and single product pages' however do show the price.

Should the query be on woocommerce.php page? What am I missing here?

page.php

$context = Timber::get_context();
$page = new TimberPost();
$context['post'] = $page;

if ( is_front_page() ) {
    $top_selling = [
        'post_type' => 'product',
        'posts_per_page' => 4,
        'post_status' => 'publish'
    ];
    $context['top_selling'] =  new Timber\PostQuery($top_selling);
}

Timber::render(array('page-' . $page->post_name . '.twig', 'page.twig'), $context);

page-home.twig

{% for post in top_selling %}
{% include 'woocommerce/tease-product.twig' %}
{% endfor %}

tease-product.php

<div class="column is-6 is-4-desktop is-3-widescreen has-text-centered">

    {{ fn('timber_set_product', post) }}

    <a href="{{ post.link }}">
        <img src="{{ post.thumbnail.src | resize(450) }}" alt="{{ post.title }}" />
    </a>

    {% if post.brands | length > 0 %}
        {% for brand in post.brands %}
            <div>{{ brand.name }}</div>
        {% endfor %}
    {% endif %}

    <a href="{{ post.link }}">
        <div>{{ post.title }}</div>
    </a>

    // This part here shows the price on archive and single-product pages' only. It needs to show the price on front page, too.
    {% do action( 'woocommerce_after_shop_loop_item_title' ) %}
</div>

woocommerce.php

<?php 

if ( ! class_exists( 'Timber' ) ) {
    echo 'Timber not activated. Make sure you activate the plugin in <a href="/wp-admin/plugins.php#timber">/wp-admin/plugins.php</a>';

    return;
}

$context            = Timber::context();
$context['sidebar'] = Timber::get_widgets( 'shop-sidebar' );

if ( is_singular( 'product' ) ) {
    $context['post']    = Timber::get_post();
    $product            = wc_get_product( $context['post']->ID );
    $context['product'] = $product;

    // Get related products
    $related_limit               = wc_get_loop_prop( 'columns' );
    $related_ids                 = wc_get_related_products( $context['post']->id, $related_limit );
    $context['related_products'] =  Timber::get_posts( $related_ids );

    // Restore the context and loop back to the main query loop.
    wp_reset_postdata();

    Timber::render( 'views/woocommerce/single-product.twig', $context );
} else {
    $posts = Timber::get_posts();
    $context['products'] = $posts;

    if ( is_product_category() ) {
        $queried_object = get_queried_object();
        $term_id = $queried_object->term_id;
        $context['category'] = get_term( $term_id, 'product_cat' );
        $context['title'] = single_term_title( '', false );
    }

    Timber::render( 'views/woocommerce/archive.twig', $context );
}


Solution

  • The price will not display in the manner you have called it unless global $product is set.

    The function call in your twig template {{ fn('timber_set_product', post) }} should be taking care of that, however if you've copied and pasted the one from the woocommerce and timber tutorial, you'll need to edit it.

    original function

    <?php
    function timber_set_product( $post ) {
        global $product;
    
        if ( is_woocommerce() ) {
            $product = wc_get_product( $post->ID );
        }
    }
    

    new function

    <?php
    function timber_set_product( $post ) {
        global $product;
    
        // is_woocommerce() does not return true on the front_page by default!
    
        if ( is_woocommerce() or is_front_page() ) {
            $product = wc_get_product( $post->ID );
        }
    }
    

    You could even do away with the is_woocommerce() check entirely, then it's up to you to ensure it's only being called at an appropriate time.