&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'] = '%TEXT%'; } else if ( isset( $image ) ) { $settings[$cc]['template_content']= '%LINK_OPEN%%TEXT%%LINK_CLOSE%'; } else if ( isset( $thumb ) ) { $settings[$cc]['template_content']= '%LINK_OPEN%%TEXT%%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: ?>