aliexpress_loader = $AliexpressModel; $this->attachment_model = $AttachmentModel; $this->helper = $Helper; //todo: in the very old plugin version we used "review_allow_country" option //need to do the code to remove it completely because now we use another option "review_country" $this->allowed_countries = get_setting('review_country'); $this->review_translated = get_setting('review_translated'); $this->review_load_attributes = get_setting('review_load_attributes'); $this->raiting_from = intval(get_setting('review_raiting_from', 1)); $this->raiting_to = intval(get_setting('review_raiting_to', 5)); $tmp = intval(get_setting('review_max_per_product')); $this->max_number_reviews_per_product = ($tmp > 0) ? $tmp : 20; $tmp = intval(get_setting('review_min_per_product')); $this->min_number_reviews_per_product = ($tmp > 0) ? $tmp : $this->max_number_reviews_per_product; } /** * Get reviews and save them in Woocommerce */ public function load(int $post_id, bool $force_clean = false, array $params = []): ?array { global $wpdb; $step = $params['step'] ?? false; $external_id = get_post_meta($post_id, "_a2w_external_id", true); if (!$external_id) { return null; } $new_steps = []; if ($step === false || $step === 'reviews') { $comment_number = get_comments( [ 'post_id' => $post_id, 'meta_key' => 'rating', 'count' => true ] ); $max_number_reviews_per_product = $this->get_max_reviews_number_by_product($post_id); $remaining_comment_number = $max_number_reviews_per_product - $comment_number; if ($remaining_comment_number > 0) { $pageNumber = intval(get_post_meta($post_id, '_a2w_review_page', true)); $pageNumber = ($pageNumber > 0) ? $pageNumber : 1; $res = $this->aliexpress_loader->load_reviews($external_id, $pageNumber, 100); if ($res['state'] !== 'error' && !empty($res['reviews'])) { //remove these meta fields from the post to recalculate review values for the product delete_post_meta($post_id, '_wc_average_rating'); delete_post_meta($post_id, '_wc_review_count'); delete_post_meta($post_id, '_wc_rating_count'); WC_Comments::clear_transients($post_id); $nextPageNumber = ($remaining_comment_number < count($res['reviews'])) ? $pageNumber : ($pageNumber + 1); $added_review_cash = []; foreach ($res['reviews'] as $item) { if ($remaining_comment_number === 0) { break; } $rating = intval($item['review']['reviewStarts']); if ($rating < $this->raiting_from || $rating > $this->raiting_to) { continue; } if (!$this->check_review_country($item)) { continue; } $review_cache = md5( $post_id . $external_id . ($item['buyer']['buyerTitle'] ?? '') . ($item['review']['reviewContent'] ?? '') . ($item['review']['itemSpecInfo'] ?? '') . ($item['review']['itemLogistics'] ?? '') ); $queryTemplate = "SELECT count(c.comment_ID) FROM {$wpdb->comments} c " . "LEFT JOIN {$wpdb->commentmeta} cm " . "ON (c.comment_ID = cm.comment_id and cm.meta_key='a2wl_cash') " . "WHERE cm.meta_value=%s"; $has_same_comment = $wpdb->get_var($wpdb->prepare($queryTemplate, $review_cache)) > 0; if ($has_same_comment || !empty($added_review_cash[$review_cache])) { continue; } $tmp_text = ($this->review_translated && isset($item['review']['translation']['reviewContent'])) ? $item['review']['translation']['reviewContent'] : ($item['review']['reviewContent'] ?? ""); $tmp_text = trim(str_replace("\\u0000", '', $tmp_text)); if ($this->review_load_attributes && isset($item['review']['itemSpecInfo'])) { $tmp_text = $tmp_text . "

" . preg_replace('#([\w\-]+:)#', '$1', str_replace(':', ': ', PhraseFilter::apply_filter_to_text($item['review']['itemSpecInfo']))); } $maybe_skip_review = $this->maybe_skip_review($tmp_text); if ($maybe_skip_review) { continue; } $review_text = PhraseFilter::apply_filter_to_text($tmp_text); $author = PhraseFilter::apply_filter_to_text($item['buyer']['buyerTitle']); $date = gmdate('Y-m-d H:i:s', strtotime($item['review']['reviewDate'])); $comment_approved = get_setting('moderation_reviews') ? 0 : 1; $data = [ 'comment_post_ID' => $post_id, 'comment_author' => $author, 'comment_author_email' => '', 'comment_author_url' => '', 'comment_content' => wp_slash($review_text), 'comment_agent' =>'', 'comment_date' => $date, 'comment_date_gmt' => $date, 'comment_parent' => 0, 'comment_type' => 'review', 'comment_approved' => $comment_approved, ]; $comment_id = wp_insert_comment($data); add_comment_meta($comment_id, 'rating', (int) esc_attr($rating), true); add_comment_meta($comment_id, 'a2wl_cash', $review_cache, true); add_comment_meta($comment_id, 'a2wl_country', $item['buyer']['buyerCountry'], true); if ($step === false) { // if this is one thread import, then load images if (get_setting('review_avatar_import')) { $author_photo = $item['buyer']['buyerImage'] ?? false; if ($author_photo !== false) { $author_photo = $this->helper->image_http_to_https($author_photo); $photo_id = $this->attachment_model->create_attachment($comment_id, $author_photo); if ($photo_id) { add_comment_meta($comment_id, 'a2wl_avatar', $photo_id, true); } } } $photo_ids = []; if (get_setting('review_show_image_list')) { $photo_list = !empty($item['review']['reviewImages']) ? (is_array($item['review']['reviewImages']) ? $item['review']['reviewImages'] : [$item['review']['reviewImages']]) : []; foreach ($photo_list as $photo) { $photo = $this->helper->image_http_to_https($photo); if ($photo_id = $this->attachment_model->create_attachment( $post_id, $photo, ['inner_post_id' => $post_id, 'inner_attach_type' => 'comment']) ) { $photo_ids[] = $photo_id; } } if ($photo_ids) { add_comment_meta($comment_id, 'a2wl_photo_list', $photo_ids, true); } } } else { // step by step flow. Prepare steps. if (get_setting('review_avatar_import')) { $author_photo = $item['buyer']['buyerImage'] ?? false; if ($author_photo) { $author_photo = $this->helper->image_http_to_https($author_photo); $new_steps[] = "reviews#avatar#".$comment_id."#".$author_photo; } } if (get_setting('review_show_image_list')) { $photo_list = !empty($item['review']['reviewImages']) ? (is_array($item['review']['reviewImages']) ? $item['review']['reviewImages'] : [$item['review']['reviewImages']]) : []; foreach ($photo_list as $photo) { $photo = $this->helper->image_http_to_https($photo); $new_steps[] = "reviews#photo#".$comment_id."#".$photo; } } } $added_review_cash[$review_cache] = $review_cache; $remaining_comment_number--; } if ($remaining_comment_number === 0) { update_post_meta($post_id, '_a2w_reviews_last_update', time() + WEEK_IN_SECONDS); update_post_meta($post_id, '_a2w_review_page', 1); } else { update_post_meta($post_id, '_a2w_reviews_last_update', time()); update_post_meta($post_id, '_a2w_review_page', $nextPageNumber); } } else { if (!empty($res['message'])) { a2wl_error_log('load_reviews error: ' . $res['message']); } update_post_meta($post_id, '_a2w_reviews_last_update', time() + WEEK_IN_SECONDS); update_post_meta($post_id, '_a2w_review_page', 1); } } //make sure that post comment status is 'open' $post_arr = [ 'ID' => $post_id, 'comment_status'=>'open' ]; wp_update_post($post_arr); if ($force_clean) { WC_Comments::clear_transients($post_id); } } if (str_starts_with($step, 'reviews#avatar')) { $parts = explode('#', $step, 4); if(count($parts)==4){ $comment_id = $parts[2]; $photo = $parts[3]; $photo_id = $this->attachment_model->create_attachment($comment_id, $photo); if ($photo_id) { add_comment_meta($comment_id, 'a2wl_avatar', $photo_id, true); } } } if (str_starts_with($step, 'reviews#photo')) { $parts = explode('#', $step, 4); if (count($parts) == 4) { $comment_id = $parts[2]; $photo = $parts[3]; $photo_id = $this->attachment_model->create_attachment($post_id, $photo, [ 'inner_post_id' => $post_id, 'inner_attach_type' => 'comment' ] ); if ($photo_id) { $photo_ids = get_comment_meta($comment_id, 'a2wl_photo_list', true); if ($photo_ids) { $photo_ids[] = $photo_id; update_comment_meta($comment_id, 'a2wl_photo_list', $photo_ids); } else { $photo_ids = [ $photo_id ]; add_comment_meta($comment_id, 'a2wl_photo_list', $photo_ids, true); } } } } return ResultBuilder::buildOk(['new_steps' => $new_steps]); } public function get_max_reviews_number_by_product($post_id){ $result = get_post_meta( $post_id, Constants::product_reviews_max_number_meta(), true); if (!$result){ $result = wp_rand( $this->max_number_reviews_per_product, $this->min_number_reviews_per_product ); update_post_meta( $post_id, Constants::product_reviews_max_number_meta(), $result ); } return $result; } public function maybe_skip_review($text){ if (get_setting('review_skip_empty') && empty($text)) { return true; } $keywords_str = trim(trim(get_setting('review_skip_keywords')),','); if ($keywords_str) { $keywords = array_map('trim', explode(',', $keywords_str)); return $this->found_keywords($keywords, $text); } return false; } private function found_keywords($keywords, $text) { return array_reduce($keywords, function ($match_found, $keyword) use ($text) { return $match_found || $this->found_keyword($keyword, $text); }, FALSE); } private function found_keyword($keyword, $text) { $keyword = trim($keyword); return preg_match('/\b' . preg_quote($keyword) . '\b/iu', $text); } private function check_review_country($item) { if (empty($this->allowed_countries)){ return true; } $review_country = strtoupper($item['buyer']['buyerCountry']); if (array_search($review_country, $this->allowed_countries) !== false){ return true; } return false; } public static function get_all_review_ids() { global $wpdb; $comments = $wpdb->get_results("SELECT cm.comment_id as comment_id FROM {$wpdb->commentmeta} cm WHERE cm.meta_key = 'a2wl_country'"); return $comments; } public static function get_product_review_ids($id) { global $wpdb; $comments = $wpdb->get_results("SELECT c.comment_ID as comment_id FROM {$wpdb->comments} c WHERE c.comment_post_ID = " . intval($id)); return $comments; } public static function remove_reviews_by_ids($comments) { $comments_count = count($comments); if ($comments_count > 0) { $comment_ids = ''; for ($i = 0; $i <= $comments_count - 1; $i++) { $comment_ids .= $comments[$i]->comment_id; if ($i < $comments_count - 1) $comment_ids .= ','; } global $wpdb; //delete reviews // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $query_result = $wpdb->query("DELETE FROM {$wpdb->comments} WHERE comment_ID IN ($comment_ids)"); //delete reviews meta // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $query_result = $wpdb->query("DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN ($comment_ids)"); //delete product meta related with review $query_result = $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_a2w_reviews_last_update' OR meta_key = '_a2w_review_page' OR meta_key = '_wc_average_rating'"); //reset review count meta in posts $query_result = $wpdb->query("UPDATE {$wpdb->postmeta} SET meta_value = 0 WHERE meta_key = '_wc_review_count'"); WC_Comments::delete_comments_count_cache(); } } public static function get_comment_photos($comment_id) { $photos = array(); if ($photos_meta = get_comment_meta($comment_id, 'a2wl_photo_list', true)) { if (is_array($photos_meta)) { foreach ($photos_meta as $photo_id) { $full_img = wp_get_attachment_image_src($photo_id, 'full'); if ($full_img) { $thumb_img = wp_get_attachment_image_src($photo_id, 'thumbnail'); $photos[] = array('image' => $full_img[0], 'thumb' => $thumb_img ? $thumb_img[0] : $full_img[0], 'photo_id' => $photo_id); } } } else { $photos = json_decode($photos_meta); } } return $photos; } public static function save_comment_photos($comment_id, $photo_list): void { update_comment_meta($comment_id, 'a2wl_photo_list', $photo_list); } public static function clear_all_product_max_number_review_meta(){ global $wpdb; $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE meta_key=%s", Constants::product_reviews_max_number_meta() ) ); } }