Join the Voxel Guide Community!

Get Involved

Shortcode to display common words from reviews

Description/Instructions

This code will create a shortcode to display common words from user reviews.  Just add the shortcode to your template (I recommend just above your post’s timeline) .

The code processes each review separately and tallies only unique words per review. In other words, if a word appears multiple times within one review, it’s only counted once for that review. This will yield common words across all reviews rather than repeated counts from individual reviews.

Additionally, we count unigrams and bigrams separately. Then—if a bigram is present (i.e. appears in more than one review) we remove its component unigrams from the final merged output so that you don’t see both “great”, “great” and “great restaurant.”

The shortcode will display up to 10 common words (across all reviews for that post) that have been mentioned in more than one review. 

You can manually set the limit of common words.  Also, there is already an array of common stop words to exclude which you can modify or add to.

 

Instructions

Add the code below in Voxel's child theme functions.php file or use a Code Snippets plugin:

Then place the shortcode in the page template using the shortcode widget:

[common_review_words limit="15"]

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

function voxel_common_review_words_shortcode( $atts ) {
global $wpdb, $post;

// Set default shortcode attributes.
$atts = shortcode_atts(
[
'limit' => 10, // Maximum number of phrases to display.
],
$atts,
'common_review_words'
);

// Use the provided post_id or fallback to the current post.
$post_id = ! empty( $atts['post_id'] )
? intval( $atts['post_id'] )
: ( isset( $post->ID ) ? $post->ID : 0 );

// Prepare the query to fetch reviews.
$table_name = $wpdb->prefix . 'voxel_timeline';
$query      = "SELECT content FROM $table_name WHERE details LIKE '%\"rating\":%'";
if ( $post_id ) {
$query .= " AND post_id = $post_id";
}
$results = $wpdb->get_results( $query );

// We count each unigram and bigram once per review.
$unigram_counts = [];
$bigram_counts  = [];

// Define an array of common stop words to exclude.
$stop_words = [
'the', 'and', 'a', 'an', 'to', 'of', 'in', 'it', 'is',
'that', 'this', 'i', 'for', 'on', 'with', 'as', 'was',
'but', 'are', 'be', 'by', 'not', 'have', 'had', 'or', 'at',
'from', 'you', 'your', 'they', 'we', 'which'
];

// Process each review.
foreach ( $results as $result ) {
// Normalize review content.
$content = strtolower( strip_tags( $result->content ) );
// Remove punctuation (only allow letters, numbers, and whitespace).
$content = preg_replace( "/[^\w\s]/", '', $content );
// Split content into words.
$words = preg_split( '/\s+/', $content, -1, PREG_SPLIT_NO_EMPTY );
// Filter out stop words.
$filtered = array_filter( $words, function( $word ) use ( $stop_words ) {
return ! in_array( $word, $stop_words, true );
});
$filtered = array_values( $filtered ); // reindex

// Get unique unigrams for this review.
$unique_unigrams = array_unique( $filtered );

// Tally each unique unigram.
foreach ( $unique_unigrams as $uni ) {
if ( ! isset( $unigram_counts[ $uni ] ) ) {
$unigram_counts[ $uni ] = 0;
}
$unigram_counts[ $uni ]++;
}

// Generate bigrams (two-word phrases) from the filtered words.
$bigrams = [];
$count_words = count( $filtered );
for ( $i = 0; $i < $count_words - 1; $i++ ) {
$bigram = $filtered[$i] . ' ' . $filtered[$i + 1];
$bigrams[] = $bigram;
}
// Get unique bigrams for this review.
$unique_bigrams = array_unique( $bigrams );

// Tally each unique bigram.
foreach ( $unique_bigrams as $bi ) {
if ( ! isset( $bigram_counts[ $bi ] ) ) {
$bigram_counts[ $bi ] = 0;
}
$bigram_counts[ $bi ]++;
}
}

// Filter out phrases that appear in only one review.
$unigram_counts = array_filter( $unigram_counts, function( $count ) {
return $count > 1;
});
$bigram_counts  = array_filter( $bigram_counts, function( $count ) {
return $count > 1;
});

// Remove unigrams that are part of any bigram in our final list.
// Loop through each bigram and remove its component words from unigrams.
foreach ( $bigram_counts as $bigram => $bcount ) {
$parts = explode( ' ', $bigram );
foreach ( $parts as $part ) {
if ( isset( $unigram_counts[ $part ] ) ) {
unset( $unigram_counts[ $part ] );
}
}
}

// Merge bigrams and unigrams.
$merged = array_merge( $unigram_counts, $bigram_counts );

// Sort by frequency in descending order.
arsort( $merged );

// Limit to the specified count.
$merged = array_slice( $merged, 0, intval( $atts['limit'] ), true );

// Build the output using tags inside a

.
$output = '

';
foreach ( $merged as $phrase => $count ) {
$output .= '' . esc_html( $phrase ) . ' ';
}
$output .= '

';

return $output;
}
add_shortcode( 'common_review_words', 'voxel_common_review_words_shortcode' );

 

  • PHP
Copy Code

Instructions

Add the CSS code to your Child Theme or in the Custom CSS area of the container: (style it as needed)

.common-review-words {
display: flex;
gap: 5px;
overflow-y: auto;
flex-direction: row;
justify-content: flex-start;
align-items: center;
padding-left: 10px;
}
.common-review-words span {
font-size:0.775rem;
padding: 5px 20px 5px 20px;
border-radius: 90px;
border-style: solid;
border-width: 1px 1px 1px 1px;
border-color: #DEDEDE;
white-space: nowrap;
display:inline-flex;
}
.common-review-words:before{
content: '';
position: absolute;
bottom: 0;
left:0;
background: linear-gradient(to left, transparent, white);
height: 100%;
width: 15px;
}
.common-review-words:after{
content: '';
position: absolute;
bottom: 0;
right:0;
background: linear-gradient(to right, transparent, white);
height: 100%;
width: 20px;
}

  • CSS
Copy Code

Let's Chat About this Snippet

Chat Toggle
Voxel Guide AI
Voxel Guide AI
Voxel Guide AI
Voxel Guide AI
Ask me anything about Voxel!
Send
Powered by AI24