Product Review Posts Are Different

A product review post is not a regular blog post. It needs structured data that Google can parse into rich snippets (star ratings in search results), comparison elements that help readers make decisions, and affiliate links that need to be tracked and managed. JekCMS handles all of this through custom fields and shortcodes without any plugins.

Rating System

We use a simple 1-5 star rating stored as a custom field on the post. The rating renders as both visual stars and structured data:

// Custom field: rating (decimal 1.0 - 5.0)
// Stored in post_meta table
$rating = get_post_meta($post['id'], 'rating');

// Visual display
function render_stars(float $rating): string {
    $html = '<div class="star-rating" aria-label="' . $rating . ' out of 5 stars">';
    for ($i = 1; $i <= 5; $i++) {
        if ($i <= floor($rating)) {
            $html .= '<span class="star filled">&#9733;</span>';
        } elseif ($i - $rating < 1) {
            $html .= '<span class="star half">&#9733;</span>';
        } else {
            $html .= '<span class="star empty">&#9734;</span>';
        }
    }
    return $html . '</div>';
}

Pros and Cons Shortcode

// Usage: [proscons pros="Fast,Affordable,Easy setup" cons="Limited themes,No plugin system"]
Shortcode::register('proscons', function($attrs) {
    $pros = array_filter(explode(',', $attrs['pros'] ?? ''));
    $cons = array_filter(explode(',', $attrs['cons'] ?? ''));

    $html = '<div class="pros-cons">';
    $html .= '<div class="pros"><h4>Pros</h4><ul>';
    foreach ($pros as $pro) {
        $html .= '<li>&#10004; ' . htmlspecialchars(trim($pro)) . '</li>';
    }
    $html .= '</ul></div>';
    $html .= '<div class="cons"><h4>Cons</h4><ul>';
    foreach ($cons as $con) {
        $html .= '<li>&#10006; ' . htmlspecialchars(trim($con)) . '</li>';
    }
    return $html . '</ul></div></div>';
});

Product Schema Markup

Google displays star ratings in search results when Product schema is present. We add it automatically for posts tagged with the "review" category:

{
    "@type": "Product",
    "name": "Product Name",
    "review": {
        "@type": "Review",
        "author": {"@type": "Person", "name": "JekCMS Team"},
        "reviewRating": {
            "@type": "Rating",
            "ratingValue": "4.5",
            "bestRating": "5"
        }
    }
}

The star rating in Google search results increases CTR by 15-30% based on our measurements across review posts.

Affiliate Link Management

Affiliate links are stored in a simple affiliate_links table: product name, merchant (Amazon, Trendyol), URL, and tracking code. We use a redirect through our domain (/go/product-slug) to maintain control — if a merchant changes their URL structure, we update one record instead of finding every post that links to them.

Each redirect is tracked in a link_clicks table with timestamp, referrer, and user agent. This gives us conversion analytics without relying on the merchant's sometimes-delayed reporting.