Lubo Masura
Lubo Masura

Reputation: 1053

Woocommerce - pagination on product reviews does not work with a custom query

I have a custom single-product-reviews.php template. On our website we use Weglot (similar to WPML) but you need to modify queries on your own to get the right reviews foreach language. If you dont the reviews are shown for the all languages for product. This is what we don't want to have.

We have modified the query to get only the reviews for selected product and current language. This works fine. Now the problem is that the pagination is not working. It displays pages for all reviews and when you switch page you get the same reviews for each page.

enter image description here

The same reviews on each page and total number of pages = 45 even when I have in query only 173 reviews filtered by 10 per page = 18 pages not 45

Code UPDATE - FIXED PAGINATION COUNT

<?php
/**
 * Display single product reviews (comments)
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/single-product-reviews.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see     https://docs.woocommerce.com/document/template-structure/
 * @package WooCommerce\Templates
 * @version 4.3.0
 */

defined( 'ABSPATH' ) || exit;


function my_plugin_paginate_comments( int $total_comments ) {
    global $wp_rewrite;
    $page = get_query_var( 'cpage' );
    if ( ! $page ) {
        $page = 1;
    }
    // This is the main difference with paginate_comments_links.
    $per_page = get_option( 'comments_per_page' );
    $max_page = ceil( $total_comments / $per_page );
    $defaults = array(
        'base'         => add_query_arg( 'cpage', '%#%' ),
        'format'       => '',
        'total'        => $max_page,
        'current'      => $page,
        'type'         => 'plain',
        'add_fragment' => '#comments',
    );
    if ( $wp_rewrite->using_permalinks() ) {
        $defaults['base'] = user_trailingslashit( trailingslashit( get_permalink() ) . $wp_rewrite->comments_pagination_base . '-%#%', 'commentpaged' );
    }

    $args = apply_filters(
        'woocommerce_comment_pagination_args',
        array(
            'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
            'next_text' => is_rtl() ? '&larr;' : '&rarr;',
            'type'      => 'list',
        )
    );

    $args = wp_parse_args( $args, $defaults );

    return paginate_links( $args );
}

global $product;
$product_id = $product->get_id();
$average_rating = $product->get_average_rating();
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$number = 10;
$offset = ( $paged - 1 ) * $number;

if ( ! comments_open() ) {
    return;
}
if(weglot_get_current_language()=='cs'){
       $args = array(
       'meta_key' => 'jazyk',
       'meta_value' => 'cz',
       'post__in' => [get_queried_object_id()],
       'posts_per_page' => 5
    );
    }
    if(weglot_get_current_language()=='sk'){
       $args = array(
       'meta_key' => 'jazyk',
       'meta_value' => 'sk',
       'post__in' => [get_queried_object_id()],
       'number' => $number,
       'offset' => $offset,
       'paged' => $paged
    );
    }
    if(weglot_get_current_language()=='hu'){
       $args = array(
       'meta_key' => 'jazyk',
       'meta_value' => 'hu',
       'post__in' => [get_queried_object_id()],
    );
    }
    if(weglot_get_current_language()=='ro'){
       $args = array(
       'meta_key' => 'jazyk',
       'meta_value' => 'ro',
       'post__in' => [get_queried_object_id()],
    );
    }
    
    // The Query
    
    //global $wp_query;
    //return $wp_query->get_queried_object_id();
    $comments_query = new WP_Comment_Query;
    $comments = $comments_query->query( $args );
    
    //count
    $args = array(
    'type' => 'review',
    'count' => true,
    'meta_key' => 'jazyk',
    'meta_value' => 'sk',
    'post__in' => [get_queried_object_id()],
    );
    
    $woocommerce_comment_pagination_args= array(
    'type' => 'review',
    'count' => true,
    'meta_key' => 'jazyk',
    'meta_value' => 'sk',
    'post__in' => [get_queried_object_id()],
    );
    $count = get_comments($args);
?>

<?php 

echo custom_woo_reviews_summary($product_id); ?>
<div id="reviews" class="woocommerce-Reviews">
    <div id="comments">
        <h2 class="woocommerce-Reviews-title">
            <?php
            //$count = $product->get_review_count($args);
            if ( $count && wc_review_ratings_enabled() ) {
                /* translators: 1: reviews count 2: product name */
                $reviews_title = sprintf( esc_html( _n( '%1$s review for %2$s', '%1$s reviews for %2$s', $count, 'woocommerce' ) ), esc_html( $count ), '<span>' . get_the_title() . '</span>' );
                echo apply_filters( 'woocommerce_reviews_title', $reviews_title, $count, $product ); // WPCS: XSS ok.
            } else {
                esc_html_e( 'Reviews', 'woocommerce' );
            }
            
?>
        </h2>

        <?php 
        if ( have_comments($comments) ) : ?>
            <ol class="commentlist">
                <?php wp_list_comments( apply_filters( 'woocommerce_product_review_list_args', array( 'callback' => 'woocommerce_comments' ) ), $comments ); ?>
            </ol>

            <?php
            $pagination = $count === 0 ? null : my_plugin_paginate_comments($count);
            if ( $pagination  ) :
            echo '<nav class="woocommerce-pagination">';
            echo $pagination;
            echo '</nav>';
        endif;
            ?>
        <?php else : ?>
            <p class="woocommerce-noreviews"><?php esc_html_e( 'There are no reviews yet.', 'woocommerce' ); ?></p>
        <?php endif; ?>
    </div>

    <?php if ( get_option( 'woocommerce_review_rating_verification_required' ) === 'no' || wc_customer_bought_product( '', get_current_user_id(), $product->get_id() ) ) : ?>
        <div id="review_form_wrapper">
            <div id="review_form">
                <?php
                $commenter    = wp_get_current_commenter();
                $comment_form = array(
                    /* translators: %s is product title */
                    'title_reply'         => have_comments() ? esc_html__( 'Add a review', 'woocommerce' ) : sprintf( esc_html__( 'Be the first to review &ldquo;%s&rdquo;', 'woocommerce' ), get_the_title() ),
                    /* translators: %s is product title */
                    'title_reply_to'      => esc_html__( 'Leave a Reply to %s', 'woocommerce' ),
                    'title_reply_before'  => '<span id="reply-title" class="comment-reply-title">',
                    'title_reply_after'   => '</span>',
                    'comment_notes_after' => '',
                    'label_submit'        => esc_html__( 'Submit', 'woocommerce' ),
                    'logged_in_as'        => '',
                    'comment_field'       => '',
                );

                $name_email_required = (bool) get_option( 'require_name_email', 1 );
                $fields              = array(
                    'author' => array(
                        'label'    => __( 'Name', 'woocommerce' ),
                        'type'     => 'text',
                        'value'    => $commenter['comment_author'],
                        'required' => $name_email_required,
                    ),
                    'email'  => array(
                        'label'    => __( 'Email', 'woocommerce' ),
                        'type'     => 'email',
                        'value'    => $commenter['comment_author_email'],
                        'required' => $name_email_required,
                    ),
                );

                $comment_form['fields'] = array();

                foreach ( $fields as $key => $field ) {
                    $field_html  = '<p class="comment-form-' . esc_attr( $key ) . '">';
                    $field_html .= '<label for="' . esc_attr( $key ) . '">' . esc_html( $field['label'] );

                    if ( $field['required'] ) {
                        $field_html .= '&nbsp;<span class="required">*</span>';
                    }

                    $field_html .= '</label><input id="' . esc_attr( $key ) . '" name="' . esc_attr( $key ) . '" type="' . esc_attr( $field['type'] ) . '" value="' . esc_attr( $field['value'] ) . '" size="30" ' . ( $field['required'] ? 'required' : '' ) . ' /></p>';

                    $comment_form['fields'][ $key ] = $field_html;
                }

                $account_page_url = wc_get_page_permalink( 'myaccount' );
                if ( $account_page_url ) {
                    /* translators: %s opening and closing link tags respectively */
                    $comment_form['must_log_in'] = '<p class="must-log-in">' . sprintf( esc_html__( 'You must be %1$slogged in%2$s to post a review.', 'woocommerce' ), '<a href="' . esc_url( $account_page_url ) . '">', '</a>' ) . '</p>';
                }

                if ( wc_review_ratings_enabled() ) {
                    $comment_form['comment_field'] = '<div class="comment-form-rating"><label for="rating">' . esc_html__( 'Your rating', 'woocommerce' ) . ( wc_review_ratings_required() ? '&nbsp;<span class="required">*</span>' : '' ) . '</label><select name="rating" id="rating" required>
                        <option value="">' . esc_html__( 'Rate&hellip;', 'woocommerce' ) . '</option>
                        <option value="5">' . esc_html__( 'Perfect', 'woocommerce' ) . '</option>
                        <option value="4">' . esc_html__( 'Good', 'woocommerce' ) . '</option>
                        <option value="3">' . esc_html__( 'Average', 'woocommerce' ) . '</option>
                        <option value="2">' . esc_html__( 'Not that bad', 'woocommerce' ) . '</option>
                        <option value="1">' . esc_html__( 'Very poor', 'woocommerce' ) . '</option>
                    </select></div>';
                }

                $comment_form['comment_field'] .= '<p class="comment-form-comment"><label for="comment">' . esc_html__( 'Your review', 'woocommerce' ) . '&nbsp;<span class="required">*</span></label><textarea id="comment" name="comment" cols="45" rows="8" required></textarea></p>';

                comment_form( apply_filters( 'woocommerce_product_review_comment_form_args', $comment_form ) );
                ?>
            </div>
        </div>
    
<?php else : ?>
        <p class="woocommerce-verification-required"><?php esc_html_e( 'Only logged in customers who have purchased this product may leave a review.', 'woocommerce' ); ?></p>
    <?php endif; ?>

    <div class="clear"></div>
</div>

PROBLEM Pagination is fixed. But comments are displayed only at page 1. On page 2,3etc...there are no comments displayed. After printing the meta data of each page I get the same data on each page.

Example print_r array, we get 10 same arrays with the same comment IDS on every page

Array
(
    [0] => WP_Comment Object
        (
            [comment_ID] => 152886
            [comment_post_ID] => 40
            [comment_author] => Edit
            [comment_author_email] => 
            [comment_author_url] => 
            [comment_author_IP] => 
            [comment_date] => 2022-07-25 21:54:59
            [comment_date_gmt] => 2022-07-25 19:54:59
            [comment_content] => Super vecička do prírody, do záhrady. Čerstvé šťavy priamo zo stromu.
            [comment_karma] => 0
            [comment_approved] => 1
            [comment_agent] => 
            [comment_type] => review
            [comment_parent] => 0
            [user_id] => 0
            [children:protected] => 
            [populated_children:protected] => 
            [post_fields:protected] => Array
                (
                    [0] => post_author
                    [1] => post_date
                    [2] => post_date_gmt
                    [3] => post_content
                    [4] => post_title
                    [5] => post_excerpt
                    [6] => post_status
                    [7] => comment_status
                    [8] => ping_status
                    [9] => post_name
                    [10] => to_ping
                    [11] => pinged
                    [12] => post_modified
                    [13] => post_modified_gmt
                    [14] => post_content_filtered
                    [15] => post_parent
                    [16] => guid
                    [17] => menu_order
                    [18] => post_type
                    [19] => post_mime_type
                    [20] => comment_count
                )

        )

Upvotes: 1

Views: 1047

Answers (1)

inwerpsel
inwerpsel

Reputation: 3237

You're calling paginate_comments_links to output the pagination, however it doesn't receive the arguments you passed to the earlier comments query. It internally calls get_comment_pages_count with no arguments.

// paginate_comments_links line 3118
$max_page = get_comment_pages_count();

As a result it ends up using the global query (see start of get_comment_pages_count). If you need to continue using paginate_comments_links, you have no choice but to modify the global query so it has the right meta filter applied. No argument exists for forcing the total number of pages.

An alternative is to not use that function, but the paginate_links function it uses internally. There's a small amount of logic we need to copy, but it's manageable.

This allows to calculate the max page based on the result of your count query.

I also moved calling the pagination arguments filter in here, to keep it out the template. I think the following should work.

function my_plugin_paginate_comments( int $total_comments, int $page ) {
    global $wp_rewrite;
    if ( ! $page ) {
        $page = 1;
    }
    // This is the main difference with paginate_comments_links.
    $per_page = get_option( 'comments_per_page' );
    $max_page = ceil( $total_comments / $per_page );
    $defaults = array(
        'base'         => add_query_arg( 'paged', '%#%' ),
        'format'       => '',
        'total'        => $max_page,
        'current'      => $page,
        'type'         => 'plain',
        'add_fragment' => '#comments',
    );
    if ( $wp_rewrite->using_permalinks() ) {
        $defaults['base'] = user_trailingslashit( trailingslashit( get_permalink() ) . $wp_rewrite->comments_pagination_base . '-%#%', 'commentpaged' );
    }

    $args = apply_filters(
        'woocommerce_comment_pagination_args',
        array(
            'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
            'next_text' => is_rtl() ? '&larr;' : '&rarr;',
            'type'      => 'list',
        )
    );

    $args = wp_parse_args( $args, $defaults );

    return paginate_links( $args );
}

You can call it and assign the HTML to a template variable.

$pagination = $count === 0 ? null : my_plugin_paginate_comments($count);

Then in the template you can just output it, if it exists.

        if ( $pagination  ) :
            echo '<nav class="woocommerce-pagination">';
            echo $pagination;
            echo '</nav>';
        endif;

Update 1

To get the right items per page, you need to pass the comments returned by your query to wp_list_comments, in the second argument. (The first argument is a bit long, the second is way at the end of the line)

<?php wp_list_comments( apply_filters( 'woocommerce_product_review_list_args', array( 'callback' => 'woocommerce_comments' ) ), $comments ); ?>

Update 2

I had used the default WordPress query var for the page number (cpage), however now I see your code is using paged.

$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;

I also made this an argument of the function now, and passed in the value you're already reading. Does it work now?

I see it might not because the site you're linking also shows another URL structure, where the comments page number is in the URL path. Maybe you can check your URL rewrite settings whether you can make it use the default query parameter for comments?

Upvotes: 1

Related Questions