Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/fb-reviews-widget/fbrev.php
+++ b/fb-reviews-widget/fbrev.php
@@ -1,9 +1,9 @@
<?php
/*
-Plugin Name: Reviews Widgets for Google, Yelp & TripAdvisor
+Plugin Name: Reviews Widgets for Google, TripAdvisor, Yelp & Recommendations
Plugin URI: https://wordpress.org/plugins/fb-reviews-widget
-Description: Combine Facebook recommendations with Google, Yelp and TripAdvisor reviews in a widget, block or shortcode. Build a trusted website!
-Version: 2.7.3
+Description: Combine Facebook reviews and recommendations with Google, TripAdvisor and Yelp reviews in a widget, block or shortcode. Build a trusted website!
+Version: 2.8
Author: Trust.Reviews <support@trust.reviews>
Author URI: https://trust.reviews
Text Domain: fb-reviews-widget
--- a/fb-reviews-widget/includes/class-activator.php
+++ b/fb-reviews-widget/includes/class-activator.php
@@ -29,6 +29,7 @@
Plugin::SLG . '_rev_notice_hide',
Plugin::SLG . '_rev_notice_show',
Plugin::SLG . '_rate_us',
+ Plugin::SLG . '_last_error',
);
}
@@ -104,15 +105,15 @@
public function update_db($last_active_version) {
global $wpdb;
+ $rev = $wpdb->prefix . Database::REVIEW_TABLE;
+ $biz = $wpdb->prefix . Database::BUSINESS_TABLE;
+
if (version_compare($last_active_version, '2.0', '<')) {
$this->first_install();
}
if (version_compare($last_active_version, '2.7', '<')) {
- $rev = $wpdb->prefix . Database::REVIEW_TABLE;
- $biz = $wpdb->prefix . Database::BUSINESS_TABLE;
-
// add column map_url
$columns = $wpdb->get_col("SHOW COLUMNS FROM {$biz}", 0);
if (!in_array('map_url', $columns, true)) {
@@ -155,9 +156,25 @@
$this->database->migrate_review_texts();
}
- /*if (version_compare($last_active_version, '2.8', '<')) {
+ if (version_compare($last_active_version, '2.8', '<')) {
+ $text = $wpdb->prefix . Database::TEXT_TABLE;
+
+ $rev_col = $wpdb->get_row("SHOW FULL COLUMNS FROM {$rev} WHERE Field = 'review_id'");
+ $txt_col = $wpdb->get_row("SHOW FULL COLUMNS FROM {$text} WHERE Field = 'review_id'");
+
+ if ($rev_col && $txt_col && !empty($rev_col->Collation)) {
+ $collation = $rev_col->Collation;
+
+ if ($txt_col->Collation !== $collation) {
+ $valid_collation = $wpdb->get_var($wpdb->prepare("SHOW COLLATION WHERE `Collation` = %s", $collation));
+ if ($valid_collation) {
+ $wpdb->query("ALTER TABLE {$text} MODIFY review_id VARCHAR(64) COLLATE {$collation} NOT NULL");
+ }
+ }
+ }
+ }
- $rev = $wpdb->prefix . Database::REVIEW_TABLE;
+ /*if (version_compare($last_active_version, '2.8', '<')) {
// remove duplicates
$wpdb->query("DELETE r1 FROM {$rev} r1 INNER JOIN {$rev} r2 ON r1.platform = r2.platform AND r1.review_id = r2.review_id AND r1.id < r2.id");
@@ -169,6 +186,10 @@
$wpdb->query("ALTER TABLE {$rev} ADD UNIQUE INDEX {$idx} (platform, review_id)");
}
}*/
+
+ if (!empty($wpdb->last_error)) {
+ update_option(Plugin::SLG . '_last_error', time() . ': ' . $wpdb->last_error);
+ }
}
/**
--- a/fb-reviews-widget/includes/class-builder-page.php
+++ b/fb-reviews-widget/includes/class-builder-page.php
@@ -73,11 +73,11 @@
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php?action=' . Post_Types::FEED_POST_TYPE . '_save')); ?>">
<?php wp_nonce_field(Plugin::SLG . '_wpnonce'); ?>
<input type="hidden" id="{slg}_post_id" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[post_id]" value="<?php echo esc_attr($feed_id); ?>">
- <input type="hidden" id="{slg}_current_url" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[current_url]" value="<?php echo home_url($_SERVER['REQUEST_URI']); ?>">
+ <input type="hidden" id="{slg}_current_url" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[current_url]" value="<?php echo esc_url(home_url($_SERVER['REQUEST_URI'])); ?>">
<div class="{slg}-builder-workspace">
<div class="{slg}-toolbar">
<div class="{slg}-toolbar-title">
- <input id="{slg}_title" class="{slg}-toolbar-title-input" type="text" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[title]" value="<?php if (isset($feed_post_title)) { echo $feed_post_title; } ?>" placeholder="Enter a widget name" maxlength="255" autofocus>
+ <input id="{slg}_title" class="{slg}-toolbar-title-input" type="text" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[title]" value="<?php if (isset($feed_post_title)) { echo esc_attr($feed_post_title); } ?>" placeholder="Enter a widget name" maxlength="255" autofocus>
</div>
<div class="{slg}-toolbar-control">
<?php if ($feed_inited) { ?>
@@ -93,7 +93,7 @@
</div>
</div>
<div class="{slg}-builder-preview">
- <textarea id="{slg}-builder-connection" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[content]" style="display:none"><?php echo $feed_content; ?></textarea>
+ <textarea id="{slg}-builder-connection" name="<?php echo Post_Types::FEED_POST_TYPE; ?>[content]" style="display:none"><?php echo esc_textarea($feed_content); ?></textarea>
<div id="{slg}_collection_preview">
<?php
if ($feed_inited) {
@@ -132,7 +132,7 @@
<span id="{slg}-rate_us-feedback-stars"></span>
</p>
<p style="font-size:16px;">
- <input type="text" value="<?php global $current_user; echo $current_user->user_email; ?>" placeholder="Contact email"/>
+ <input type="text" value="<?php global $current_user; echo esc_attr($current_user->user_email); ?>" placeholder="Contact email"/>
</p>
<p style="font-size:16px;">
<textarea autofocus placeholder="Describe your experience and how we can improve that"></textarea>
--- a/fb-reviews-widget/includes/class-plugin.php
+++ b/fb-reviews-widget/includes/class-plugin.php
@@ -17,7 +17,7 @@
final class Plugin {
- const VER = '2.7.3';
+ const VER = '2.8';
const SLG = 'trustreviews';
const PFX = self::SLG . '_';
const NAME = 'fb-reviews-widget';
--- a/fb-reviews-widget/includes/class-view.php
+++ b/fb-reviews-widget/includes/class-view.php
@@ -23,17 +23,17 @@
}
$style = '';
- if (isset($max_width) && strlen($max_width) > 0) {
+ if (!empty($max_width)) {
$style .= 'width:' . $max_width . '!important;';
}
- if (isset($max_height) && strlen($max_height) > 0) {
+ if (!empty($max_height)) {
$style .= 'height:' . $max_height . '!important;overflow-y:auto!important;';
}
if ($options->centered) {
$style .= 'margin:0 auto!important;';
}
- ?><div class="{slg}<?php if ($options->dark_theme) { ?> wp-dark<?php } ?>"<?php if ($style) { ?> style="<?php echo $style;?>"<?php } ?> data-id="<?php echo $feed_id; ?>" data-layout="<?php echo $options->view_mode; ?>" data-exec="false"><?php
+ ?><div class="{slg}<?php if ($options->dark_theme) { ?> wp-dark<?php } ?>"<?php if ($style) { ?> style="<?php echo esc_attr($style);?>"<?php } ?> data-id="<?php echo esc_attr($feed_id); ?>" data-layout="<?php echo esc_attr($options->view_mode); ?>" data-exec="false"><?php
switch ($options->view_mode) {
case 'slider':
$this->render_slider($businesses, $reviews, $options, $is_admin);
@@ -146,7 +146,7 @@
?>
</div>
<?php if ($options->pagination > 0 && $hr) { ?>
- <a class="{slg}-url" href="#" onclick="return TrustReviews.Plugin.next.call(this, '{slg}', <?php echo $options->pagination; ?>);">
+ <a class="{slg}-url" href="#" onclick="return TrustReviews.Plugin.next.call(this, '{slg}', <?php echo (int) $options->pagination; ?>);">
<?php echo __('More Reviews', Plugin::NAME); ?>
</a>
<?php } ?>
@@ -187,7 +187,7 @@
<?php if (!$options->header_hide_photo) { ?>
<img src="<?php echo esc_url($place_img); ?>" class="{slg}-img" alt="<?php echo esc_attr($place->name); ?>" width="50" height="50" title="<?php echo esc_attr($place->name); ?>">
<?php } ?>
- <div class="{slg}-flex" data-platform="<?php echo $place->provider; ?>" style="--dir:column;--gap:8px">
+ <div class="{slg}-flex" data-platform="<?php echo esc_attr($place->provider); ?>" style="--dir:column;--gap:8px">
<?php if (!$options->header_hide_name) { ?>
<div class="{slg}-name">
<?php $place_name_content = '<span>' . $place->name . '</span>';
@@ -235,7 +235,7 @@
}
}
if ($options->pagination > 0 && $hr) { ?>
- <a class="{slg}-url" href="#" onclick="return TrustReviews.Plugin.next.call(this, '{slg}', <?php echo $options->pagination; ?>);">
+ <a class="{slg}-url" href="#" onclick="return TrustReviews.Plugin.next.call(this, '{slg}', <?php echo (int) $options->pagination; ?>);">
<?php echo __('More Reviews', Plugin::NAME); ?>
</a>
<?php
@@ -247,34 +247,25 @@
function place_review($review, $hr, $options, $is_admin = false) {
$addcls = $is_admin && $review->hide != '' ? " wp-review-hidden" : "";
- ?>
- <div class="{slg}-list-review<?php echo $addcls; ?><?php if ($hr) { echo ' {slg}-hide'; } ?>" data-rev="<?php echo $review->provider; ?>">
- <?php if (!$options->hide_avatar) { ?>
- <div class="{slg}-flex" style="--dir:row;--align:star;--gap:12px">
- <?php
- $default_avatar = Plugin::ASSETS_URL() . 'img/guest.png';
- if (strlen($review->author_img) > 0) {
- $author_img = $review->author_img;
- } else {
- $author_img = $default_avatar;
- }
- if (isset($options->reviewer_avatar_size)) {
- $author_img = str_replace('s128', 's' . $options->reviewer_avatar_size, $author_img);
- $default_avatar = str_replace('s128', 's' . $options->reviewer_avatar_size, $default_avatar);
+ ?><div class="{slg}-list-review<?php echo $addcls; ?><?php if ($hr) { echo ' {slg}-hide'; } ?>" data-rev="<?php echo esc_attr($review->provider); ?>">
+ <div class="{slg}-flex" style="--dir:row;--align:star;--gap:12px"><?php
+ if (!$options->hide_avatar) {
+ $default_avatar = Plugin::ASSETS_URL() . 'img/guest.png';
+ $author_img = empty($review->author_img) ? $default_avatar : $review->author_img;
+ if (isset($options->reviewer_avatar_size)) {
+ $author_img = str_replace('s128', 's' . $options->reviewer_avatar_size, $author_img);
+ $default_avatar = str_replace('s128', 's' . $options->reviewer_avatar_size, $default_avatar);
+ }
+ $this->image($author_img, '{slg}-img', $review->author_name, $options->lazy_load_img, $default_avatar);
}
- $this->image($author_img, '{slg}-img', $review->author_name, $options->lazy_load_img, $default_avatar);
- ?>
- <div class="{slg}-flex" style="--dir:column;--align:star;--gap:4px">
+ ?><div class="{slg}-flex" style="--dir:column;--align:star;--gap:4px">
<?php
- if (strlen($review->author_url) > 0) {
- $this->anchor($review->author_url, '{slg}-name', $review->author_name, $options->open_link, $options->nofollow_link);
+ if (empty($review->author_url)) {
+ $author_name = empty($review->author_name) ? __('Google User', Plugin::NAME) : $review->author_name;
+ ?><div class="{slg}-name"><?php echo esc_html($author_name); ?></div><?php
+
} else {
- if (strlen($review->author_name) > 0) {
- $author_name = $review->author_name;
- } else {
- $author_name = __('Google User', Plugin::NAME);
- }
- ?><div class="{slg}-name"><?php echo $author_name; ?></div><?php
+ $this->anchor($review->author_url, '{slg}-name', $review->author_name, $options->open_link, $options->nofollow_link);
}
?>
<div class="{slg}-time" data-time="<?php echo $review->time; ?>"><?php echo esc_html(gmdate("H:i d M y", (int)$review->time)); ?></div>
@@ -284,12 +275,10 @@
</div>
<?php if ($is_admin && !empty($review->id)) {
echo '<a href="#" class="wp-review-hide" data-id=' . $review->id . '>' . ($review->hide == '' ? 'Hide' : 'Show') . ' review</a>';
- } ?>
- </div>
+ }
+ ?></div>
</div>
- <?php } ?>
- </div>
- <?php
+ </div><?php
}
function slider_review($review, $hr, $options, $is_admin = false) {
@@ -297,61 +286,53 @@
$addcls .= $options->show_round ? " {slg}-round" : "";
$addcls .= $options->show_shadow ? " {slg}-shadow" : "";
$addcls .= $is_admin && $review->hide != '' ? " wp-review-hidden" : "";
- ?>
- <div class="{slg}-review<?php if ($hr) { echo ' {slg}-hide'; } ?>" data-rev="<?php echo $review->provider; ?>">
+ ?><div class="{slg}-review<?php if ($hr) { echo ' {slg}-hide'; } ?>" data-rev="<?php echo esc_attr($review->provider); ?>">
<div class="{slg}-review-inner<?php echo $addcls; ?>">
- <div class="{slg}-flex" style="--gap:12px;--dir:row;--align:center">
- <?php
- // Google reviewer avatar
- $default_avatar = Plugin::ASSETS_URL() . 'img/guest.png';
- if (strlen($review->author_img) > 0) {
- $author_img = $review->author_img;
- } else {
- $author_img = $default_avatar;
- }
- if (isset($options->reviewer_avatar_size)) {
- $author_img = str_replace('s128', 's' . $options->reviewer_avatar_size, $author_img);
- $default_avatar = str_replace('s128', 's' . $options->reviewer_avatar_size, $default_avatar);
+ <div class="{slg}-flex" style="--gap:12px;--dir:row;--align:center"><?php
+ if (!$options->hide_avatar) {
+ $default_avatar = Plugin::ASSETS_URL() . 'img/guest.png';
+ $author_img = empty($review->author_img) ? $default_avatar : $review->author_img;
+ if (isset($options->reviewer_avatar_size)) {
+ $author_img = str_replace('s128', 's' . $options->reviewer_avatar_size, $author_img);
+ $default_avatar = str_replace('s128', 's' . $options->reviewer_avatar_size, $default_avatar);
+ }
+ $this->image($author_img, '{slg}-img', $review->author_name, $options->lazy_load_img, $default_avatar);
}
- $this->image($author_img, '{slg}-img', $review->author_name, $options->lazy_load_img, $default_avatar);
?><div class="{slg}-flex" style="--gap:6px;--dir:column;--align:star;--overflow:hidden"><?php
// Google reviewer name
- if (strlen($review->author_url) > 0) {
- $this->anchor($review->author_url, '{slg}-name', $review->author_name, $options->open_link, $options->nofollow_link);
+ if (empty($review->author_url)) {
+ $author_name = empty($review->author_name) ? __('Google User', Plugin::NAME) : $review->author_name;
+ ?><div class="{slg}-name"><?php echo esc_html($author_name); ?></div><?php
} else {
- if (strlen($review->author_name) > 0) {
- $author_name = $review->author_name;
- } else {
- $author_name = __('Google User', Plugin::NAME);
- }
- ?><div class="{slg}-name"><?php echo $author_name; ?></div><?php
+ $this->anchor($review->author_url, '{slg}-name', $review->author_name, $options->open_link, $options->nofollow_link);
}
- ?>
- <div class="{slg}-time" data-time="<?php echo $review->time; ?>"><?php echo esc_html(gmdate("H:i d M y", (int)$review->time)); ?></div>
+ ?><div class="{slg}-time" data-time="<?php echo $review->time; ?>"><?php
+ echo esc_html(gmdate("H:i d M y", (int)$review->time));
+ ?></div>
</div>
- </div>
- <?php echo $this->stars($review->rating, $review->provider); ?>
- <div>
- <div class="{slg}-feedback" <?php if (strlen($options->slider_text_height) > 0) {?> style="height:<?php echo $options->slider_text_height; ?>!important"<?php } ?>>
- <?php if (strlen($review->text) > 0) { ?>
+ </div><?php
+
+ echo $this->stars($review->rating, $review->provider);
+
+ ?><div>
+ <div class="{slg}-feedback" <?php if (!empty($options->slider_text_height)) {?> style="height:<?php echo esc_attr($options->slider_text_height); ?>!important"<?php } ?>>
+ <?php if (!empty($review->text)) { ?>
<span class="{slg}-text"><?php echo $this->trim_text($review->text, $options->text_size); ?></span>
<?php } ?>
</div>
- </div>
- <?php $this->social_logo($review->provider);
+ </div><?php $this->social_logo($review->provider);
if ($is_admin && isset($review->id)) {
echo '<a href="#" class="wp-review-hide" data-id=' . $review->id . '>' . ($review->hide == '' ? 'Hide' : 'Show') . ' review</a>';
- } ?>
- </div>
- </div>
- <?php
+ }
+ ?></div>
+ </div><?php
}
function stars($rating, $provider = '', $show_rating = false) {
switch ($provider) {
case 'facebook':
if ($show_rating) {
- ?><span class="rpi-stars" style="--rating:<?php echo $rating; ?>"><?php echo $rating; ?></span><?php
+ ?><span class="rpi-stars" style="--rating:<?php echo esc_attr($rating); ?>"><?php echo $rating; ?></span><?php
} else {
$text = ($rating < 2 ? "doesn't" : "") . ' recommends';
?><span class="rpi-star-fb" data-rating="<?php echo $rating; ?>"><?php echo $text; ?></span><?php
@@ -364,18 +345,16 @@
?><span class="rpi-stars-<?php echo $provider; ?>"<?php echo $data_atts; ?>><i></i><i></i><i></i><i></i><i></i></span><?php
break;
default:
- ?><span class="rpi-stars" style="--rating:<?php echo $rating; ?>"><?php if ($show_rating) echo $rating; ?></span><?php
+ ?><span class="rpi-stars" style="--rating:<?php echo esc_attr($rating); ?>"><?php if ($show_rating) echo $rating; ?></span><?php
}
}
private function writereview_url($biz) {
switch ($biz->provider) {
- case 'google':
- return 'https://search.google.com/local/writereview?placeid=' . $biz->id;
- case 'facebook':
- return 'https://facebook.com/' . $biz->id . '/reviews';
- case 'yelp':
- return 'https://www.yelp.com/writeareview/biz/' . $biz->id;
+ case 'google': return 'https://search.google.com/local/writereview?placeid=' . $biz->id;
+ case 'facebook': return 'https://facebook.com/' . $biz->id . '/reviews';
+ case 'tripadvisor': return 'https://www.tripadvisor.com/UserReview-d' . $biz->id;
+ case 'yelp': return 'https://www.yelp.com/writeareview/biz/' . $biz->id;
}
}
@@ -405,7 +384,7 @@
}
private function powered($biz, $opt) {
- ?><div class="{slg}-powered {slg}-flex" data-platform="<?php echo $biz->provider; ?>" style="--gap: 2px;--dir:row;--align:center"><?php
+ ?><div class="{slg}-powered {slg}-flex" data-platform="<?php echo esc_attr($biz->provider); ?>" style="--gap: 2px;--dir:row;--align:center"><?php
switch ($biz->provider) {
case 'google':
?><img src="<?php echo Plugin::ASSETS_URL(); ?>img/powered_by_google_on_<?php if ($opt->dark_theme) { ?>non_<?php } ?>white.png" alt="powered by Google" width="144" height="18" title="powered by Google"><?php
@@ -431,12 +410,12 @@
echo '<a href="' . $href . '"' . $class_attr . $target_rel . $rel_attr . '>' . wp_kses_post($text) . '</a>';
}
- function image($src, $cls = '', $alt, $lazy, $def_ava = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', $atts = '') {
+ function image($src, $cls, $alt, $lazy, $def_ava = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', $atts = '') {
?><img src="<?php echo esc_url($src); ?>" <?php if ($lazy) { ?>loading="lazy"<?php } ?> class="<?php echo esc_attr($cls); ?>" alt="<?php echo esc_attr($alt); ?>" onerror="this.onerror=null;this.src='<?php echo esc_url($def_ava); ?>';" <?php echo $atts; ?>><?php
}
function js_loader($cls, $func, $data = '') {
- ?><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="js_loader" onload="(function(el, data) {var f = function() { window.<?php echo $cls; ?> ? <?php echo $cls . '.' . $func; ?>('{slg}', el, data) : setTimeout(f, 400) }; f() })(this<?php if (strlen($data) > 0) { ?>, <?php echo str_replace('"', ''', $data); } ?>);" width="1" height="1" style="display:none"><?php
+ ?><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="js_loader" onload="(function(el, data) {var f = function() { window.<?php echo $cls; ?> ? <?php echo $cls . '.' . $func; ?>('{slg}', el, data) : setTimeout(f, 400) }; f() })(this<?php if (!empty($data)) { ?>, <?php echo str_replace('"', ''', $data); } ?>);" width="1" height="1" style="display:none"><?php
}
function trim_text($text, $size) {
--- a/fb-reviews-widget/includes/core/class-core.php
+++ b/fb-reviews-widget/includes/core/class-core.php
@@ -120,7 +120,7 @@
$result = $this->get_fb_reviews($conn, $options);
break;
default:
- $result = $this->get_db_reviews($conn, $is_admin);
+ $result = $this->get_db_reviews($conn, $options, $is_admin);
}
if (isset($result['business'])) {
array_push($bizs, $result['business']);
@@ -133,7 +133,7 @@
return array('businesses' => $bizs, 'reviews' => $reviews, 'options' => $options);
}
- public function get_db_reviews($biz, $is_admin = false) {
+ public function get_db_reviews($biz, $options, $is_admin = false) {
global $wpdb;
$rating = 0;
@@ -148,98 +148,58 @@
)
);
- if ($place) {
-
- // Get reviews
- $hidden_ids = array();
- $where_plain = $is_admin ? '' : " AND r2.hide = ''";
- $where_r = $is_admin ? '' : " AND r.hide = ''";
-
- if (isset($options->hidden) && !$is_admin) {
- $hidden_ids = $this->parse_hidden_ids($options->hidden);
- if (!empty($hidden_ids)) {
- $hidden_phs = implode(',', array_fill(0, count($hidden_ids), '%d'));
- $where_plain .= ' AND r2.id NOT IN (' . $hidden_phs . ')';
- $where_r .= ' AND r.id NOT IN (' . $hidden_phs . ')';
- }
- }
-
- if (empty($biz->lang)) {
-
- $sql = "SELECT r.*
- FROM {$wpdb->prefix}" . Database::REVIEW_TABLE . " r
- WHERE r.biz_id = %d{$where_r}
- AND r.author_url IS NOT NULL
- AND NOT EXISTS (
- SELECT 1
- FROM {$wpdb->prefix}" . Database::REVIEW_TABLE . " r2
- WHERE r2.biz_id = r.biz_id
- AND r2.author_url = r.author_url{$where_plain}
- AND (
- r2.time > r.time
- OR (r2.time = r.time AND r2.id > r.id)
- )
- )
- ORDER BY r.time DESC, r.id DESC";
-
- $params = array_merge([$place->id], $hidden_ids, $hidden_ids);
-
- } else {
-
- $sql = "SELECT r2.*
- FROM {$wpdb->prefix}" . Database::REVIEW_TABLE . " r2
- WHERE r2.biz_id = %d{$where_plain} AND (r2.language = %s OR r2.language IS NULL)
- ORDER BY r2.time DESC";
+ if (!$place) {
+ return array('reviews' => array());
+ }
- $params = array_merge([$place->id], $hidden_ids);
- $params[] = $biz->lang;
- }
+ $lang = empty($biz->lang) ? substr(get_locale(), 0, 2) : $biz->lang;
+ $all_langs = isset($options->all_langs) ? (int)(bool)$options->all_langs : (empty($biz->lang) ? 1 : 0);
- $revs = $wpdb->get_results($wpdb->prepare($sql, $params));
+ $revs = $this->fetch_reviews([$place->id], $options, $lang, $all_langs, 0, $is_admin);
- // Setup photo
- $place->photo = empty($biz->photo) ? (empty($place->photo) ? Plugin::G_BIZ_LOGO() : $place->photo) : $biz->photo;
+ $place->photo = empty($biz->photo) ? (empty($place->photo) ? Plugin::G_BIZ_LOGO() : $place->photo) : $biz->photo;
- // Calculate reviews count
- if (isset($place->review_count) && $place->review_count > 0) {
- $review_count = $place->review_count;
- } else {
- $review_count = $wpdb->get_var(
- $wpdb->prepare(
- "SELECT count(*) FROM " . $wpdb->prefix . Database::REVIEW_TABLE .
- " WHERE biz_id = %d", $place->id
- )
- );
- }
+ if (isset($place->review_count) && $place->review_count > 0) {
+ $review_count = $place->review_count;
+ } else {
+ $review_count = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT count(*) FROM " . $wpdb->prefix . Database::REVIEW_TABLE .
+ " WHERE biz_id = %d", $place->id
+ )
+ );
+ }
- // Calculate rating
- $rating = 0;
- if ($place->rating > 0) {
- $rating = $place->rating;
- } else if (count($revs) > 0) {
- foreach ($revs as $review) {
- $rating = $rating + $review->rating;
- }
- $rating = round($rating / count($revs), 1);
+ $rating = 0;
+ if ($place->rating > 0) {
+ $rating = $place->rating;
+ } else if (count($revs) > 0) {
+ foreach ($revs as $review) {
+ $rating = $rating + $review->rating;
}
- $rating = number_format((float)$rating, 1, '.', '');
+ $rating = round($rating / count($revs), 1);
}
+ $rating = number_format((float)$rating, 1, '.', '');
$business = json_decode(json_encode(
array(
- 'id' => $biz->id,
- 'name' => $biz->name ? $biz->name : $place->name,
- 'url' => isset($place->url) ? $place->url : null,
- 'photo' => isset($place->photo) ? $place->photo : Plugin::G_BIZ_LOGO(),
- 'address' => isset($place->address) ? $place->address : null,
- 'rating' => $rating,
- 'review_count' => $review_count,
- 'provider' => $place->platform
+ 'id' => $biz->id,
+ 'name' => $biz->name ? $biz->name : $place->name,
+ 'url' => isset($place->url) ? $place->url : null,
+ 'photo' => isset($place->photo) ? $place->photo : Plugin::G_BIZ_LOGO(),
+ 'address' => isset($place->address) ? $place->address : null,
+ 'rating' => $rating,
+ 'review_count' => $review_count,
+ 'provider' => $place->platform
)
));
$reviews = array();
foreach ($revs as $rev) {
+ $text = (isset($rev->lang_text) && $rev->lang_text !== null && $rev->lang_text !== '')
+ ? $rev->lang_text
+ : $rev->text;
+
$review = json_decode(json_encode(
array(
'id' => $rev->id,
@@ -247,7 +207,7 @@
'biz_id' => $biz->id,
'biz_url' => $place->url,
'rating' => $rev->rating,
- 'text' => wp_encode_emoji($rev->text),
+ 'text' => wp_encode_emoji($text),
'author_img' => $rev->author_img,
'author_url' => $rev->author_url,
'author_name' => $rev->author_name,
@@ -261,6 +221,97 @@
return array('business' => $business, 'reviews' => $reviews);
}
+ private function fetch_reviews($place_ids, $options, $lang, $all_langs, $limit, $is_admin) {
+ global $wpdb;
+
+ $where_plain = $is_admin ? '' : " AND r2.hide = ''";
+ $where_r = $is_admin ? '' : " AND r.hide = ''";
+
+ $hidden_ids = array();
+ if (isset($options->hidden) && !$is_admin) {
+ $hidden_ids = $this->parse_hidden_ids($options->hidden);
+ if (!empty($hidden_ids)) {
+ $hidden_phs = implode(',', array_fill(0, count($hidden_ids), '%d'));
+ $where_plain .= ' AND r2.id NOT IN (' . $hidden_phs . ')';
+ $where_r .= ' AND r.id NOT IN (' . $hidden_phs . ')';
+ }
+ }
+
+ if (!is_array($place_ids)) {
+ $place_ids = [$place_ids];
+ }
+ $place_ids_phs = implode(',', array_fill(0, count($place_ids), '%d'));
+
+ $lang_aliases = $this->get_lang_aliases($lang);
+ $lang_phs = implode(',', array_fill(0, count($lang_aliases), '%s'));
+
+ $sql = "SELECT r.*, t.text AS lang_text
+ FROM {$wpdb->prefix}" . Database::REVIEW_TABLE . " r
+ LEFT JOIN {$wpdb->prefix}" . Database::TEXT_TABLE . " t
+ ON t.review_id = r.review_id AND t.lang IN ({$lang_phs})
+ WHERE r.biz_id IN ({$place_ids_phs}){$where_r}
+ AND (%d = 1 OR t.text IS NOT NULL OR r.language IN ({$lang_phs}) OR r.language IS NULL OR r.language = '')
+ AND (
+ r.author_url IS NULL OR r.author_url = ''
+ OR NOT EXISTS (
+ SELECT 1 FROM {$wpdb->prefix}" . Database::REVIEW_TABLE . " r2
+ WHERE r2.biz_id = r.biz_id AND r2.author_url = r.author_url{$where_plain}
+ AND (r2.time > r.time OR (r2.time = r.time AND r2.id > r.id))
+ )
+ )
+ ORDER BY r.time DESC, r.id DESC";
+
+ if ($limit > 0) {
+ $sql .= " LIMIT " . (int)$limit;
+ }
+
+ $params = array_merge(
+ $lang_aliases, // t.lang IN (...) [LEFT JOIN]
+ $place_ids, // r.biz_id IN (...)
+ $hidden_ids, // {$where_r}
+ [$all_langs], // %d = 1
+ $lang_aliases, // r.language IN (...)
+ $hidden_ids // {$where_plain} [NOT EXISTS]
+ );
+
+ return $wpdb->get_results($wpdb->prepare($sql, $params));
+ }
+
+ private function get_lang_aliases($lang) {
+ $key = strtolower(str_replace('_', '-', trim((string)$lang)));
+ $traditional = array('zh-TW', 'zh-HK', 'zh-MO', 'zh-Hant', 'zh-Hant-TW', 'zh-Hant-HK', 'zh-Hant-MO');
+ $simplified = array('zh', 'zh-CN', 'zh-SG', 'zh-Hans', 'zh-Hans-CN', 'zh-Hans-SG');
+ if (in_array($key, array_map('strtolower', $traditional), true)) {
+ return array_merge($traditional, array('zh'));
+ }
+ if (in_array($key, array_map('strtolower', $simplified), true)) {
+ return $simplified;
+ }
+ return array($lang);
+ }
+
+ private function parse_hidden_ids($input) {
+ $ids = array();
+ if (empty($input)) {
+ return $ids;
+ }
+ if (is_string($input)) {
+ $parts = preg_split('/s*,s*/', $input, -1, PREG_SPLIT_NO_EMPTY);
+ } elseif (is_array($input)) {
+ $parts = $input;
+ } else {
+ return $ids;
+ }
+ foreach ($parts as $p) {
+ $val = intval($p);
+ if ($val > 0) {
+ $ids[] = $val;
+ }
+ }
+ $ids = array_values(array_unique($ids));
+ return $ids;
+ }
+
public function get_fb_reviews($biz, $opts, $zzz = true) {
global $wpdb;
--- a/fb-reviews-widget/includes/core/class-google-dao.php
+++ b/fb-reviews-widget/includes/core/class-google-dao.php
@@ -55,12 +55,7 @@
);
}
- $review_lang = null;
- if (isset($review->language)) {
- $review_lang = ($review->language == 'en-US' ? 'en' : $review->language);
- }
-
- $db_review_id = empty($db_review_id) ? $this->old_review_id($db_biz_id, $review, $review_lang) : $db_review_id;
+ $db_review_id = empty($db_review_id) ? $this->old_review_id($db_biz_id, $review) : $db_review_id;
$author_img = null;
if (isset($review->author_img)) {
@@ -94,6 +89,11 @@
$reply_time = $review->reply_time;
}
+ $review_lang = null;
+ if (isset($review->language)) {
+ $review_lang = ($review->language == 'en-US' ? 'en' : $review->language);
+ }
+
if ($db_review_id) {
$this->update_review($place->pid, $review, $review_lang, $author_img, $images, $reply, $reply_time, $db_review_id, $log);
} else {
@@ -106,40 +106,31 @@
update_option('grw_save_log', implode('_', $log));
}
- private function old_review_id($db_biz_id, $review, $lang) {
+ private function old_review_id($db_biz_id, $review) {
global $wpdb;
$where = " WHERE";
$where_params = array();
- if (!empty($review->provider)) {
- $where .= " platform = %s AND";
- array_push($where_params, $review->provider);
- }
-
if (!empty($review->author_url)) {
$where .= " author_url = %s";
array_push($where_params, $review->author_url);
} else {
- $where .= " time = %s";
- array_push($where_params, $review->time);
+ $where .= " time = %d";
+ array_push($where_params, $this->review_time($review));
+
if (!empty($review->author_name)) {
$where .= " AND author_name = %s";
array_push($where_params, $review->author_name);
}
}
- if (!empty($lang)) {
- $where .= " AND language = %s";
- array_push($where_params, $lang);
- }
-
if ($db_biz_id) {
$where .= " AND biz_id = %d";
array_push($where_params, $db_biz_id);
}
- $sql = "SELECT id FROM " . $wpdb->prefix . Database::REVIEW_TABLE . $where/* . " ORDER BY id DESC LIMIT 1"*/;
+ $sql = "SELECT id FROM " . $wpdb->prefix . Database::REVIEW_TABLE . $where . " ORDER BY time DESC, id DESC LIMIT 1";
return $wpdb->get_var($wpdb->prepare($sql, $where_params));
}
@@ -335,7 +326,13 @@
private function upsert_review_text($pid, $review, $lang) {
global $wpdb;
- if (empty($lang)) return;
+ $lang = trim((string)$lang);
+ $lang_key = strtolower($lang);
+
+ if ($lang === '' || $lang_key === 'undefined' || $lang_key === 'null') {
+ return;
+ }
+
if (!isset($review->text) || $review->text === '') return;
if (empty($review_id = $this->review_id($pid, $review))) return;
@@ -360,6 +357,17 @@
);
}
+ private function review_time($review) {
+ if (!empty($review->time)) return (int)$review->time;
+
+ if (!empty($review->time_str)) {
+ $ts = strtotime($review->time_str);
+ if ($ts) return (int)$ts;
+ }
+
+ return 0;
+ }
+
private function log_last_error($wpdb) {
if (!empty($wpdb->last_error)) {
$last_error = $wpdb->last_error;