&text=] --> inserts link to amazon item
[amazon cat=&last=] --> inserts table of random items
Layout:
amazon_container - Encloses whole wishlist.
amazon_prod - Encloses each list item.
amazon_img_container - Encloses the item thumbnail (link+img)
amazon_pic - Class of the item thumbnail IMG element
amazon_text_container - Encloses the item description (Title paragraphs+link + Details paragraphs)
amazon_details - Encloses the item details part of the description
amazon_price - Spans the item's formatted price.
*/
/*******************************************************************************************************
To serve a page containing amazon links the plugin performs the following:
* Queue the Amazon javascript and styles
* Search through the content and widget text for Amazon links, for each one:
* Parse arguments:
- get_default_settings (>cached),
- get_options_list (>cached),
- get_country_data (>cached),
- get country [ip2n lookup (>cached)]
* Make Links:
* get_templates (>cached)
* for each ASIN:
* parse template:
* (if live) perform [DB cached] itemLookup & process data returned
* Fill in template
* Keyword specific actions for:
- links,
- urls,
- tags & channels,
- [optionally] Check for local images
* If 'multinational' link found when doing the above then:
* Return all channels and user channels(>cached), create the javascript for the multinational popup.
TODO: Rationalise encoding / decoding
* Can we prevent WP from encoding?
- Can't guarantee that (esp visual editor) chars won't be &xxx; encoded
* Can we pre-encode data?
- in cached_query => do the " ' \r \n encoding? NO -> as & converted to %26 (do lone & encode as per WP?)
- in parse arguments also do the "'\r\n encoding?
Item Encoding:
Content =>
WordPress content filters:
& => &
'" => smart quotes
parse_shortcode:
ALL => html_entity_decode( $args, ENT_QUOTES, 'UTF-8' );
> this turns & back into & and ensures all other &xx; chars are converted back
each args !template_content => trim( urldecode( $data ), "\x22\x27 \t\n\r\0\x0B" );
> this strips ws & '" and converts any %xx char back.
cached_query:
ALL => raw no filters
parse_template_callback:
escape => ' and & converted to \' and %26
'Live' => '"', "'", "\r", "\n" converted to '"', ''','
','
'
*******************************************************************************************************/
include ('include/ip2nation.php');
//include ('include/ip2location.php');
if (!class_exists('AmazonWishlist_For_WordPress')) {
class AmazonWishlist_For_WordPress {
/*****************************************************************************************/
// Plugin Constants
const cache_table = 'amazon_link_cache';
const sc_cache_table = 'amazon_link_sc_cache';
const refs_table = 'amazon_link_refs';
const optionName = 'AmazonLinkOptions';
const user_options = 'amazonlinkoptions';
const templatesName = 'AmazonLinkTemplates';
const channels_name = 'AmazonLinkChannels';
var $option_version = 9;
var $plugin_version = '3.2.3-rc1';
var $plugin_home = 'http://www.houseindorset.co.uk/plugins/amazon-link/';
var $stats = array();
var $scripts_done = False;
var $tags = array();
/*****************************************************************************************/
// Constructor for the Plugin
function __construct() {
$this->filename = __FILE__;
$this->URLRoot = plugins_url('', __FILE__);
$this->ip2n = new AmazonWishlist_ip2nation;
// Register Initialisation Hook
add_action( 'init', array( $this, 'init' ) );
// Register filters to process the content and widget text
if ( false ) { // change false to true - To support WP Super Cache
add_cacheaction( 'wpsc_cachedata_safety', array( $this, 'safety' ) );
add_cacheaction( 'wpsc_cachedata', array( $this, 'widget_filter' ) );
} else {
add_filter( 'the_content', array( $this, 'content_filter' ),15,1 );
add_filter( 'widget_text', array( $this, 'widget_filter' ), 16,1 );
}
}
function safety () { return 1; }
/*****************************************************************************************/
// Functions for the above hooks
/*
* Initialise the Plugin
*
* Called on wordpress initialisation. Do all Frontend related aspects:
* - register styles, scripts & standard filters.
*/
function init() {
$settings = $this->get_default_settings();
// Create and Initialise Dependent Class Instances:
if ( ! is_admin() && ! empty( $settings['media_library'] ) ) {
/*
* If user is using the media_library to store Amazon images then
* we need to initialise the Amazon Link Search class.
*/
include( 'include/amazonSearch.php' );
$this->search = new AmazonLinkSearch;
$this->search->init( $this );
}
// ip2nation needed on Frontend
$this->ip2n->init( $this );
// Register our frontend styles and scripts:
// Optional / Override-able stylesheet
$stylesheet = apply_filters( 'amazon_link_style_sheet', plugins_url( "Amazon.css", __FILE__ ) );
if ( ! empty( $stylesheet ) ) {
wp_register_style ( 'amazon-link-style', $stylesheet, false, $this->plugin_version );
add_action( 'wp_enqueue_scripts', array( $this, 'amazon_styles' ) );
}
// Multinational popup script - printed in page footer if required.
$script = plugins_url( "amazon.js", __FILE__ );
wp_register_script( 'amazon-link-script', $script, false, $this->plugin_version );
if ( ! empty( $settings['sc_cache_enabled'] ) ) {
// We can't tell if the multinational popup is needed so just load the script
$this->scripts_done = True;
add_action( 'wp_print_footer_scripts', array( $this, 'footer_scripts' ) );
}
// Set up default plugin filters:
// Add default url generator - low priority
add_filter( 'amazon_link_url', array( $this, 'get_url' ), 20, 6 );
add_filter( 'amazon_link_url', 'esc_url', 21, 1);
/* Set up the default channel filters - priority determines order */
if (!empty($settings['do_channels'])) {
add_filter( 'amazon_link_get_channel' , array( $this, 'get_channel_by_setting' ), 10,4 );
add_filter( 'amazon_link_get_channel' , array( $this, 'get_channel_by_rules' ), 12,4 );
if (!empty($settings['user_ids'])) {
add_filter( 'amazon_link_get_channel' , array( $this, 'get_channel_by_user' ), 14,4 );
}
}
/* Set up the default link and channel filters */
add_filter( 'amazon_link_template_get_link_open', array( $this, 'get_links_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_rlink_open', array( $this, 'get_links_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_slink_open', array( $this, 'get_links_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_url', array( $this, 'get_urls_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_rurl', array( $this, 'get_urls_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_surl', array( $this, 'get_urls_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_tag', array( $this, 'get_tags_filter' ), 12, 5 );
add_filter( 'amazon_link_template_get_chan', array( $this, 'get_channel_filter' ), 12, 5 );
// Call any user hooks - passing the current plugin Settings and the Amazon Link Instance.
do_action( 'amazon_link_init', $settings, $this );
}
/*
* Enqueue Amazon Link Style Sheet.
*/
function amazon_styles() {
wp_enqueue_style( 'amazon-link-style' );
}
/*
* Print Amazon Link Footer Scripts.
*
* Only done if multinational popup is used in a link.
*/
function footer_scripts() {
$settings = $this->get_default_settings();
$link_templates = $this->get_link_templates();
// Create Element used to display the popup
echo '';
// Pass required data to the multinational popup script and print it.
wp_localize_script( 'amazon-link-script',
'AmazonLinkMulti',
array('link_templates' => $link_templates,
'country_data' => $this->get_country_data(),
'channels' => $this->get_channels( True ),
'target' => ( $settings['new_window'] ? 'target="_blank"' : '' ))
);
wp_print_scripts( 'amazon-link-script' );
// If called directly then don't need to print again
remove_action( 'wp_print_footer_scripts', array( $this, 'footer_scripts' ) );
}
/*****************************************************************************************/
// Various Arrays to Control the Plugin
/*****************************************************************************************/
function get_keywords( $keywords = array() ) {
/*
* Keyword array arguments:
* - Description: For Keyword Help Display
* - Live: [1|0] Indicates if keyword is retrieved via AWS
* - Position: Array of arrays to determine location of data in AWS XML
* - Group: Which ResponseGroup needed for AWS to return item data
* - User: [1|0] Indicates if keyword is supplied by User
* - Link: [1|0] Indicates keyword should not have \r \n replaced before insertion.
* - Default: If not provided/found use this value, if not provided '-' is used
* - Calculated: If keyword should not be substituted during first template run
*/
if ( ! isset( $this->keywords ) ) {
$this->keywords = array(
'link_open' => array( ),
'rlink_open' => array( ),
'slink_open' => array( ),
'link_close' => array( 'Default' => ''),
'asin' => array( 'Live' => '1', 'Group' => 'ItemAttributes', 'Default' => '0',
'Position' => array(array('ASIN'))),
'asins' => array( 'Default' => ''),
'product' => array( 'Live' => '1', 'Group' => 'ItemAttributes',
'Position' => array(array('ItemAttributes','ProductGroup'))),
'binding' => array( 'Live' => '1', 'Group' => 'ItemAttributes', 'Default' => ' ',
'Position' => array(array('ItemAttributes','Binding'))),
'features' => array( 'Live' => '1', 'Group' => 'ItemAttributes', 'Callback' => array($this,'format_list'), 'Default' => ' ',
'Position' => array(array('ItemAttributes','Feature'))),
'title' => array( 'Live' => '1', 'Group' => 'ItemAttributes', 'Default' => ' ',
'Position' => array(array('ItemAttributes','Title'))),
'artist' => array( 'Live' => '1', 'Group' => 'ItemAttributes',
'Position' => array(array('ItemAttributes','Artist'),
array('ItemAttributes','Author'),
array('ItemAttributes','Director'),
array('ItemAttributes','Creator'),
array('ItemAttributes','Brand'))),
'manufacturer' => array( 'Live' => '1', 'Group' => 'ItemAttributes',
'Position' => array(array('ItemAttributes','Manufacturer'),
array('ItemAttributes','Brand'))),
'thumb' => array( 'Live' => '1', 'Group' => 'Images', 'Default' => 'http://images-eu.amazon.com/images/G/02/misc/no-img-lg-uk.gif',
'Position' => array(array('MediumImage','URL'))),
'image' => array( 'Live' => '1', 'Group' => 'Images', 'Default' => 'http://images-eu.amazon.com/images/G/02/misc/no-img-lg-uk.gif',
'Position' => array(array('LargeImage','URL'),
array('MediumImage','URL'))),
'image_class' => array( ),
'search_text_s'=> array( ),
'search_text' => array( ),
'url' => array( ),
'surl' => array( ),
'rurl' => array( ),
'rank' => array( 'Live' => '1', 'Group' => 'SalesRank',
'Position' => array(array('SalesRank'))),
'rating' => array( 'Live' => '1',
'Position' => array(array('CustomerReviews','AverageRating'))),
'offer_price' => array( 'Live' => '1', 'Group' => 'Offers',
'Position' => array(array('Offers','Offer','OfferListing','Price','FormattedPrice'),
array('OfferSummary','LowestNewPrice','FormattedPrice'),
array('OfferSummary','LowestUsedPrice','FormattedPrice'))),
'list_price' => array( 'Live' => '1', 'Group' => 'ItemAttributes',
'Position' => array(array('ItemAttributes','ListPrice','FormattedPrice'))),
'price' => array( 'Live' => '1', 'Group' => 'Offers', 'National' => '1',
'Position' => array(array('Offers','Offer','OfferListing','Price','FormattedPrice'),
array('OfferSummary','LowestNewPrice','FormattedPrice'),
array('OfferSummary','LowestUsedPrice','FormattedPrice'),
array('ItemAttributes','ListPrice','FormattedPrice'))),
'text' => array( 'User' => '1'),
'text1' => array( 'User' => '1'),
'text2' => array( 'User' => '1'),
'text3' => array( 'User' => '1'),
'text4' => array( 'User' => '1'),
'pub_key' => array( ),
'mplace' => array( ),
'mplace_id' => array( ),
'rcm' => array( ),
'region' => array( ),
'imp' => array( ),
'buy_button' => array( ),
'language' => array( ),
'tag' => array( ),
'chan' => array( ),
'cc' => array( ),
'flag' => array( ),
'tld' => array( ),
'downloaded' => array( 'Calculated' => '1'),
'found' => array( 'Calculated' => '1', 'Default' => '1', 'National' => 1),
'timestamp' => array( 'Calculated' => 1, 'Default' => '0')
);
if ( isset ( $keywords ) ) {
$this->keywords = array_merge_recursive( $keywords, $this->keywords );
}
$this->keywords = apply_filters( 'amazon_link_keywords', $this->keywords, $this );
}
return $this->keywords;
}
function get_country_data( $cc = NULL ) {
if ( ! isset( $this->country_data ) ) {
/*
* Country specific aspects:
*
* Some needed in the plugin code:
* - cc -> the country code (also the index).
* - lang -> language identifier (see Microsoft Translate)
* - flag -> country flag image, used in settings pages (also a keyword)
* - tld -> tld of amazon site, used when making AWS request (also a keyword)
* - site -> link to affiliate program site, used on settings pages
* - country_name -> full name of country, used in settings pages (also a keyword)
*
* Some only needed for templates:
* - mplace -> market place of amazon site, used in Amazon Scripts
* - mplace_id -> market place id of amazon locale, used in Amazon Scripts
* - rcm -> amazon domain for location of scripts - backward compatible / depreciated
* - region -> advert region prefix for iframes & banners (amazon-adsystem.com) & widgets
* - imp -> advert prefix for serving impression tracking images
* - buy_button -> example buy button stored on Amazon Servers
* - language -> Language of each locale.
*/
$this->country_data = array(
'uk' => array( 'cc' => 'uk', 'mplace' => 'GB', 'mplace_id' => '2', 'lang' => 'en', 'flag' => $this->URLRoot. '/'. 'images/flag_uk.gif', 'tld' => 'co.uk', 'language' => 'English', 'region' => 'eu', 'imp' => 'ir-uk', 'rcm' => 'rcm-eu.amazon-adsystem.com', 'site' => 'https://affiliate-program.amazon.co.uk', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/02/buttons/buy-from-tan.gif', 'country_name' => 'United Kingdom', 'link_close' => ''),
'us' => array( 'cc' => 'us', 'mplace' => 'US', 'mplace_id' => '1', 'lang' => 'en', 'flag' => $this->URLRoot. '/'. 'images/flag_us.gif', 'tld' => 'com', 'language' => 'English', 'region' => 'na', 'imp' => 'ir-na', 'rcm' => 'rcm.amazon.com', 'site' => 'https://affiliate-program.amazon.com', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/01/buttons/buy-from-tan.gif', 'country_name' => 'United States', 'link_close' => ''),
'de' => array( 'cc' => 'de', 'mplace' => 'DE', 'mplace_id' => '3', 'lang' => 'de', 'flag' => $this->URLRoot. '/'. 'images/flag_de.gif', 'tld' => 'de', 'language' => 'Deutsch', 'region' => 'eu', 'imp' => 'ir-de', 'rcm' => 'rcm-de.amazon.de', 'site' => 'https://partnernet.amazon.de', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/03/buttons/buy-from-tan.gif', 'country_name' => 'Germany', 'link_close' => ''),
'es' => array( 'cc' => 'es', 'mplace' => 'ES', 'mplace_id' => '30', 'lang' => 'es', 'flag' => $this->URLRoot. '/'. 'images/flag_es.gif', 'tld' => 'es', 'language' => 'Español', 'region' => 'eu', 'imp' => 'ir-es', 'rcm' => 'rcm-es.amazon.es', 'site' => 'https://afiliados.amazon.es', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/30/buttons/buy-from-tan.gif', 'country_name' => 'Spain', 'link_close' => ''),
'fr' => array( 'cc' => 'fr', 'mplace' => 'FR', 'mplace_id' => '8', 'lang' => 'fr', 'flag' => $this->URLRoot. '/'. 'images/flag_fr.gif', 'tld' => 'fr', 'language' => 'Français', 'region' => 'eu', 'imp' => 'ir-fr', 'rcm' => 'rcm-fr.amazon.fr', 'site' => 'https://partenaires.amazon.fr', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/08/buttons/buy-from-tan.gif', 'country_name' => 'France', 'link_close' => ''),
'jp' => array( 'cc' => 'jp', 'mplace' => 'JP', 'mplace_id' => '9', 'lang' => 'ja', 'flag' => $this->URLRoot. '/'. 'images/flag_jp.gif', 'tld' => 'co.jp', 'language' => '日本語', 'region' => 'fe', 'imp' => 'ir-jp', 'rcm' => 'rcm-jp.amazon.co.jp', 'site' => 'https://affiliate.amazon.co.jp', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/09/buttons/buy-from-tan.gif', 'country_name' => 'Japan', 'link_close' => ''),
'it' => array( 'cc' => 'it', 'mplace' => 'IT', 'mplace_id' => '29', 'lang' => 'it', 'flag' => $this->URLRoot. '/'. 'images/flag_it.gif', 'tld' => 'it', 'language' => 'Italiano', 'region' => 'eu', 'imp' => 'ir-it', 'rcm' => 'rcm-it.amazon.it', 'site' => 'https://programma-affiliazione.amazon.it', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/29/buttons/buy-from-tan.gif', 'country_name' => 'Italy', 'link_close' => ''),
'cn' => array( 'cc' => 'cn', 'mplace' => 'CN', 'mplace_id' => '28', 'lang' => 'zh-CHS', 'flag' => $this->URLRoot. '/'. 'images/flag_cn.gif', 'tld' => 'cn', 'language' => '简体中文', 'region' => 'cn', 'imp' => 'ir-cn', 'rcm' => 'rcm-cn.amazon.cn', 'site' => 'https://associates.amazon.cn', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/28/buttons/buy-from-tan.gif', 'country_name' => 'China', 'link_close' => ''),
'in' => array( 'cc' => 'in', 'mplace' => 'IN', 'mplace_id' => '31', 'lang' => 'hi', 'flag' => $this->URLRoot. '/'. 'images/flag_in.gif', 'tld' => 'in', 'language' => 'Hindi', 'region' => 'in', 'imp' => 'ir-in', 'rcm' => 'ws-in.amazon-adsystem.com', 'site' => 'https://associates.amazon.in', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/31/buttons/buy-from-tan.gif', 'country_name' => 'India', 'link_close' => ''),
'ca' => array( 'cc' => 'ca', 'mplace' => 'CA', 'mplace_id' => '15', 'lang' => 'en', 'flag' => $this->URLRoot. '/'. 'images/flag_ca.gif', 'tld' => 'ca', 'language' => 'English', 'region' => 'na', 'imp' => 'ir-ca', 'rcm' => 'rcm-ca.amazon.ca', 'site' => 'https://associates.amazon.ca', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/15/buttons/buy-from-tan.gif', 'country_name' => 'Canada', 'link_close' => ''),
'br' => array( 'cc' => 'br', 'mplace' => 'BR', 'mplace_id' => '33', 'lang' => 'pt-br', 'flag' => $this->URLRoot. '/'. 'images/flag_br.gif', 'tld' => 'com.br','language' => 'Portuguese', 'region' => 'na', 'imp' => 'ir-br', 'rcm' => 'rcm-br.amazon-adsystem.br', 'site' => 'https://associados.amazon.com.br/', 'buy_button' => 'https://images-na.ssl-images-amazon.com/images/G/33/buttons/buy-from-tan.gif', 'country_name' => 'Brazil', 'link_close' => ''),
);
}
if ( empty( $cc ) ) {
return $this->country_data;
} else {
return $this->country_data[$cc];
}
/*
* To add a new locale:
* - Add line in the above array
* - Add default tag in get_channels
* - Add line in get_country
* - Add icon to images directory
* - Update amazon-search.php to support Searches
*/
}
function get_link_templates() {
if ( ! isset( $this->link_templates ) ) {
$this->link_templates = apply_filters( 'amazon_link_multi_link_templates',
array( 'A'=>'http://www.amazon.%TLD%/gp/product/%ARG%?ie=UTF8&linkCode=as2&camp=1634&creative=6738&tag=%TAG%%CC%#&creativeASIN=%ARG%',
'S'=>'http://www.amazon.%TLD%/mn/search/?_encoding=UTF8&linkCode=ur2&camp=1634&creative=19450&tag=%TAG%%CC%#&field-keywords=%ARG%',
'R'=>'http://www.amazon.%TLD%/review/%ARG%?ie=UTF8&linkCode=ur2&camp=1634&creative=6738&tag=%TAG%%CC%#',
'U'=>'%ARG%',
'X'=>'%ARG%'),
$this);
}
return $this->link_templates;
}
/*
* Get all possible plugin options, these are also the arguments accepted by the shortcode.
*
* option_list array arguments:
*
* Frontend
* - Default: Default Value if Not Set
*
*/
function get_option_list( $option_list = array() ) {
if ( ! isset( $this->option_list ) ) {
$this->option_list = $option_list;
// Populate the defaults - only aspected needed for Frontend
$this->option_list['text']['Default'] = 'Amazon';
$this->option_list['last']['Default'] = '30';
$this->option_list['image_class']['Default'] = 'wishlist_image';
$this->option_list['wishlist_template']['Default'] = 'Wishlist';
$this->option_list['wishlist_items']['Default'] = 5;
$this->option_list['wishlist_type']['Default'] = 'Similar';
$this->option_list['default_cc']['Default'] = 'uk';
$this->option_list['plugin_ids']['Default'] = '0';
$this->option_list['localise']['Default'] = '1';
$this->option_list['search_text']['Default'] = '%ARTIST% | %TITLE%';
$this->option_list['search_text_s']['Default'] = '%ARTIST%S# | %TITLE%S#';
$this->option_list['multi_cc']['Default'] = '1';
$this->option_list['live']['Default'] = '1';
$this->option_list['cache_age']['Default'] = '48';
$this->option_list['sc_cache_age']['Default'] = '1';
// Give plugins option of changing settings
$this->option_list = apply_filters( 'amazon_link_option_list', $this->option_list );
}
return $this->option_list;
}
/*
* Extract required ResponseGroups from the Keyword Table
*
* Content of Keywords array may be changed by plugins.
*/
function get_response_groups() {
if ( ! isset( $this->response_groups ) ) {
$this->response_groups = array();
foreach ( $this->get_keywords() as $key => $key_data ) {
if ( isset( $key_data['Group'] ) && ! in_array( $key_data['Group'], $this->response_groups ) ) {
$this->response_groups[] = $key_data['Group'];
}
}
$this->response_groups = implode( ',', $this->response_groups );
}
return $this->response_groups;
}
/*****************************************************************************************/
// Various Options, Arguments, Templates and Channels Handling
/*****************************************************************************************/
/*
* For backward compatibility this should return the 'local' settings
*/
function getSettings() {
if ( ! isset( $this->Settings ) ) {
$this->Settings = $this->get_default_settings();
}
return $this->Settings;
}
/*
* Normally Settings are populated from parsing user arguments, however some
* external calls do not cause argument parsing (e.g. amazon_query). So this
* ensures we have the defaults.
*/
function get_default_settings() {
if ( ! isset( $this->default_settings ) ) {
$this->default_settings = get_option( self::optionName, array() );
$option_list = $this->get_option_list();
foreach ( $option_list as $key => $details ) {
if ( ! isset( $this->default_settings[$key] ) && isset( $details['Default'] ) ) {
$this->default_settings[$key] = $details['Default'];
}
}
}
return $this->default_settings;
}
/*****************************************************************************************/
// Templates
function getTemplates ( $template = ' ' ) {
if ( ! isset ( $this->Templates ) ) {
$this->Templates = get_option ( self::templatesName, array() );
}
if ( ! empty ( $this->Templates[$template] ) ) {
return $this->Templates[$template];
} else if ( $template == ' ' ) {
return $this->Templates;
} else {
return NULL;
}
}
/*****************************************************************************************/
// Channels
/*
* Get all the Affiliate ID Channels
*
* override fills any unset IDs with the defaults
*/
function get_channels( $override = False ) {
$settings = $this->get_default_settings();
if ( ! isset( $this->channels ) || ! $override ) {
$channels = get_option( self::channels_name, array() );
if ( ! $override ) return $channels;
if ( ! empty($settings['plugin_ids']) ) {
/*
* Only use the plugin ids for unpopulated locales if it has
* been explicitly enabled by the user option.
*/
$default_tags = array( 'tag_uk' => 'al-uk-21', 'tag_us' => 'al-us-20', 'tag_de' => 'al-de-21', 'tag_es' => 'al-es-21', 'tag_fr' => 'al-fr-21', 'tag_jp' => 'al-jp-22', 'tag_it' => 'al-it-21', 'tag_cn' => 'al-cn-23', 'tag_in' => 'al-in-21', 'tag_ca' => 'al-ca-20', 'tag_br' => 'al-br-20');
} else {
$default_tags = array();
}
$channels['default'] = array_filter( $channels['default'] );
$this->channels = array();
foreach ( $channels as $channel_id => $channel_data ) {
$this->channels[$channel_id] = array_filter( $channel_data ) + $channels['default'] + $default_tags;
$this->channels[$channel_id]['ID'] = $channel_id;
}
}
return $this->channels;
}
/*
* Check the channels in order until we get a match
*
* TODO: Add option to enable Channel Rules, (i.e. remove all filters)
*/
function get_channel( $settings ) {
// get post ID if in post, needed for channel cache.
if ( ! empty( $settings['in_post'] ) ) {
global $post;
$cache_index = $settings['asin']. $post->ID;
} else {
$post = NULL;
$cache_index = $settings['asin'].'X';
}
$channels = $this->get_channels( True );
if ( isset( $this->channel_cache[$cache_index] ) ) {
$channel_data = $channels[$this->channel_cache[$cache_index]];
} else {
$channel_data = apply_filters ( 'amazon_link_get_channel', array(), $channels, $post, $settings, $this );
// No match found return default channel.
if ( empty( $channel_data ) ) $channel_data = $channels['default'];
$this->channel_cache[$cache_index] = $channel_data['ID'];
}
return $channel_data;
}
/*
* If channel is manually set in the link then always apply here
*/
function get_channel_by_setting ( $channel_data, $channels, $post, $settings ) {
if ( ! empty( $channel_data ) ) return $channel_data;
if ( isset( $settings['chan'] ) && isset( $channels[strtolower( $settings['chan'] )] ) ) {
return $channels[strtolower( $settings['chan'] )];
}
return $channel_data;
}
/*
* Filter rules:
* cat = [category slug|category id]
* parent_cat = [category slug| category id]
* author = [author name|author id]
* tag = [tag name|tag id]
* type = [page|post|other = widget|template, etc]
* parent = [page/post id]
* random = 1-99
* empty rule = won't be used by this filter
*/
function get_channel_by_rules ( $channel_data, $channels, $post, $settings ) {
if ( ! empty( $channel_data ) ) return $channel_data;
foreach ( $channels as $channel => $data ) {
// Process the rules if they are defined
if ( ! empty( $data['Rule'] ) ) {
if ( isset( $data['Rule']['rand'] ) && ( $data['Rule']['rand'] > rand( 0, 99) ) )
return $data;
if ( isset( $post ) ) {
if ( isset( $data['Rule']['cat'] ) && has_category( $data['Rule']['cat'], $post ) )
return $data;
if ( isset( $data['Rule']['tag'] ) && has_tag( $data['Rule']['tag'], $post ) )
return $data;
if ( isset( $data['Rule']['type'] ) && ( $post->post_type == $data['Rule']['type'] ) )
return $data;
if ( isset( $data['Rule']['author'] ) && ( $post->post_author == $data['Rule']['author'] ) )
return $data;
}
}
}
return $channel_data;
}
/*
* If all previous filters have failed then look for User channel
*/
function get_channel_by_user ( $channel_data, $channels, $post, $settings ) {
if ( ! empty( $channel_data ) ) return $channel_data;
// If no specific channel detected then check for author specific IDs via get_the_author_meta
if ( isset( $post->post_author ) && isset( $channels['al_user_'.$post->post_author] ) ) {
return $channels['al_user_'.$post->post_author];
}
return $channel_data;
}
/*****************************************************************************************/
// Frontend Cache Facility
function cache_update_item( $asin, $cc, &$data ) {
global $wpdb;
$settings = $this->get_default_settings();
if ( ! empty( $settings['cache_enabled'] ) ) {
/* Use SQL timestamp to avoid timezone difference between SQL and PHP */
$result = $wpdb->get_row( "SELECT NOW() AS timestamp", ARRAY_A );
$data['timestamp'] = $updated = $result['timestamp'];
$cache_table = $wpdb->prefix . self::cache_table;
$sql_data = array( 'asin' => $asin, 'cc' => $cc, 'xml' => serialize( $data ), 'updated' => $updated );
$wpdb->replace( $cache_table, $sql_data );
}
}
function cache_lookup_item( $asin, $cc ) {
global $wpdb;
$settings = $this->get_default_settings();
if ( ! empty( $settings['cache_enabled'] ) ) {
// Check if asin is already in the cache
$cache_table = $wpdb->prefix . self::cache_table;
if ( ! empty( $settings['cache_age'] ) ) {
$sql = "SELECT xml FROM $cache_table WHERE asin LIKE '$asin' AND cc LIKE '$cc' AND updated >= DATE_SUB(NOW(),INTERVAL " . $settings['cache_age']. " HOUR)";
} else {
$sql = "SELECT xml FROM $cache_table WHERE asin LIKE '$asin' AND cc LIKE '$cc'";
}
$result = $wpdb->get_row( $sql, ARRAY_A );
if ($result !== NULL) {
$data = unserialize( $result['xml'] );
$data['cached'] = 1;
return $data;
}
}
return NULL;
}
/*****************************************************************************************/
// Frontend Shortcode Cache Facility
function sc_cache_update_item( $args, $cc, $postid, &$data ) {
global $wpdb;
$settings = $this->get_default_settings();
if ( ! empty ( $args ) && ! empty( $settings['sc_cache_enabled'] ) ) {
/* Use SQL timestamp to avoid timezone difference between SQL and PHP */
$result= $wpdb->get_row( "SELECT NOW() AS timestamp", ARRAY_A );
$updated = $result['timestamp'];
$hash = hash( 'md5', $args );
$postid = ( ! empty( $postid ) ? $postid : '0');
$cache_table = $wpdb->prefix . self::sc_cache_table;
$sql_data = array( 'hash' => $hash, 'cc' => $cc, 'postid' => $postid, 'args' => $args, 'content' => $data, 'updated' => $updated );
$wpdb->replace( $cache_table, $sql_data );
}
}
function sc_cache_lookup_item( $args, $cc, $postid ) {
global $wpdb;
$settings = $this->get_default_settings();
if ( !empty ( $args ) && ! empty( $settings['sc_cache_enabled'] ) ) {
$postid = ( ! empty( $postid ) ? $postid : '0' );
$hash = hash( 'md5', $args );
// Check if shortcode is already in the cache
$cache_table = $wpdb->prefix . self::sc_cache_table;
if ( ! empty( $settings['sc_cache_age'] ) ) {
$sql = "SELECT content FROM $cache_table WHERE hash = '$hash' AND cc = '$cc' AND postid = '$postid' AND updated >= DATE_SUB(NOW(),INTERVAL " . $settings['sc_cache_age']. " HOUR)";
} else {
$sql = "SELECT content FROM $cache_table WHERE hash = '$hash' AND cc = '$cc' AND postid = '$postid'";
}
$result = $wpdb->get_row( $sql, ARRAY_A );
if ( $result !== NULL ) {
return $result['content'];
}
}
return NULL;
}
/*****************************************************************************************/
/// Localise Link Facility
function get_country( $settings ) {
if ( ! empty( $settings['localise'] ) ) {
if ( empty( $this->local_country ) ) {
// Pretty arbitrary mapping of domains to Amazon sites, default to 'com' - the 'international' site.
$country_map = array( 'uk' => array('uk', 'ie', 'im', 'gi', 'gl', 'nl', 'vg', 'cy', 'gb', 'dk', 'gb'),
'fr' => array('fr', 'be', 'bj', 'bf', 'bi', 'cm', 'cf', 'td', 'km', 'cg', 'dj', 'ga', 'gp',
'gf', 'gr', 'pf', 'tf', 'ht', 'ci', 'lu', 'mg', 'ml', 'mq', 'yt', 'mc', 'nc',
'ne', 're', 'sn', 'sc', 'tg', 'vu', 'wf'),
'de' => array('de', 'at', 'ch', 'no', 'dn', 'li', 'sk'),
'es' => array('es'),
'it' => array('it', 'va'),
'cn' => array('cn'),
'ca' => array('ca', 'pm'),
'jp' => array('jp'),
'in' => array('in'),
'br' => array('br')
);
$cc = $this->ip2n->get_cc();
if ( $cc === NULL ) return $settings['default_cc'];
$country = 'us';
foreach ( $country_map as $key => $countries ) {
if ( in_array( $cc, $countries ) ) {
$country = $key;
continue;
}
}
$this->local_country = $country;
}
return $this->local_country;
}
return $settings['default_cc'];
}
function get_local_info( $settings ) {
return $this->get_country_data( $this->get_country( $settings ) );
}
function get_regex() {
if ( empty ( $this->regex ) ) {
/*
* Default regex needs to match opening and closing brackets '['
*/
$this->regex = apply_filters( 'amazon_link_regex',
'~
\[amazon\s+ # "[amazon" with at least one space
(?P # capture everything that follows as a named expression "args"
(?:(?>[^\[\]]*) # argument name excluding any "[" or "]" character
(?:\[(?>[a-z]*)\])? # optional "[alphaindex]" phrase
)* # 0 or more of these arguments
) # end of "args" group
\] # closing ]
~sx',
$this);
}
return $this->regex;
}
/*****************************************************************************************/
/* Actual Mechanics of the Shortcode Processing
*
* - Filter the Content and Widget Text for Shortcodes
* * content_filter
* * widget_filter
*
* - Either action the shortcode, or just extract ASINs
* * shortcode_expand
* * shortcode_extract_asins
* - parse_shortcode [to turn argument string into settings array
*
* - Generate Output
* * make_links
* * show_recommendations
*
/*****************************************************************************************/
/*****************************************************************************************/
// Searches through the_content for our 'Tag' and replaces it with the lists or links
/*
* Performs 2 functions:
* 1. Process the content and replace the shortcode with amazon links and wishlists
* 2. Search through the content and record any Amazon ASIN numbers ready to generate a wishlist.
*/
function content_filter( $content, $create_shortcodes = True, $in_post = True ) {
if ( $create_shortcodes ) {
$this->in_post = $in_post;
if ( $in_post ) {
global $post;
$this->post_ID = $post->ID;
} else {
$this->post_ID = '0';
}
$text = preg_replace_callback( $this->get_regex(), array($this,'shortcode_expand'), $content );
if ( ( preg_last_error() != PREG_NO_ERROR ) ) echo '';
return $text;
} else {
return preg_replace_callback( $this->get_regex(), array( $this, 'shortcode_extract_asins' ), $content );
}
}
/*
* Widget Text Filter - as Content Filter but not 'in_post'
*/
function widget_filter( $content ) {
return $this->content_filter( $content, True, False );
}
/*****************************************************************************************/
/*
* Expand shortcode arguments and action accordingly
*
* args is an array of options, with either option '1' or 'args' containing an shortcode arg string
*/
function shortcode_expand ( $args ) {
$args['in_post'] = $this->in_post;
$settings = $this->parse_shortcode( $args );
$this->inc_stats( 'shortcodes', 0 );
$output='';
$cc = $settings['local_cc'];
if ( $settings[$cc]['debug'] ) {
$output .= '';
}
if ( empty( $settings[$cc]['cat'] ) && empty( $settings[$cc]['s_index'] ) ) {
// Standard shortcode
// Save ASINs in global 'tags' tracker.
if ( ! empty( $settings['asin'] ) ) {
$this->tags = array_merge( $settings['asin'], $this->tags );
}
// Lookup Shortcode in Shortcode Cache,
$cached_output = $this->sc_cache_lookup_item( $args, $cc, $this->post_ID );
if ( ! empty( $cached_output ) ) {
$output .= $cached_output;
} else {
// TODO: Remove:
$this->Settings = &$settings['global'];
// Generate Amazon Link
$output .= $this->make_links( $settings );
// Save Shortcode
$this->sc_cache_update_item( $args, $cc, $this->post_ID, $output );
}
} else {
// Generated list of ASINS, either via category, local items, or Amazon search
$output .= $this->showRecommendations( $settings );
}
// Filter the shortcode output
return apply_filters( 'amazon_link_shortcode_output', $output, $this );
}
/*
* Expand shortcode arguments and record ASINs listed
*/
function shortcode_extract_asins ( $split_content ) {
$settings = $this->parse_shortcode( $split_content );
$this->tags = array_merge( $settings['asin'], $this->tags );
return '';
}
/*
* Amazon Link version of parse_str
*/
function parse_str( $args, &$settings ) {
// Split string into arguments arg[cc]=data at each '&'
$arguments = explode( '&', $args );
foreach ( $arguments as $argument ) {
// Split argument into arg[cc] and data at '='
list( $arg, $data ) = explode( '=', $argument, 2 );
list( $arg, $cc ) = preg_split( '/(\]|\[|$)/', $arg, 3 );
if ( empty( $cc ) ) $cc = 'global';
$arg = strtolower( $arg );
$cc = strtolower( $cc );
if ( $arg == 'asin' ) {
// ASIN we store outside the main settings
$asins = explode( ',', $data );
if ( $cc == 'global' ) {
$cc = $settings['global']['default_cc'];
}
foreach ( $asins as $i => $asin ) {
$settings['asin'][$i][$cc] = $asin;
}
} else if ( $arg == 'template_content' ) {
// TEMPLATE_CONTENT does not want to be urldecoded
$settings[$cc][$arg] = $data;
} else if ( ! empty( $arg ) ) {
// Strip off quotes and urldecode arguments
$settings[$cc][$arg] = trim( urldecode( $data ), "\x22\x27 \t\n\r\0\x0B" );
}
}
}
/*
* Extract settings from shortcode arguments
*
* We need to get the shortcode 'content' and 'args' in raw format, we also
* need to ensure output is not 'texturized' by the WP default filters.
*/
function parse_shortcode( &$split ) {
// Get global settings and default country data
$settings = $this->get_country_data();
$countries = array_keys( $settings );
$settings['global'] = $this->get_default_settings();
// If no ASIN supplied, ensure template is expanded at least once.
$settings['asin'][0][$settings['global']['default_cc']] = '';
/*
* First get the main arguments string
*/
if ( ! empty( $split['args'] ) ) {
$args = html_entity_decode( $split['args'], ENT_QUOTES, 'UTF-8' );
unset ( $split['args'] );
} else if ( ! empty( $split[1] ) ) {
$args = html_entity_decode( $split[1] , ENT_QUOTES, 'UTF-8');
unset ( $split[1] );
}
/*
* Reverse some of the WordPress filters efforts & ensure '’ => '�' characters are decoded
*/
foreach ( $split as $arg => $data ) {
if ( ! is_int( $arg ) ) {
if ( $arg == 'asin' ) {
// ASIN we store outside the main settings
$asins = explode ( ',', $data );
foreach ( $asins as $i => $asin ) {
$settings['asin'][$i][$settings['global']['default_cc']] = $asin;
}
} else {
$settings['global'][$arg] = html_entity_decode( $data, ENT_QUOTES, 'UTF-8' );
}
}
}
if ( ! empty( $args ) ) {
$this->parse_str( $args, $settings );
$split = $args;
} else {
$split = NULL;
}
$settings = apply_filters( 'amazon_link_process_args', $settings, $this );
$settings['local_cc'] = $this->get_country( $settings['global'] );
$settings['default_cc'] = $settings['home_cc'] = $settings['global']['default_cc'];
$settings['global']['local_cc'] = $settings['local_cc'];
$settings['global']['home_cc'] = $settings['global']['default_cc'];
foreach ( $countries as $cc ) {
// copy global settings into each locale
$settings[$cc] += $settings['global'];
}
return $settings;
}
/*****************************************************************************************/
/*
* Generate Content
*/
/*****************************************************************************************/
function make_links( $settings )
{
$cc = $settings['local_cc'];
/*
* If a template is specified and exists then populate it
*/
if ( isset( $settings[$cc]['template'] ) ) {
$template = strtolower( $settings[$cc]['template'] );
$template = $this->getTemplates( $template );
if ( ! empty( $template ) ) {
$settings[$cc]['template_content'] = $template['Content'];
$settings[$cc]['template_type'] = $template['Type'];
}
}
if ( ! isset( $settings[$cc]['template_content'] ) ) {
// Backward Compatible Shortcode, just has image,thumb and text
if ( ! empty( $settings[$cc]['image'] ) ) {
$image = True;
if ( strlen( $settings[$cc]['image'] ) < 5 ) unset( $settings[$cc]['image'] );
}
if ( ! empty( $settings[$cc]['thumb'] ) ) {
$thumb = True;
if ( strlen( $settings[$cc]['thumb'] ) < 5 ) unset( $settings[$cc]['thumb'] );
}
if ( isset( $thumb ) && isset( $image ) ) {
$settings[$cc]['template_content'] = '
';
} else if ( isset( $image ) ) {
$settings[$cc]['template_content']= '%LINK_OPEN%
%LINK_CLOSE%';
} else if ( isset( $thumb ) ) {
$settings[$cc]['template_content']= '%LINK_OPEN%
%LINK_CLOSE%';
} else {
$settings[$cc]['template_content']= '%LINK_OPEN%%TEXT%%LINK_CLOSE%';
}
$settings[$cc]['template_type'] = 'Product';
}
$details = array();
if ( empty( $settings[$cc]['template_type'] ) ) $settings[$cc]['template_type'] = 'Product';
if ( $settings[$cc]['template_type'] == 'Multi' ) {
/* Multi-product template collapse array back to a list, respecting country specific selection */
$sep = '';
$settings[$cc]['asins']='';
foreach ( $settings['asin'] as $i => $asin ) {
$settings[$cc]['asins'] .= $sep .( is_array( $asin ) ? ( isset( $asin[$cc] ) ? $asin[$cc] : $asin[$settings['default_cc']]) : $asin );
$sep=',';
}
$output = $this->parse_template( $settings );
} elseif ( $settings[$cc]['template_type'] == 'No ASIN' ) {
/* No asin provided so don't try and parse it */
$settings[$cc]['found'] = 1;
$settings['asin'] = array();
$output = $this->parse_template( $settings );
} else {
/* Usual case where user provides asin=X or asin=X,Y,Z */
$asins = $settings['asin'];
if ( count( $asins ) > 1) {
$settings[$cc]['live'] = 1;
}
$output = '';
$countries = array_keys( $this->get_country_data() );
foreach ( $asins as $asin ) {
// TODO: Do we need this loop?
foreach ( $countries as $cc ) {
$settings[$cc]['asin'] = ! empty( $asin[$cc] ) ? $asin[$cc] : NULL;
}
$settings['asin'] = $asin;
$output .= $this->parse_template( $settings );
}
}
return $output;
}
function showRecommendations ( $settings ) {
return include('include/showRecommendations.php');
}
/*****************************************************************************************/
/*
* Parse Template - keyword filters
*/
function get_channel_filter ( $channel, $keyword, $country, $data, $settings ) {
if ( ! empty( $channel ) ) return $channel;
$channel = $this->get_channel( $data[$country] );
return $channel['ID'];
}
function get_tags_filter ( $tag, $keyword, $country, $data, $settings ) {
if (!empty($tag)) return $tag;
$channel = $this->get_channel( $data[$country] );
return $channel['tag_'.$country];
}
function get_urls_filter ( $url, $keyword, $cc, $data, $settings ) {
if ( ! empty( $url ) ) return $url;
$map = array( 'url' => 'A', 'rurl' => 'R', 'surl' => 'S' );
$type = $map[$keyword];
$url = apply_filters( 'amazon_link_url', '', $type, $data, $data[$cc]['search_text_s'], $data[$cc]['cc'], $settings, $this );
return $url;
}
function get_links_filter ( $link, $keyword, $cc, $data, $settings ) {
// TODO: Use $settings / $data[$cc]?, rationalise
if ( empty( $this->temp_settings['multi_cc'] ) && ! empty( $link ) ) return $link;
$map = array( 'link_open' => 'A', 'rlink_open' => 'R', 'slink_open' => 'S' );
$type = $map[$keyword];
$attributes = 'rel="nofollow"' . ( $settings['new_window'] ? ' target="_blank"' : '' );
$attributes .= ! empty( $data[$cc]['link_title'] ) ? ' title="'.addslashes( $data[$cc]['link_title'] ).'"' : '';
$url = apply_filters( 'amazon_link_url', '', $type, $data, $data[$cc]['search_text_s'], $data[$cc]['cc'], $settings, $this );
$text = "";
if ( $settings['multi_cc'] ) {
$multi_data = array( 'settings' => $data, 'asin' => $data['asin'], 'type' => $type, 'search' => $data[$cc]['search_text_s'], 'cc' => $data[$cc]['cc'] );
$text = $this->create_popup( $multi_data, $text );
}
return $text;
}
/*
* We need to run the regex multiple times to catch new template tags replacing old ones (LINK_OPEN)
*/
function parse_template ( $item ) {
$start_time = microtime( true );
$countries_a = array_keys( $this->get_country_data() );
$keywords_data = $this->get_keywords();
$sep = $sepc = $keywords = $keywords_c = '';
// TODO: Cache this
foreach ( $keywords_data as $keyword => $key_data ) {
if ( empty( $key_data['Calculated'] ) ) {
$keywords .= $sep.$keyword;
$sep = '|';
} else {
$keywords_c .= $sepc.$keyword;
$sepc= '|';
}
}
$input = htmlspecialchars_decode ( stripslashes( $item[$item['local_cc']]['template_content'] ) );
// TODO: Do we really need both?
$this->temp_settings = $item[$item['local_cc']];
$this->temp_data = $item;
$countries = implode( '|', $countries_a );
do {
$input = preg_replace_callback( "!(?>%($keywords)%)(?:(?>($countries))?(?>(S))?([0-9]+)?#)?!i", array( $this, 'parse_template_callback' ), $input, -1, $count );
} while ( $count );
$input = preg_replace_callback( "!(?>%($keywords_c)%)(?:(?>($countries))?(?>(S))?([0-9]+)?#)?!i", array( $this, 'parse_template_callback' ), $input );
$time = microtime( true ) - $start_time;
if ( ! empty( $item[$item['local_cc']]['debug'] ) ) $input .="";
// Clear out local settings and data, no longer needed
unset( $this->temp_settings, $this->temp_data );
return $input;
}
/*
* Callback to process the preg_replace result where:
*
* - $args[1] => 'KEYWORD'
* - $args[2] => 'CC'
* - $args[3] => 'ESCAPE'
* - $args[4] => 'INDEX'
*/
function parse_template_callback ( $args ) {
$keyword = strtolower( $args[1] );
// TODO: Just return key_data?
$key_data = $this->get_keywords();
$key_data = $key_data[$keyword];
$settings = $this->temp_settings; // $data[$data['local_cc']]
$default_country = $settings['home_cc'];
/*
* Process Modifiers
*/
if ( empty( $args[2] ) ) {
$country = $settings['local_cc'];
} else {
// Manually set country, hard code to not localised
$country = strtolower( $args[2] );
$settings['multi_cc'] = 0;
$settings['localise'] = 0;
$settings['default_cc'] = $country;
}
$escaped = ! empty( $args[3]);
$keyword_index = ( ! empty( $args[4] ) ? $args[4] : 0 );
/*
* Select the most appropriate ASIN for the locale
* TODO: Pre-do this?
*/
if ( empty( $this->temp_data[$country]['asin'] ) ) {
$this->temp_data[$country]['asin'] = isset( $this->temp_data[$default_country]['asin'] ) ? $this->temp_data[$default_country]['asin'] : NULL;
}
$asin = $this->temp_data[$country]['asin'];
/*
* Prefetch product data if not already fetched and prefetch is enabled
*/
if ( $settings['live'] && $settings['prefetch'] && empty( $this->temp_data[$country]['prefetched']) && ! empty($asin) ) {
$this->temp_data[$country] += $this->get_item_data( $asin, $country, $settings );
$this->temp_data[$country]['prefetched'] = 1;
}
/*
* Apply any template_get filters for this keyword
*/
$phrase = apply_filters( 'amazon_link_template_get_'. $keyword, isset($this->temp_data[$country][$keyword])?$this->temp_data[$country][$keyword]:NULL, $keyword, $country, $this->temp_data, $settings, $this);
if ($phrase !== NULL) $this->temp_data[$country][$keyword] = $phrase;
/*
* If the keyword is not yet set then we need to populate it
*/
if ( ! isset( $this->temp_data[$country][$keyword] ) ) {
/*
* If we can get it from Amazon then try and get it
*/
if ( ! empty($key_data['Live'] ) && ( $settings['live'] ) ) {
$this->temp_data[$country] += $this->get_item_data( $asin, $country, $settings );
} else {
/*
* We can't retreive it, so just use the default if set
*/
$this->temp_data[$country][$keyword] = isset( $key_data['Default'] ) ? ( is_array( $key_data['Default'] ) ? $key_data['Default'][$country] : $key_data['Default'] ) : '-';
}
}
/*
* Run the 'process' filters to post process the keyword
*/
$this->temp_data[$country][$keyword] = apply_filters( 'amazon_link_template_process_'. $keyword, isset( $this->temp_data[$country][$keyword] ) ? $this->temp_data[$country][$keyword]:NULL, $keyword, $country, $this->temp_data, $settings, $this );
/*
* If multiple results returned then select the one requested in the template
*/
$phrase = $this->temp_data[$country][$keyword];
if ( is_array( $phrase ) ) {
$phrase = $phrase[$keyword_index];
}
/*
* Special cases when data being displayed is not available in locale
*/
if ( ! empty($key_data['National']) && ! empty($this->temp_data[$country]['not_found']) ) {
if ( ($keyword == 'found') && ($settings['localise'] == 0) ) {
$phrase = '0';
} else {
$phrase = isset( $key_data['Default'] ) ? ( is_array( $key_data['Default'] ) ? $key_data['Default'][$country] : $key_data['Default'] ) : '-';;
}
}
/*
* This just needs to get the data through to the javascript, typical HTML looks like:
*
* Need to ensure there are no unescaped ' or " characters or new lines
* " => '"'
*
* Also for search links need to ensure & is escaped
*
* For keywords in the link title need to escape "
*
* It is up to the receiving javascript to ensure that the data is present correctly for the next stage
* - in postedit -> strip out > and " and & and [ to ensure the shortcode is parsed correctly
* - in popup (do nothing?).
*/
if ( $escaped ) {
$phrase = str_replace( array( '"', "'", '&', "\r", "\n" ), array( '%22', "%27", '%26', '
','
' ), $phrase);
}
/*
* Update unused_args to remove used keyword.
*/
if ( ! empty( $this->temp_data[$country]['unused_args'] ) ) {
$this->temp_data[$country]['unused_args'] = preg_replace( '!(&?)'.$keyword.'=[^&]*(\1?)&?!','\2', $this->temp_data[$country]['unused_args'] );
}
return $phrase;
}
/*****************************************************************************************/
/// Helper Functions
/*
* Get Item data either locally or from default locale
*/
function get_item_data ( $asin, $country, &$settings ) {
$item_data = $this->cached_query( $asin, $settings, True );
if ( $item_data['found'] ) {
if ( empty( $this->temp_data['asin'][$country] ) ) {
$this->temp_data['asin'][$country] = $asin;
}
} else if ( ! empty( $settings['localise'] ) && ( $country != $settings['home_cc'] ) ) {
$settings['default_cc'] = $settings['home_cc'];
$settings['localise'] = 0;
$item_data = $this->cached_query( $asin, $settings, True );
if ( ! empty($settings['home_links']) ) {
// ***** Not available just show home data & links *****
$this->temp_data[$country] = $this->temp_data[$settings['default_cc']];
} else {
$item_data['not_found'] = 1;
}
}
if ( $settings['debug'] && isset( $item_data['Error'] ) ) {
echo "";
}
return $item_data;
}
/*
* Use Templates to create appropriate URL
*/
function get_url( $url, $type, $data, $search, $cc, $settings ) {
// URL already created just drop out.
if ($url != '') return $url;
$link = $this->get_link_type( $type, $data['asin'], $cc, $search, $data );
/* If not standard localisation then populate the %MANUAL_CC% keyword */
if ( empty( $setting['localise'] ) && ( $cc != $settings['home_cc'] ) ) {
$manual_cc = $cc;
} else {
$manual_cc = '';
}
$links = $this->get_link_templates();
$text = $links[$link['type']];
$text = str_replace( array( '%ARG%', '%TLD%', '%TYPE%', '%CC%', '%MANUAL_CC%' ), array($link['term'], $data[$cc]['tld'], $link['type'], $cc, $manual_cc), $text);
return $text;
}
function create_popup ( $data, $text ) {
if ( ! $this->scripts_done ) {
$this->scripts_done = True;
add_action( 'wp_print_footer_scripts', array( $this, 'footer_scripts' ) );
}
// Need to check all locales...
$sep = '';
$term ='{';
$countries = array_keys($this->get_country_data());
foreach ( $countries as $country ) {
$link = $this->get_link_type ( $data['type'], $data['asin'], $country, $data['search'], $data['settings'] );
$term .= $sep. $country .' : \''.$link['type'].'-' . $link['term'] . '\'';
$sep = ',';
}
$term .= '}';
$script = 'onMouseOut="al_link_out()" onMouseOver="al_gen_multi('. rand() . ', ' . $term. ', \''. $data['cc']. '\', \'%CHAN%\');" ';
$script = str_replace ( ' URL[CC]
} else if ( ( $type == 'A' ) &&
! empty( $settings[$cc]['url'] ) )
{
$type = 'U';
$term = $settings[$cc]['url'];
// Search Links enabled and home ASIN available => search for ASIN[home]
} else if ( ! empty( $settings[$cc]['search_link'] ) && ! empty( $asin[$home_cc] ) ) {
$type = 'S';
$term = $search;
// No ASIN defined but URL defined
} else if ( empty( $asin[$home_cc] ) &&
! empty( $settings[$cc]['url'] ) )
{
$type = 'U';
$term = $settings[$cc]['url'];
// Home ASIN defined
} else if ( ! empty( $asin[$home_cc] ) ) {
$term = $asin[$home_cc];
} else if ( ! empty( $settings[$cc]['search_link'] ) ) {
$type = 'S';
$term = $search;
} else {
$type = 'X';
$term = ! empty( $settings[$home_cc]['url'] ) ? $settings[$home_cc]['url'][$cc] : '';
}
}
return array( 'type' => $type, 'term' => $term );
}
function inc_stats( $array, $element ) {
$this->stats[$array][$element] = isset( $this->stats[$array][$element] ) ? $this->stats[$array][$element] + 1 : 1;
}
function format_list ( $array, $key_info = array() ) {
/* Only process if it is an array, if it isn't then it probably has already been filtered. */
if ( ! is_array( $array ) ) return $array;
$class = isset( $key_info['Class'] ) ? $key_info['Class'] : 'al_'. $key_info['Keyword'];
$ul = '';
foreach ( $array as $item ) {
$ul .= '- '. $item . '
';
}
$ul .= '
';
return $ul;
}
function grab( $data, $keys, $default ) {
foreach ( $keys as $location ) {
$result = $data;
foreach ( $location as $key ) {
if ( isset( $result[$key] ) ) {
$result = $result[$key];
} else {
$result = NULL;
break;
}
}
if ( isset( $result ) ) return $result;
}
if ( empty( $keys ) ) return $data; // If no keys then return the whole item
return $default;
}
function cached_query( $request, $settings, $first_only = False ) {
$cc = $this->get_country( $settings );
$data = NULL;
/* If not a request then must be a standard ASIN Lookup */
if ( ! is_array( $request ) ) {
$asin = $request;
$this->inc_stats( 'lookups', $asin );
// Try and retrieve from the cache
$data[0] = $this->cache_lookup_item( $asin, $cc );
if ($data[0] !== NULL) {
$this->inc_stats( 'cache_hit', $asin );
return $first_only ? $data[0] : $data;
}
$this->inc_stats( 'cache_miss', $asin );
// Create query to retrieve the an item
$request = array();
$request['Operation'] = 'ItemLookup';
$request['ItemId'] = $asin;
$request['IdType'] = 'ASIN';
$request['ResponseGroup'] = $this->get_response_groups();
if (!empty($settings['condition'])) {
$request['Condition'] = $settings['condition'];
}
} else {
$request['ResponseGroup'] = $this->get_response_groups();
}
$pxml = $this->doQuery( $request, $settings );
if ( ! empty( $pxml['Items']['Item'] ) ) {
$data = array();
if ( array_key_exists( 'ASIN', $pxml['Items']['Item'] ) ) {
// Returned a single result (not in an array)
$items = array( $pxml['Items']['Item'] );
$this->inc_stats( 'aws_hit', $asin );
} else {
// Returned several results
$items = $pxml['Items']['Item'];
}
} else {
$this->inc_stats( 'aws_miss', $asin );
// Failed to return any results
$data['Error'] = ( isset( $pxml['Error'] )? $pxml['Error'] :
( isset( $pxml['Items']['Request']['Errors']['Error'] ) ?
$pxml['Items']['Request']['Errors']['Error'] : array( 'Message' => 'No Items Found', 'Code' => 'NoResults') ) );
$items = array( array( 'ASIN' => $asin, 'found' => 0, 'Error' => $data['Error'] ) );
}
$keywords = $this->get_keywords();
$partial = False;
/* Extract useful information from the xml */
for ( $index = 0; $index < count( $items ); $index++ ) {
$result = $items[$index];
foreach ( $keywords as $keyword => $key_info ) {
if ( ! empty( $key_info['Live'] ) && // Is a Live Keyword
isset( $key_info['Position'] ) && is_array( $key_info['Position'] ) ) // Has a pointer to what data to use
{
if ( ! empty( $settings['skip_slow'] ) && ! empty( $key_info['Slow'] ) ) {
/* Slow Callbacks skipped so flag partial data so as not to cache it */
$partial = True;
} else {
$key_data = $this->grab( $result,
$key_info['Position'],
isset( $key_info['Default'] ) ? ( is_array( $key_info['Default'] ) ? $key_info['Default'][$cc] : $key_info['Default'] ) : '-');
$key_info['Keyword'] = $keyword;
if ( isset( $key_info['Callback'] ) ) {
$key_data = call_user_func( $key_info['Callback'], $key_data, $key_info, $this, $data[$index]);
} else if ( isset( $key_info['Filter'] ) ) {
$key_data = apply_filters( $key_info['Filter'], $key_data, $key_info, $this, $data[$index]);
}
$data[$index][$keyword] = $key_data;
}
}
}
$data[$index]['found'] = isset( $result['found'] ) ? $result['found'] : '1';
$data[$index]['partial'] = $partial;
/* Save each item to the cache if it is enabled and got complete data */
if ( ! $partial &&
( $data[$index]['found'] ||
( $result['Error']['Code'] == 'AWS.InvalidParameterValue' ) ||
( $result['Error']['Code'] == 'AWS.ECommerceService.ItemNotAccessible' ) ) )
$this->cache_update_item( $data[$index]['asin'], $cc, $data[$index] );
}
return $first_only ? $data[0] : $data;
}
function doQuery( $request, $settings )
{
$li = $this->get_local_info( $settings );
$tld = $li['tld'];
/*
* It seems that although 'AssociateTag' is mandatory it is not currently
* validated.
*/
if ( ! isset( $request['AssociateTag'] ) ) $request['AssociateTag'] = 'dummy-tag';
return $this->aws_signed_request($tld, $request, $settings['pub_key'], $settings['priv_key']);
}
function aws_signed_request($region, $params, $public_key, $private_key)
{
return include('include/awsRequest.php');
}
} // End Class
// Create either Admin instance or Frontend instance of the Amazon Link Class.
if ( is_admin() ) {
include( 'include/amazonSearch.php' );
include( 'include/displayForm.php' );
include( 'include/amazon-link-admin-support.php' );
$awlfw = new Amazon_Link_Admin_Support();
} else {
$awlfw = new AmazonWishlist_For_WordPress();
}
} // End if exists
// Return a URL to Amazon given shortcode arguments 'args'.
function amazon_get_link( $args )
{
global $awlfw;
return $awlfw->shortcode_expand( array( 'args' => $args, 'template_content' => '%URL%' ) );
}
// Print the Amazon javascript to support the multinational popup
function amazon_scripts()
{
global $awlfw;
$awlfw->footer_scripts();
}
// Perform an AWS query given a request array.
function amazon_query( $request )
{
global $awlfw;
return $awlfw->doQuery( $request, $awlfw->get_default_settings() ); // Return response
}
// Perform cached query $request can be just an ASIN or a request array
function amazon_cached_query($request, $settings = NULL, $first_only = False)
{
global $awlfw;
if ($settings === NULL)
$settings = $awlfw->get_default_settings();
return $awlfw->cached_query($request, $settings, $first_only);
}
// Process shortcode args and return output.
function amazon_shortcode( $args )
{
global $awlfw;
$awlfw->in_post = False;
$awlfw->post_ID = NULL;
return $awlfw->shortcode_expand( array( 'args' => $args ) );
}
// Depreciated
function amazon_recommends( $categories = '1', $last = '30' )
{
global $awlfw;
return $awlfw->shortcode_expand( array( 'cat' => $categories, 'last' => $last ) );
}
// Depreciated
function amazon_make_links($args)
{
return amazon_shortcode($args);
}
// vim:set ts=3 sts=3 sw=3 st: et:
?>