$settings['access_key'],
'secret_key' => $settings['secret_key'],
'partner_tag' => $settings['partner_tag'],
'marketplace' => $settings['marketplace'] ?? AFFIAMSH_FALLBACK_MARKETPLACE,
'region' => $settings['region'] ?? 'eu-west-1',
'using_fallback' => false
];
} else {
// Usa le credenziali di fallback
$marketplaces = affiamsh_get_amazon_marketplaces();
$marketplace = AFFIAMSH_FALLBACK_MARKETPLACE;
return [
'access_key' => AFFIAMSH_FALLBACK_ACCESS_KEY,
'secret_key' => AFFIAMSH_FALLBACK_SECRET_KEY,
'partner_tag' => AFFIAMSH_FALLBACK_PARTNER_TAG,
'marketplace' => $marketplace,
'region' => $marketplaces[$marketplace] ?? 'eu-west-1',
'using_fallback' => true
];
}
}
// Enqueue plugin styles
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style(
'affiamsh-amazon-products-style',
plugins_url('amazon-products.css', __FILE__),
[],
AFFIAMSH_VER
);
});
// Add the settings menu
add_action('admin_menu', function () {
add_menu_page(
'Affiliate Amazon Shortcode Settings',
'Affiliate Amazon Shortcode',
'manage_options',
'affiamsh-amazon-api-settings',
'affiamsh_amazon_api_settings_page',
'dashicons-cart'
);
});
// Get Amazon marketplaces
function affiamsh_get_amazon_marketplaces() {
return [
'www.amazon.it' => 'eu-west-1',
'www.amazon.com' => 'us-east-1',
'www.amazon.co.uk' => 'eu-west-1',
'www.amazon.de' => 'eu-central-1',
'www.amazon.fr' => 'eu-west-1',
'www.amazon.es' => 'eu-west-1',
'www.amazon.ca' => 'ca-central-1',
'www.amazon.co.jp' => 'ap-northeast-1',
'www.amazon.in' => 'ap-south-1',
];
}
// Get image sizes
function affiamsh_get_image_sizes() {
return [
'Medium' => 'Images.Primary.Medium',
'Large' => 'Images.Primary.Large',
];
}
// Settings Page
function affiamsh_amazon_api_settings_page() {
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['affiamsh_api_settings_nonce']) &&
wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['affiamsh_api_settings_nonce'])), 'affiamsh_save_settings')) {
$marketplace = isset($_POST['marketplace']) ? sanitize_text_field(wp_unslash($_POST['marketplace'])) : '';
$marketplaces = affiamsh_get_amazon_marketplaces();
$image_sizes = affiamsh_get_image_sizes();
$settings = [
'access_key' => isset($_POST['access_key']) ? sanitize_text_field(wp_unslash($_POST['access_key'])) : '',
'secret_key' => isset($_POST['secret_key']) ? sanitize_text_field(wp_unslash($_POST['secret_key'])) : '',
'partner_tag' => isset($_POST['partner_tag']) ? sanitize_text_field(wp_unslash($_POST['partner_tag'])) : '',
'region' => $marketplaces[$marketplace] ?? 'us-east-1',
'marketplace' => $marketplace,
'num_products' => isset($_POST['num_products']) ? absint(wp_unslash($_POST['num_products'])) : 3,
'num_columns' => isset($_POST['num_columns']) ? absint(wp_unslash($_POST['num_columns'])) : 3,
'image_size' => isset($_POST['image_size']) ? sanitize_text_field(wp_unslash($_POST['image_size'])) : 'Medium',
'font_size' => isset($_POST['font_size']) ? affiamsh_validate_font_size(sanitize_text_field(wp_unslash($_POST['font_size']))) : '16px',
];
update_option('affiamsh_plugin_settings', $settings);
echo '
Settings saved successfully.
';
}
$settings = get_option('affiamsh_plugin_settings', []);
$credentials = affiamsh_get_credentials();
$marketplaces = affiamsh_get_amazon_marketplaces();
$image_sizes = affiamsh_get_image_sizes();
?>
Amazon API Settings
ℹ️ Demo Mode Active
You're using default credentials for testing. Products will be displayed with a demo affiliate ID.
To use your own affiliate ID and earn commissions, enter your Amazon API credentials below.
'smartphone'], $atts, 'affiamsh_amazon');
$settings = get_option('affiamsh_plugin_settings', []);
// Ottieni le credenziali (con fallback se necessario)
$credentials = affiamsh_get_credentials();
// Construct the payload
$image_sizes = affiamsh_get_image_sizes();
$image_size_key = $settings['image_size'] ?? 'Medium';
$image_size = $image_sizes[$image_size_key] ?? 'Images.Primary.Medium';
$payload = "{"
. " \"Keywords\": \"" . esc_js($atts['keyword']) . "\","
. " \"Resources\": ["
. " \"$image_size\","
. " \"ItemInfo.ContentInfo\","
. " \"ItemInfo.Title\","
. " \"Offers.Listings.Price\""
. " ],"
. " \"SearchIndex\": \"All\","
. " \"PartnerTag\": \"" . esc_js($credentials['partner_tag']) . "\","
. " \"PartnerType\": \"Associates\","
. " \"Marketplace\": \"" . esc_js($credentials['marketplace']) . "\","
. " \"ItemCount\": " . absint($settings['num_products'] ?? 3)
. "}";
$host = str_replace('www.', 'webservices.', $credentials['marketplace']);
$uriPath = "/paapi5/searchitems";
$url = 'https://' . $host . $uriPath;
// Sign the request using AwsV4
$awsv4 = new Affiamsh_AwsV4($credentials['access_key'], $credentials['secret_key']);
$awsv4->setRegionName($credentials['region']);
$awsv4->setServiceName("ProductAdvertisingAPI");
$awsv4->setPath($uriPath);
$awsv4->setPayload($payload);
$awsv4->setRequestMethod("POST");
$awsv4->addHeader('content-encoding', 'amz-1.0');
$awsv4->addHeader('content-type', 'application/json; charset=utf-8');
$awsv4->addHeader('host', $host);
$awsv4->addHeader('x-amz-target', 'com.amazon.paapi5.v1.ProductAdvertisingAPIv1.SearchItems');
$headers = $awsv4->getHeaders();
// Perform the API request
$response = wp_remote_post($url, [
'headers' => $headers,
'body' => $payload,
'timeout' => 20,
'method' => 'POST',
]);
if (is_wp_error($response)) {
return 'Error: ' . esc_html($response->get_error_message()) . '
';
}
$http_code = wp_remote_retrieve_response_code($response);
if ($http_code !== 200) {
$error_body = wp_remote_retrieve_body($response);
return 'Error: Invalid response from Amazon server. HTTP Code: ' . esc_html($http_code) . '
'
. '' . esc_html($error_body) . '
';
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (empty($data)) {
return 'Error: Unable to parse the Amazon server response.
';
}
if (empty($data['SearchResult']['Items'])) {
return 'No products found.
';
}
// Generate HTML
$num_products = $settings['num_products'] ?? 3;
$num_columns = $settings['num_columns'] ?? 3;
$font_size = esc_attr($settings['font_size'] ?? '16px');
// Get PRO options
$pro_opts = get_option('affiamsh_pro_display_options', [
'template' => 'card',
'theme' => 'slate',
'text_color' => '',
'title_color' => '',
'price_color' => ''
]);
$template = isset($pro_opts['template']) && !empty($pro_opts['template']) ? $pro_opts['template'] : 'card';
$theme = isset($pro_opts['theme']) && !empty($pro_opts['theme']) ? $pro_opts['theme'] : 'slate';
$is_pro = affiamsh_is_pro();
// Build classes
$container_classes = 'affiamsh-amazon-products template-' . esc_attr($template);
$container_classes .= ' affiamsh-theme-' . esc_attr($theme);
// Build inline styles con CSS variables
$inline_styles = "display: grid; grid-template-columns: repeat(" . esc_attr($num_columns) . ", 1fr); gap: 20px;margin-bottom:20px;";
// Add custom color overrides SOLO se theme è CUSTOM e PRO è attivo
if ($is_pro && $theme === 'custom') {
if (!empty($pro_opts['text_color'])) {
$inline_styles .= " --affiamsh-text: " . esc_attr($pro_opts['text_color']) . " !important;";
}
if (!empty($pro_opts['title_color'])) {
$inline_styles .= " --affiamsh-title: " . esc_attr($pro_opts['title_color']) . " !important;";
}
if (!empty($pro_opts['price_color'])) {
$inline_styles .= " --affiamsh-price: " . esc_attr($pro_opts['price_color']) . " !important;";
}
if (!empty($pro_opts['box_bg'])) {
$inline_styles .= " --affiamsh-bg: " . esc_attr($pro_opts['box_bg']) . " !important;";
}
if (!empty($pro_opts['ticket_bg'])) {
$inline_styles .= " --affiamsh-discount-bg: " . esc_attr($pro_opts['ticket_bg']) . " !important;";
}
if (!empty($pro_opts['discount_fg'])) {
$inline_styles .= " --affiamsh-discount-fg: " . esc_attr($pro_opts['discount_fg']) . " !important;";
}
if (!empty($pro_opts['box_bg_hover'])) {
$inline_styles .= " --affiamsh-bg-hover: " . esc_attr($pro_opts['box_bg_hover']) . " !important;";
}
}
$html = '';
foreach ($data['SearchResult']['Items'] as $index => $item) {
if ($index >= $num_products) break;
$title = esc_html($item['ItemInfo']['Title']['DisplayValue'] ?? 'Title not available');
$short_title = (strlen($title) > 50) ? substr($title, 0, 50) . '...' : $title;
$image = esc_url($item['Images']['Primary'][$image_size_key]['URL'] ?? '');
$link = esc_url($item['DetailPageURL'] ?? '#');
$price = $item['Offers']['Listings'][0]['Price']['DisplayAmount'] ?? 'Price not available';
$percentage = $item['Offers']['Listings'][0]['Price']['Savings']['Percentage'] ?? null;
$html .= '
';
}
$html .= '
';
return $html;
}
add_shortcode('affiamsh_amazon', 'affiamsh_amazon_handler');
/**
* Classe AwsV4
*/
class Affiamsh_AwsV4 {
private $accessKey = null;
private $secretKey = null;
private $path = null;
private $regionName = null;
private $serviceName = null;
private $httpMethodName = null;
private $queryParametes = array();
private $awsHeaders = array();
private $payload = "";
private $HMACAlgorithm = "AWS4-HMAC-SHA256";
private $aws4Request = "aws4_request";
private $strSignedHeader = null;
private $xAmzDate = null;
private $currentDate = null;
public function __construct($accessKey, $secretKey) {
$this->accessKey = $accessKey;
$this->secretKey = $secretKey;
$this->xAmzDate = $this->getTimeStamp();
$this->currentDate = $this->getDate();
}
function setPath($path) {
$this->path = $path;
}
function setServiceName($serviceName) {
$this->serviceName = $serviceName;
}
function setRegionName($regionName) {
$this->regionName = $regionName;
}
function setPayload($payload) {
$this->payload = $payload;
}
function setRequestMethod($method) {
$this->httpMethodName = $method;
}
function addHeader($headerName, $headerValue) {
$this->awsHeaders[$headerName] = $headerValue;
}
private function prepareCanonicalRequest() {
$canonicalURL = "";
$canonicalURL .= $this->httpMethodName . "\n";
$canonicalURL .= $this->path . "\n" . "\n";
$signedHeaders = '';
foreach ($this->awsHeaders as $key => $value) {
$signedHeaders .= $key . ";";
$canonicalURL .= $key . ":" . $value . "\n";
}
$canonicalURL .= "\n";
$this->strSignedHeader = substr($signedHeaders, 0, -1);
$canonicalURL .= $this->strSignedHeader . "\n";
$canonicalURL .= $this->generateHex($this->payload);
return $canonicalURL;
}
private function prepareStringToSign($canonicalURL) {
$stringToSign = '';
$stringToSign .= $this->HMACAlgorithm . "\n";
$stringToSign .= $this->xAmzDate . "\n";
$stringToSign .= $this->currentDate . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "\n";
$stringToSign .= $this->generateHex($canonicalURL);
return $stringToSign;
}
private function calculateSignature($stringToSign) {
$signatureKey = $this->getSignatureKey($this->secretKey, $this->currentDate, $this->regionName, $this->serviceName);
$signature = hash_hmac("sha256", $stringToSign, $signatureKey, true);
$strHexSignature = strtolower(bin2hex($signature));
return $strHexSignature;
}
public function getHeaders() {
$this->awsHeaders['x-amz-date'] = $this->xAmzDate;
ksort($this->awsHeaders);
$canonicalURL = $this->prepareCanonicalRequest();
$stringToSign = $this->prepareStringToSign($canonicalURL);
$signature = $this->calculateSignature($stringToSign);
if ($signature) {
$this->awsHeaders['Authorization'] = $this->buildAuthorizationString($signature);
return $this->awsHeaders;
}
}
private function buildAuthorizationString($strSignature) {
return $this->HMACAlgorithm . " " . "Credential=" . $this->accessKey . "/" . $this->getDate() . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "," . "SignedHeaders=" . $this->strSignedHeader . "," . "Signature=" . $strSignature;
}
private function generateHex($data) {
return strtolower(bin2hex(hash("sha256", $data, true)));
}
private function getSignatureKey($key, $date, $regionName, $serviceName) {
$kSecret = "AWS4" . $key;
$kDate = hash_hmac("sha256", $date, $kSecret, true);
$kRegion = hash_hmac("sha256", $regionName, $kDate, true);
$kService = hash_hmac("sha256", $serviceName, $kRegion, true);
$kSigning = hash_hmac("sha256", $this->aws4Request, $kService, true);
return $kSigning;
}
private function getTimeStamp() {
return gmdate("Ymd\THis\Z");
}
private function getDate() {
return gmdate("Ymd");
}
}
// === PRO Licensing & Display Options ===
if (!defined('AFFIAMSH_PRO_KEY_PLAIN')) {
define('AFFIAMSH_PRO_KEY_PLAIN', 'AMSH1899271');
}
if (!function_exists('affiamsh_is_pro')) {
function affiamsh_is_pro(): bool {
return (bool) get_option('affiamsh_is_pro', false);
}
}
add_action('admin_menu', function () {
add_submenu_page(
'affiamsh-amazon-api-settings',
__('Activate PRO', 'affiliate-amazon-shortcode'),
__('Activate PRO', 'affiliate-amazon-shortcode'),
'manage_options',
'affiamsh-activate-pro',
'affiamsh_pro_activation_page'
);
add_submenu_page(
'affiamsh-amazon-api-settings',
__('Display (PRO)', 'affiliate-amazon-shortcode'),
__('Display (PRO)', 'affiliate-amazon-shortcode'),
'manage_options',
'affiamsh-pro-display',
'affiamsh_pro_display_settings_page'
);
});
add_action('admin_init', function () {
if (!isset($_POST['affiamsh_activate_pro'])) { return; }
if (!current_user_can('manage_options')) { return; }
check_admin_referer('affiamsh_activate_pro');
$key = isset($_POST['affiamsh_license_key']) ? sanitize_text_field( wp_unslash($_POST['affiamsh_license_key']) ) : '';
if (hash_equals(AFFIAMSH_PRO_KEY_PLAIN, $key)) {
update_option('affiamsh_is_pro', 1);
update_option('affiamsh_license_key', $key);
add_settings_error('affiamsh_pro', 'pro_ok', __('PRO version successful activated.', 'affiliate-amazon-shortcode'), 'updated');
} else {
update_option('affiamsh_is_pro', 0);
add_settings_error('affiamsh_pro', 'pro_ko', __('License Code Invalid.', 'affiliate-amazon-shortcode'), 'error');
}
});
add_action('admin_init', function () {
register_setting('affiamsh_pro_display_group', 'affiamsh_pro_display_options', function ($value) {
$out = [
'template' => 'card',
'theme' => 'slate',
'text_color' => '',
'title_color' => '',
'price_color' => '',
'box_bg' => '',
'ticket_bg' => '',
'discount_fg' => '',
'box_bg_hover' => '',
];
if (is_array($value)) {
$tpl = isset($value['template']) ? sanitize_text_field($value['template']) : 'card';
$out['template'] = in_array($tpl, ['card','list'], true) ? $tpl : 'card';
$allowed_themes = ['slate','blue','emerald','amber','rose','violet','indigo','teal','zinc','custom'];
$th = isset($value['theme']) ? sanitize_text_field($value['theme']) : 'slate';
if (!in_array($th, $allowed_themes, true)) { $th = 'slate'; }
if (!affiamsh_is_pro()) { $th = 'slate'; }
$out['theme'] = $th;
if ($th === 'custom') {
foreach (['text_color','title_color','price_color','box_bg','ticket_bg','discount_fg','box_bg_hover'] as $k) {
$c = isset($value[$k]) ? sanitize_text_field($value[$k]) : '';
if ($c && preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $c)) {
$out[$k] = $c;
}
}
} else {
$out['text_color'] = '';
$out['title_color'] = '';
$out['price_color'] = '';
$out['box_bg'] = '';
$out['ticket_bg'] = '';
$out['discount_fg'] = '';
$out['box_bg_hover'] = '';
}
}
return $out;
});
});
function affiamsh_pro_activation_page() {
?>
'card',
'theme' => 'slate',
'text_color' => '',
'title_color' => '',
'price_color' => '',
'box_bg' => '',
'ticket_bg' => '',
'discount_fg' => '',
'box_bg_hover' => '',
]);
$theme = isset($opts['theme']) ? $opts['theme'] : 'slate';
$is_pro = affiamsh_is_pro();
$show_colors = ($theme === 'custom');
?>
'.esc_html__('Settings','affiliate-amazon-shortcode').'';
$links[] = ''.esc_html__('Activate PRO','affiliate-amazon-shortcode').'';
$links[] = ''.esc_html__('Purchase PRO','affiliate-amazon-shortcode').'';
return $links;
});
add_action('admin_post_affiamsh_reset_pro', function () {
if (!current_user_can('manage_options')) {
wp_die( esc_html__( 'Forbidden', 'affiliate-amazon-shortcode' ) );
}
check_admin_referer('affiamsh_reset_pro');
delete_option('affiamsh_is_pro');
add_settings_error('affiamsh_pro', 'pro_reset', __('PRO disabled. You are in FREE version.', 'affiliate-amazon-shortcode'), 'updated');
wp_redirect( admin_url('admin.php?page=affiamsh-activate-pro') );
exit;
});
add_action('wp_enqueue_scripts', function () {
wp_register_script('affiamsh-frontend', '', [], AFFIAMSH_VER, true);
wp_enqueue_script('affiamsh-frontend');
$opts = get_option('affiamsh_pro_display_options', []);
$data = [
'isPro' => affiamsh_is_pro() ? 1 : 0,
'template' => isset($opts['template']) ? $opts['template'] : 'default',
'theme' => isset($opts['theme']) ? $opts['theme'] : 'slate',
];
$js = '(function(d,w){try{var CFG=' . wp_json_encode($data) . ';'
. 'function injectWatermark(){'
. 'if(CFG.isPro){return;}'
. 'var wrappers=d.querySelectorAll(".affiamsh-amazon-products");'
. 'wrappers.forEach(function(w){'
. 'if(w.querySelector(".affiamsh-watermark"))return;'
. 'var wm=d.createElement("span");'
. 'wm.className="affiamsh-watermark";'
. 'wm.setAttribute("aria-hidden","true");'
. 'wm.textContent="Made with Affiliate Amazon Shortcode Plugin";'
. 'w.appendChild(wm);'
. 'try{'
. 'var cs=w.ownerDocument.defaultView.getComputedStyle(w);'
. 'if(!cs||cs.position==="static"){w.style.position="relative";}'
. '}catch(e){if(!w.style.position){w.style.position="relative";}}'
. '});'
. '}'
. 'injectWatermark();'
. 'w.addEventListener("load",injectWatermark);'
. '}catch(e){}})(document,window);';
wp_add_inline_script('affiamsh-frontend', $js);
}, 40);
?>