$cached_code,
'i18n' => array(
'videoLoadError' => __('Napaka pri nalaganju videa. Poskusite znova.', 'aboutbuzz-stories-embed'),
'alreadyLiked' => __('Že ste označili kot uporabno', 'aboutbuzz-stories-embed'),
'voteError' => __('Napaka pri glasovanju. Poskusite znova.', 'aboutbuzz-stories-embed'),
'voteErrorPrefix' => __('Napaka pri glasovanju:', 'aboutbuzz-stories-embed'),
),
)
);
}
add_action('wp_enqueue_scripts', 'aboutbuzz_enqueue_assets');
// === Admin Menu ===
function aboutbuzz_activation_menu() {
add_options_page(
'AboutBuzz Activation',
'AboutBuzz Activation',
'manage_options',
'aboutbuzz-activation',
'aboutbuzz_activation_page'
);
}
add_action('admin_menu', 'aboutbuzz_activation_menu');
function aboutbuzz_activation_page() {
if (!current_user_can('manage_options')) {
wp_die('Unauthorized user');
}
?>
AboutBuzz Activation
For setup or help, please contact
info@aboutbuzz.com
and visit
aboutbuzz.com.
If you are subscribed to an AboutBuzz plan, you will find your setup instructions directly inside your client dashboard area on AboutBuzz.com.
Loading...'
);
}
function aboutbuzz_is_mobile() {
return wp_is_mobile() || (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i', sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT']))));
}
function aboutbuzz_get_user_identifier() {
$user_id = get_current_user_id();
if ($user_id) {
return 'user_' . $user_id;
}
$ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : 'unknown';
return 'anon_' . md5($ip . NONCE_SALT);
}
function aboutbuzz_get_detailed_error($response_code, $response_body) {
switch ($response_code) {
case 401:
return 'Invalid secret code. Please check your activation settings.';
case 403:
return 'Access forbidden. Your secret code may be expired.';
case 404:
return 'Brand not found. Please check your activation code.';
case 429:
return '';
case 500:
return 'Server error. Please try again later.';
default:
$data = json_decode($response_body, true);
if (isset($data['message'])) {
return 'API Error: ' . $data['message'];
}
return 'Unknown API error (Code: ' . $response_code . ')';
}
}
function aboutbuzz_render_stars($rating) {
$rating = max(0, min(5, intval($rating)));
$path = 'M 189.410156 10.039062 L 229.1875 90.308594 C 230.976562 94.25 234.921875 97.117188 239.21875 97.476562 L 328.089844 110.375 C 338.84375 112.167969 343.5 125.425781 335.617188 133.3125 L 271.113281 195.664062 C 267.886719 198.890625 266.453125 203.191406 267.171875 207.488281 L 282.222656 295.644531 C 284.015625 306.394531 272.546875 314.996094 262.871094 309.621094 L 183.675781 268.050781 C 179.734375 265.902344 175.074219 265.902344 171.132812 268.050781 L 91.9375 309.980469 C 82.261719 314.996094 70.792969 306.753906 72.585938 296.003906 L 87.636719 207.847656 C 88.355469 203.546875 86.921875 199.246094 83.695312 196.023438 L 19.550781 133.3125 C 11.667969 125.425781 15.96875 112.167969 27.074219 110.375 L 115.945312 97.476562 C 120.246094 96.757812 124.1875 94.25 125.980469 90.308594 L 165.398438 10.039062 C 170.417969 0.00390625 184.390625 0.00390625 189.410156 10.039062 Z';
$out = '';
for ($i = 1; $i <= 5; $i++) {
$filled = $i <= $rating;
$class = 'aboutbutzz-star-icon aboutbutzz-star-size aboutbutzz-star-' . ($filled ? 'filled' : 'empty');
$out .= '';
}
return $out;
}
function aboutbuzz_get_source_badge_url($value) {
if (!is_string($value) || $value === '') {
return [];
}
$trimmed = ltrim($value);
if (strpos($trimmed, 'Verified Purchase') === 0) {
return [
'url' => plugin_dir_url(__FILE__) . 'assets/icons/badge-verified-purchase.png',
'alt' => 'Authentic Verified Purchase',
];
}
if (strpos($trimmed, 'Verified Tester') === 0) {
return [
'url' => plugin_dir_url(__FILE__) . 'assets/icons/badge-verified-tester.png',
'alt' => 'Authentic Verified Tester',
];
}
return [];
}
// === Shortcode - Uses ONLY /v1/stories/by-code ===
function aboutbuzz_smart_brand_stories_shortcode($atts) {
$atts = shortcode_atts(['code' => ''], $atts);
$activation_code = !empty($atts['code']) ? sanitize_text_field($atts['code']) : '';
if (empty($activation_code)) {
return 'Activation code required in shortcode: [aboutbuzz_reviews code="ABZ-XXXX-XXXX"]
';
}
if (strlen($activation_code) > 255) {
return 'Invalid activation code format.
';
}
if (!empty($activation_code)) {
update_option('aboutbuzz_activation_code_cache', $activation_code);
}
$cache_key = 'aboutbuzz_stories_bycode_' . md5($activation_code);
$admin_nocache = isset($_GET['abz_nocache']) && current_user_can('manage_options');
$cached_body = $admin_nocache ? false : get_transient($cache_key);
$from_cache = ($cached_body !== false);
// Migration guard: earlier builds cached the raw JSON response body as a
// string. This build caches the sanitized $sanitized_posts array so unused
// fields from the server never land in wp_options. Discard legacy strings.
if ($from_cache && is_string($cached_body)) {
$from_cache = false;
delete_transient($cache_key);
$cached_body = false;
}
$sanitized_posts = ($from_cache && is_array($cached_body)) ? $cached_body : [];
if (!$from_cache) {
$api_rate_limit_key = 'aboutbuzz_api_rate_' . aboutbuzz_get_user_identifier();
$api_rate_count = get_transient($api_rate_limit_key);
if ($api_rate_count && $api_rate_count >= 60) {
if (current_user_can('manage_options')) {
return 'AboutBuzz: API rate limit reached (>60 uncached requests/hour). Visible to admins only. Non-admin visitors see no output.
';
}
return '';
}
$response = wp_remote_post('https://aboutbuzz.com/wp-json/aboutbuzz/v1/stories/by-code', [
'timeout' => 10,
'headers' => [
'Content-Type' => 'application/json',
'User-Agent' => 'AboutBuzz-WordPress-Plugin/' . ABOUTBUZZ_EMBED_VERSION,
'Accept' => 'application/json',
],
'body' => wp_json_encode(['code' => $activation_code]),
'sslverify' => true,
]);
$new_api_count = $api_rate_count ? $api_rate_count + 1 : 1;
set_transient($api_rate_limit_key, $new_api_count, 3600);
if (is_wp_error($response)) {
if (current_user_can('manage_options')) {
return 'AboutBuzz: network error fetching stories: ' . esc_html($response->get_error_message()) . ' — visible to admins only.
';
}
return '';
}
$response_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
if ($response_code !== 200) {
$error_message = aboutbuzz_get_detailed_error($response_code, $response_body);
if ($response_code === 429) {
$error_message = 'Rate limit reached. Please try again in a few minutes.';
}
if ($error_message === '') {
$error_message = 'Unable to load reviews right now. Please try again soon.';
}
if (current_user_can('manage_options')) {
return 'AboutBuzz: API error (HTTP ' . intval($response_code) . '): ' . esc_html($error_message) . ' — visible to admins only. Non-admin visitors see no output.
';
}
return '';
}
$data = json_decode($response_body, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) {
if (current_user_can('manage_options')) {
return 'AboutBuzz: invalid response format from API — visible to admins only.
';
}
return '';
}
foreach ($data as $story) {
if (!is_array($story) || empty($story['id'])) {
continue;
}
$video_url = $story['content'] ?? $story['link'] ?? '';
$rating = intval($story['acf']['rating'] ?? $story['meta']['rating'][0] ?? 5);
$vote_count = intval($story['acf']['vote_count'] ?? $story['meta']['vote_count'][0] ?? 0);
$watermark = $story['acf']['watermark_video'] ?? $story['meta']['watermark_video'][0] ?? '';
$product_source = $story['acf']['product_source'] ?? $story['meta']['product_source'][0] ?? '';
$product_source = is_string($product_source) ? sanitize_text_field($product_source) : '';
$brand_name = $story['acf']['brand'] ?? $story['meta']['brand'][0] ?? '';
$brand_name = is_string($brand_name) ? sanitize_text_field($brand_name) : '';
$sanitized_posts[] = [
'ID' => intval($story['id']),
'meta' => [
'story' => [esc_url_raw($video_url)],
'rating' => [$rating],
'vote_count' => [$vote_count],
'watermark_video' => [esc_url_raw(is_array($watermark) ? ($watermark[0] ?? '') : $watermark)],
'product_source' => [$product_source],
'brand' => [$brand_name],
],
'acf' => [
'watermark_video' => esc_url_raw(is_array($watermark) ? ($watermark[0] ?? '') : $watermark),
'story' => esc_url_raw($video_url),
'rating' => $rating,
'vote_count' => $vote_count,
'product_source' => $product_source,
'brand' => $brand_name,
],
];
}
set_transient($cache_key, $sanitized_posts, 5 * MINUTE_IN_SECONDS);
}
if (empty($sanitized_posts)) {
return '' . esc_html__('Ni video ocen', 'aboutbuzz-stories-embed') . '
';
}
$total_rating = 0;
$rating_count = 0;
foreach ($sanitized_posts as $post) {
$rating = $post['meta']['rating'][0] ?? $post['acf']['rating'] ?? 0;
if ($rating > 0) {
$total_rating += $rating;
$rating_count++;
}
}
$average_rating = $rating_count > 0 ? round($total_rating / $rating_count, 2) : 0;
$widget_nonce = wp_create_nonce('aboutbuzz_widget_' . md5($activation_code));
$video_count = count($sanitized_posts);
$has_many_videos = ' aboutbutzz-has-many-videos';
ob_start();
?>
400));
}
$nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
$post_id = intval(wp_unslash($_POST['post_id']));
$activation_code = get_option('aboutbuzz_activation_code_cache', '');
if (empty($activation_code)) {
wp_die('Plugin not configured', 'Error', array('response' => 403));
}
if (!wp_verify_nonce($nonce, 'aboutbuzz_widget_' . md5($activation_code))) {
wp_die('Security check failed');
}
$user_id = aboutbuzz_get_user_identifier();
$like_key = 'aboutbuzz_liked_' . $post_id . '_' . $user_id;
if (get_transient($like_key)) {
wp_send_json_error(['message' => 'Already liked']);
return;
}
$rate_limit_key = 'aboutbuzz_like_rate_' . $user_id;
$rate_count = get_transient($rate_limit_key);
if ($rate_count && $rate_count >= 5) {
wp_send_json_error(['message' => 'Too many likes']);
return;
}
$new_rate_count = $rate_count ? $rate_count + 1 : 1;
set_transient($rate_limit_key, $new_rate_count, 3600);
$secret_code = get_option('aboutbuzz_activation_code_cache', '');
if (empty($secret_code)) {
wp_send_json_error(['message' => 'Plugin not configured. Please use the shortcode first.']);
return;
}
$response = wp_remote_post('https://aboutbuzz.com/wp-json/aboutbuzz/v1/like/', [
'timeout' => 8,
'headers' => [
'Content-Type' => 'application/json',
'User-Agent' => 'AboutBuzz-WordPress-Plugin/' . ABOUTBUZZ_EMBED_VERSION
],
'body' => wp_json_encode([
'code' => sanitize_text_field($secret_code),
'post_id' => $post_id
])
]);
if (is_wp_error($response)) {
wp_send_json_error(['message' => 'API error']);
return;
}
$response_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
if ($response_code !== 200) {
wp_send_json_error(['message' => 'API error']);
return;
}
$data = json_decode($response_body, true);
if (!$data || !isset($data['success']) || !$data['success']) {
wp_send_json_error(['message' => 'API error']);
return;
}
set_transient($like_key, true, 86400);
wp_send_json_success([
'vote_count' => intval($data['vote_count'] ?? 0)
]);
}
add_action('wp_ajax_aboutbuzz_like_post', 'aboutbuzz_like_post');
add_action('wp_ajax_nopriv_aboutbuzz_like_post', 'aboutbuzz_like_post');
// === Uninstall Hook ===
register_uninstall_hook(__FILE__, 'aboutbuzz_uninstall');
function aboutbuzz_uninstall() {
try {
delete_option('aboutbuzz_secret_code');
delete_option('aboutbuzz_activation_code_cache');
$transient_keys = [
'aboutbuzz_validation_',
'aboutbuzz_rate_limit_',
'aboutbuzz_cache_',
'aboutbuzz_stories_bycode_'
];
foreach ($transient_keys as $key) {
wp_cache_delete($key, 'transient');
}
wp_cache_flush();
} catch (Exception $e) {
// Silent fail
}
}
// === Plugin Activation Hook ===
register_activation_hook(__FILE__, 'aboutbuzz_activate');
function aboutbuzz_activate() {
if (version_compare(PHP_VERSION, '7.4', '<')) {
deactivate_plugins(plugin_basename(__FILE__));
wp_die('This plugin requires PHP 7.4 or higher.');
}
add_option('aboutbuzz_secret_code', '');
wp_cache_flush();
}
// === Plugin Deactivation Hook ===
register_deactivation_hook(__FILE__, 'aboutbuzz_deactivate');
function aboutbuzz_deactivate() {
$transient_keys = [
'aboutbuzz_validation_',
'aboutbuzz_rate_limit_',
'aboutbuzz_cache_',
'aboutbuzz_stories_bycode_'
];
foreach ($transient_keys as $key) {
wp_cache_delete($key, 'transient');
}
wp_cache_flush();
}