PluginProbe ʕ •ᴥ•ʔ
Author Website Templates – Create Writer, Author & Publisher Websites Easily / 1.1.9
Author Website Templates – Create Writer, Author & Publisher Websites Easily v1.1.9
trunk 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9
author-website-templates / build / blocks / author-pro / book-page-review-section / render.php
author-website-templates / build / blocks / author-pro / book-page-review-section Last commit date
block.json 1 month ago index.asset.php 1 month ago index.js 1 month ago render.php 1 month ago view.asset.php 1 month ago view.js 1 month ago
render.php
325 lines
1 <?php
2 /**
3 * Render Book Page Reviews [Author Pro] Block
4 */
5
6 $block_id = isset($attributes['blockId']) ? $attributes['blockId'] : '';
7 if (empty($block_id)) {
8 $block_id = 'awt-book-reviews-' . uniqid();
9 }
10
11 $anchor = isset($attributes['anchor']) ? $attributes['anchor'] : '';
12 $element_id = !empty($anchor) ? $anchor : $block_id;
13
14 $section_title = !empty($attributes['sectionTitle']) ? $attributes['sectionTitle'] : 'Customer Reviews';
15 $form_title = !empty($attributes['formTitle']) ? $attributes['formTitle'] : 'Write a Review';
16 $submit_btn_text = !empty($attributes['submitBtnText']) ? $attributes['submitBtnText'] : 'Submit Review';
17
18 // New Attributes with Defaults
19 $sort_label_most_recent = !empty($attributes['sortLabelMostRecent']) ? $attributes['sortLabelMostRecent'] : 'Most Recent';
20 $sort_label_highest = !empty($attributes['sortLabelHighest']) ? $attributes['sortLabelHighest'] : 'Highest Rated';
21 $sort_label_lowest = !empty($attributes['sortLabelLowest']) ? $attributes['sortLabelLowest'] : 'Lowest Rated';
22
23 $text_based_on = !empty($attributes['textBasedOn']) ? $attributes['textBasedOn'] : 'Based on';
24 $text_reviews_suffix = !empty($attributes['textReviewsSuffix']) ? $attributes['textReviewsSuffix'] : 'reviews';
25 $text_star = !empty($attributes['textStar']) ? $attributes['textStar'] : 'Star';
26
27 $cta_heading = !empty($attributes['ctaHeading']) ? $attributes['ctaHeading'] : 'Share your thoughts';
28 $cta_description = !empty($attributes['ctaDescription']) ? $attributes['ctaDescription'] : "If you've read this book, we'd love to hear what you think!";
29 $cta_button_text = !empty($attributes['ctaButtonText']) ? $attributes['ctaButtonText'] : 'Write a Review';
30
31 $label_name = !empty($attributes['labelName']) ? $attributes['labelName'] : 'Name *';
32 $label_email = !empty($attributes['labelEmail']) ? $attributes['labelEmail'] : 'Email *';
33 $label_rating = !empty($attributes['labelRating']) ? $attributes['labelRating'] : 'Rating *';
34 $label_review_title = !empty($attributes['labelReviewTitle']) ? $attributes['labelReviewTitle'] : 'Review Title *';
35 $label_review_content = !empty($attributes['labelReviewContent']) ? $attributes['labelReviewContent'] : 'Your Review *';
36
37 $msg_no_reviews = !empty($attributes['msgNoReviews']) ? $attributes['msgNoReviews'] : 'No reviews yet. Be the first to review!';
38
39 $book_id = get_the_ID();
40 $is_editor = defined('REST_REQUEST') && REST_REQUEST === true;
41
42 // If in editor, preview with a real book if possible
43 if ($is_editor && get_post_type($book_id) !== 'book') {
44 $min_query = new WP_Query([
45 'post_type' => 'book',
46 'posts_per_page' => 1,
47 'post_status' => 'publish'
48 ]);
49 if ($min_query->have_posts()) {
50 $min_query->the_post();
51 $book_id = get_the_ID();
52 wp_reset_postdata();
53 }
54 }
55
56 // 1. Fetch Reviews
57 $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
58 $args = array(
59 'post_type' => 'book_reviews',
60 'posts_per_page' => 5,
61 'paged' => $paged,
62 'meta_query' => array(
63 array(
64 'key' => '_rswpbs_reviewed_book',
65 'value' => $book_id,
66 'compare' => '='
67 )
68 )
69 );
70 $reviews_query = new WP_Query($args);
71 $total_reviews = $reviews_query->found_posts;
72
73 // 2. Calculate Stats (All time)
74 // Separate query for ALL reviews to calculate stats correctly
75 $stats_args = $args;
76 $stats_args['posts_per_page'] = -1;
77 $stats_args['paged'] = 1;
78 $all_reviews = get_posts($stats_args);
79
80 $total_rating_sum = 0;
81 $star_counts = [5 => 0, 4 => 0, 3 => 0, 2 => 0, 1 => 0];
82
83 foreach ($all_reviews as $review) {
84 $rating = get_post_meta($review->ID, '_rswpbs_rating', true);
85 $rating = intval($rating);
86 if ($rating >= 1 && $rating <= 5) {
87 $total_rating_sum += $rating;
88 $star_counts[$rating]++;
89 }
90 }
91
92 $avg_rating = ($total_reviews > 0) ? round($total_rating_sum / count($all_reviews), 1) : 0; // Use count of fetched posts for accuracy
93
94 // Helper to render stars
95 function awt_render_stars($rating) {
96 $html = '';
97
98 for ($i = 1; $i <= 5; $i++) {
99 $color_class = ($i <= $rating) ? 'text-yellow-400' : 'text-gray-300';
100
101 $html .= '
102 <svg
103 xmlns="http://www.w3.org/2000/svg"
104 viewBox="0 0 640 640"
105 class="w-4 h-4 inline-block ' . esc_attr($color_class) . '"
106 fill="currentColor"
107 aria-hidden="true"
108 >
109 <path d="M341.5 45.1C337.4 37.1 329.1 32 320.1 32C311.1 32 302.8 37.1 298.7 45.1L225.1 189.3L65.2 214.7C56.3 216.1 48.9 222.4 46.1 231C43.3 239.6 45.6 249 51.9 255.4L166.3 369.9L141.1 529.8C139.7 538.7 143.4 547.7 150.7 553C158 558.3 167.6 559.1 175.7 555L320.1 481.6L464.4 555C472.4 559.1 482.1 558.3 489.4 553C496.7 547.7 500.4 538.8 499 529.8L473.7 369.9L588.1 255.4C594.5 249 596.7 239.6 593.9 231C591.1 222.4 583.8 216.1 574.8 214.7L415 189.3L341.5 45.1z"/>
110 </svg>';
111 }
112
113 return $html;
114 }
115
116
117 $wrapper_attributes = get_block_wrapper_attributes([
118 'class' => 'awt-book-reviews',
119 'id' => $element_id,
120 ]);
121 ?>
122
123 <section class="py-20 bg-white" <?php echo $wrapper_attributes; ?>>
124 <div class="awt-container">
125 <div class="grid grid-cols-1 lg:grid-cols-12 gap-12">
126
127 <!-- Left Column: Stats -->
128 <div class="lg:col-span-4">
129 <!-- Summary Card -->
130 <div class="bg-paper p-8 rounded-xl border border-gray-100 text-center mb-8">
131 <div class="text-5xl font-bold text-primary mb-2"><?php echo esc_html($avg_rating); ?></div>
132 <div class="flex justify-center gap-1 text-yellow-400 mb-2">
133 <?php echo awt_render_stars(round($avg_rating)); ?>
134 </div>
135 <p class="text-secondary text-sm"><?php echo esc_html($text_based_on); ?> <?php echo esc_html($total_reviews); ?> <?php echo esc_html($text_reviews_suffix); ?></p>
136 </div>
137
138 <!-- Progress Bars -->
139 <div class="space-y-3 mb-8">
140 <?php for ($star = 5; $star >= 1; $star--) :
141 $count = $star_counts[$star];
142 $percent = ($total_reviews > 0) ? ($count / $total_reviews) * 100 : 0;
143 ?>
144 <?php
145 ?>
146 <div class="flex items-center text-sm">
147 <span class="w-12 text-secondary font-medium"><?php echo $star; ?> <?php echo esc_html($text_star); ?></span>
148 <div class="flex-1 h-2 bg-gray-100 rounded-full mx-3 overflow-hidden">
149 <div class="h-full bg-yellow-400 rounded-full" style="width: <?php echo esc_attr($percent); ?>%"></div>
150 </div>
151 <span class="w-8 text-right text-gray-400 text-xs"><?php echo round($percent); ?>%</span>
152 </div>
153 <?php endfor; ?>
154 </div>
155
156 <!-- CTA Box -->
157 <div class="bg-primary text-white p-6 rounded-xl relative overflow-hidden">
158 <div class="relative z-10">
159 <h3 class="font-serif font-bold text-xl mb-2"><?php echo esc_html($cta_heading); ?></h3>
160 <p class="text-white/80 text-sm mb-6"><?php echo esc_html($cta_description); ?></p>
161 <a href="#write-review" class="block w-full py-3 bg-white text-primary text-center font-bold rounded-lg hover:bg-accent hover:text-white transition"><?php echo esc_html($cta_button_text); ?></a>
162 </div>
163 <!-- Decorative Circles in CSS/Class similar to ref if needed, strictly keeping structure simple as requested -->
164 </div>
165 </div>
166
167 <!-- Right Column: Review List -->
168 <div class="lg:col-span-8">
169 <div class="flex justify-between items-center mb-8 pb-4 border-b border-gray-100">
170 <h2 class="font-serif font-bold text-2xl text-primary"><?php echo esc_html($section_title); ?></h2>
171
172 <!-- Sorting Dropdown (Optional visual only for now) -->
173 <div class="relative">
174 <select class="appearance-none bg-white border border-gray-200 rounded-lg py-2 pl-4 pr-10 text-sm font-medium text-secondary focus:outline-none focus:border-accent">
175 <option><?php echo esc_html($sort_label_most_recent); ?></option>
176 <option><?php echo esc_html($sort_label_highest); ?></option>
177 <option><?php echo esc_html($sort_label_lowest); ?></option>
178 </select>
179 <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
180 <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
181 </div>
182 </div>
183 </div>
184
185 <?php if ($reviews_query->have_posts()) : ?>
186 <div class="space-y-8 mb-12">
187 <?php while ($reviews_query->have_posts()) : $reviews_query->the_post();
188 $reviewer_email = get_post_meta(get_the_ID(), '_rswpbs_reviewer_email', true);
189 $reviewer_name = get_post_meta(get_the_ID(), '_rswpbs_reviewer_name', true);
190 $rating = get_post_meta(get_the_ID(), '_rswpbs_rating', true);
191 $avatar_url = get_avatar_url($reviewer_email, ['default' => 'mp']);
192 ?>
193 <div class="flex gap-4 mb-8">
194 <div class="flex-shrink-0">
195 <img src="<?php echo esc_url($avatar_url); ?>" alt="<?php echo esc_attr($reviewer_name); ?>" class="w-12 h-12 rounded-full object-cover border border-gray-100">
196 </div>
197 <div class="flex-grow">
198 <div class="flex justify-between items-start mb-2">
199 <div>
200 <h4 class="font-bold text-primary"><?php echo esc_html($reviewer_name); ?></h4>
201 <div class="text-xs text-gray-400"><?php echo get_the_date(); ?></div>
202 </div>
203 <div class="flex text-yellow-400 text-xs gap-0.5">
204 <?php echo awt_render_stars(intval($rating)); ?>
205 </div>
206 </div>
207 <h5 class="font-bold text-sm text-primary mb-2"><?php the_title(); ?></h5>
208 <div class="text-secondary prose text-sm leading-relaxed">
209 <?php the_content(); ?>
210 <!-- Using the_content() or excerpt depending on need. The ref request asked for content. -->
211 </div>
212 </div>
213 </div>
214 <?php endwhile; wp_reset_postdata(); ?>
215 </div>
216
217 <!-- Pagination -->
218 <div class="flex justify-center gap-2 mb-12">
219 <?php
220 $prev_icon = '
221 <svg xmlns="http://www.w3.org/2000/svg"
222 viewBox="0 0 640 640"
223 class="w-4 h-4"
224 fill="currentColor"
225 aria-hidden="true">
226 <path d="M169.4 297.4C156.9 309.9 156.9 330.2 169.4 342.7L361.4 534.7C373.9 547.2 394.2 547.2 406.7 534.7C419.2 522.2 419.2 501.9 406.7 489.4L237.3 320L406.6 150.6C419.1 138.1 419.1 117.8 406.6 105.3C394.1 92.8 373.8 92.8 361.3 105.3L169.3 297.3z"/>
227 </svg>';
228
229 $next_icon = '
230 <svg xmlns="http://www.w3.org/2000/svg"
231 viewBox="0 0 640 640"
232 class="w-4 h-4"
233 fill="currentColor"
234 aria-hidden="true">
235 <path d="M471.1 297.4C483.6 309.9 483.6 330.2 471.1 342.7L279.1 534.7C266.6 547.2 246.3 547.2 233.8 534.7C221.3 522.2 221.3 501.9 233.8 489.4L403.2 320L233.9 150.6C221.4 138.1 221.4 117.8 233.9 105.3C246.4 92.8 266.7 92.8 279.2 105.3L471.2 297.3z"/>
236 </svg>';
237
238 $pagination = paginate_links(array(
239 'base' => str_replace(999999999, '%#%', esc_url(get_pagenum_link(999999999))),
240 'format' => '?paged=%#%',
241 'current' => max(1, get_query_var('paged')),
242 'total' => $reviews_query->max_num_pages,
243 'prev_text' => $prev_icon,
244 'next_text' => $next_icon,
245 'type' => 'array',
246 ));
247
248
249 if( is_array( $pagination ) ) {
250 foreach ( $pagination as $page ) {
251 // Add tailwind classes to pagination links logic if needed,
252 // but standard WP output is usually sufficient with theme styles,
253 // or we can wrapper it.
254 // For now echoing simple links.
255 echo '<span class="px-4 py-2 border border-gray-200 rounded hover:bg-gray-50 text-sm font-medium text-secondary transition cursor-pointer">' . $page . '</span>';
256 }
257 }
258 ?>
259 </div>
260
261 <?php else : ?>
262 <p class="text-gray-500 italic mb-12"><?php echo esc_html($msg_no_reviews); ?></p>
263 <?php endif; ?>
264
265 <!-- Submission Form -->
266 <div id="write-review" class="pt-12 border-t border-gray-100">
267 <h3 class="font-serif font-bold text-2xl text-primary mb-6"><?php echo esc_html($form_title); ?></h3>
268
269 <form id="rswpbs-review-form" action="" method="post" class="space-y-6">
270 <?php
271 // AJAX Action and Nonce for RS WP Books Showcase
272 // Note: The plugin must handle this action.
273 wp_nonce_field( 'rswpbs_submit_review', '_rswpbs_submit_review_nonce' );
274 ?>
275 <input type="hidden" name="action" value="rswpbs_submit_review_form">
276 <input type="hidden" name="current_post_id" value="<?php echo esc_attr($book_id); ?>">
277 <input type="hidden" name="rating" value="5">
278
279 <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
280 <div>
281 <label class="block text-sm font-bold text-primary mb-2"><?php echo esc_html($label_name); ?></label>
282 <input type="text" name="reviewer_name" required class="w-full px-4 py-3 bg-paper border border-gray-200 rounded-lg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition">
283 </div>
284 <div>
285 <label class="block text-sm font-bold text-primary mb-2"><?php echo esc_html($label_email); ?></label>
286 <input type="email" name="reviewer_email" required class="w-full px-4 py-3 bg-paper border border-gray-200 rounded-lg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition">
287 </div>
288 </div>
289
290 <div>
291 <label class="block text-sm font-bold text-primary mb-2"><?php echo esc_html($label_rating); ?></label>
292 <div class="flex gap-1 text-2xl awt-star-rating-select">
293 <?php for ($i = 1; $i <= 5; $i++) : ?>
294 <svg
295 class="awt-star-icon w-6 h-6 cursor-pointer text-gray-300 hover:scale-110 transition-transform duration-200"
296 data-rating="<?php echo $i; ?>"
297 fill="currentColor"
298 xmlns="http://www.w3.org/2000/svg"
299 viewBox="0 0 640 640">
300 <path d="M341.5 45.1C337.4 37.1 329.1 32 320.1 32C311.1 32 302.8 37.1 298.7 45.1L225.1 189.3L65.2 214.7C56.3 216.1 48.9 222.4 46.1 231C43.3 239.6 45.6 249 51.9 255.4L166.3 369.9L141.1 529.8C139.7 538.7 143.4 547.7 150.7 553C158 558.3 167.6 559.1 175.7 555L320.1 481.6L464.4 555C472.4 559.1 482.1 558.3 489.4 553C496.7 547.7 500.4 538.8 499 529.8L473.7 369.9L588.1 255.4C594.5 249 596.7 239.6 593.9 231C591.1 222.4 583.8 216.1 574.8 214.7L415 189.3L341.5 45.1z"/>
301 </svg>
302 <?php endfor; ?>
303 </div>
304 </div>
305
306 <div>
307 <label class="block text-sm font-bold text-primary mb-2"><?php echo esc_html($label_review_title); ?></label>
308 <input type="text" name="review_title" required class="w-full px-4 py-3 bg-paper border border-gray-200 rounded-lg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition">
309 </div>
310
311 <div>
312 <label class="block text-sm font-bold text-primary mb-2"><?php echo esc_html($label_review_content); ?></label>
313 <textarea name="reviewer_comment" rows="5" required class="w-full px-4 py-3 bg-paper border border-gray-200 rounded-lg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent transition"></textarea>
314 </div>
315
316 <button type="submit" class="px-8 py-3 bg-accent text-white font-bold rounded-lg hover:border-orange-700 hover:bg-orange-700 transition shadow-lg shadow-orange-500/20">
317 <?php echo esc_html($submit_btn_text); ?>
318 </button>
319 </form>
320 </div>
321 </div>
322 </div>
323 </div>
324 </section>
325