*
*/
class AffiGet_Review_Element_Product_Details extends AffiGet_Abstract_Element
{
static protected $product_details;
static protected $link_attributes;
static protected $price_attributes;
static protected $complex_attributes;
protected $features;
const IDX_POS = 0;
const IDX_LBL = 1;
const IDX_VAL = 2;
const IDX_ACT = 3;
function __construct( AffiGet_Abstract_Meta $meta, $name, array $params ){
if( is_null( self::$product_details )){
self::$product_details = array(
'ASIN' => _x('ASIN', 'product attribute', 'afg'),
'Title' => _x('Title', 'product attribute', 'afg'),
'Author' => _x('Author', 'product attribute', 'afg'),
'Publisher' => _x('Publisher', 'product attribute', 'afg'),
'Binding' => _x('Binding', 'product attribute', 'afg'),
'Edition' => _x('Edition', 'product attribute', 'afg'),
'ISBN' => _x('ISBN-10', 'product attribute', 'afg'),
'Department' => _x('Department', 'product attribute', 'afg'),
'PublicationDate' => _x('Publication date', 'product attribute', 'afg'),
'NumberOfPages' => _x('Number of pages', 'product attribute', 'afg'),
'Languages' => _x('Languages', 'product attribute', 'afg'),
//'ItemDimensions' => _x('Item dimensions', 'product attribute', 'afg'),
'Label' => _x('Label', 'product attribute', 'afg'),
'Manufacturer' => _x('Manufacturer', 'product attribute', 'afg'),
'ProductGroup' => _x('Product group', 'product attribute', 'afg'),
'Studio' => _x('Studio', 'product attribute', 'afg'),
//'NumberOfItems' => _x('Number of items', 'product attribute', 'afg'),
//'PackageDimensions' => _x('Package dimensions', 'product attribute', 'afg'),
'ProductTypeName' => _x('Product type name', 'product attribute', 'afg'),
'ListPrice' => _x('List price', 'product attribute', 'afg'),
'LowestNewPrice' => _x('Lowest New Price', 'product attribute', 'afg'),
'LowestUsedPrice' => _x('Lowest Used Price', 'product attribute', 'afg'),
'LowestCollectiblePrice' => _x('Lowest Collectible Price', 'product attribute', 'afg'),
'LowestRefurbishedPrice' => _x('Lowest Refurbished Price', 'product attribute', 'afg'),
//'IsEligibleForTradeIn' => _x('Is eligible for trade-in', 'product attribute', 'afg'),
//'TradeInValue' => _x('Trade-in value', 'product attribute', 'afg'),
//'EANList' => _x('EAN list', 'product attribute', 'afg'),
//'EAN' => _x('EAN', 'product attribute', 'afg'),
'DetailPageURL' => _x('Product Details', 'link to product page', 'afg'),
'TechnicalDetails' => _x('Technical Details', 'link to product page', 'afg'),
'AddToBabyRegistry' => _x('Add To Baby Registry', 'link to product page', 'afg'),
'AddToWeddingRegistry' => _x('Add To Wedding Registry', 'link to product page', 'afg'),
'AddToWishlist' => _x('Add To Wishlist', 'link to product page', 'afg'),
'TellAFriend' => _x('Tell A Friend', 'link to product page', 'afg'),
'AllCustomerReviews' => _x('All Customer Reviews', 'link to product page', 'afg'),
'AllOffers' => _x('All Offers', 'link to product page', 'afg'),
);
self::$link_attributes = array(//requires anchor formatting
'DetailPageURL',
'TechnicalDetails',
'AddToBabyRegistry',
'AddToWeddingRegistry',
'AddToWishlist',
'TellAFriend',
'AllCustomerReviews',
'AllOffers',
);
self::$price_attributes = array(
'ListPrice',
'LowestNewPrice',
'LowestUsedPrice',
'LowestCollectiblePrice',
'LowestRefurbishedPrice',
);
self::$complex_attributes = array( //requires special formatting
'Languages',
'ItemDimensions',
'PackageDimensions',
'ProductTypeName',
'TradeInValue',
'IsEligibleForTradeIn',
);
}
if( isset( $params['features'] ) ){
$this->features = $params['features'];
} else {
$this->features = self::$product_details;
}
//must be resolved before parent constructor is called!
//(because it is used to resolve defaults for settings)
$this->features = apply_filters('afg_product_details_items', $this->features, $this->name );
//echo 'Features
'.print_r($this->features, true).''; parent::__construct( $meta, $name, $params ); //calls resolve_settings(), which calls get_settings_config() if( ! $this->is_status( AffiGet_Abstract_Element::STATUS_ENABLED ) ) return; $element_name = $this->name; add_action("afg_front__html_{$element_name}", array(&$this, 'front_html'), 10, 1); $meta_key = AFG_META_PREFIX . $this->name; add_filter( "sanitize_post_meta_{$meta_key}", array(&$this, 'sanitize_value' ), 10, 3); //metabox add_action( 'afg_review_renderer__register_metabox_fields', array(&$this, 'register_cmb2_fields')); add_action( "cmb2_render_{$this->control_id}", array(&$this, 'render_cmb2_field'), 10, 5 ); add_filter( "cmb2_types_esc_{$this->control_id}", array(&$this, 'escape_cmb2_field'), 10, 4 ); //assets add_action( 'admin_enqueue_scripts', array(&$this, 'enqueue_scripts_and_styles')); add_action( 'wp_enqueue_scripts', array(&$this, 'enqueue_scripts_and_styles')); add_action( 'afg_review_controller__inherit_from_latest_in_category', array(&$this, 'inherit_from_latest_in_category'), 10, 5 ); } protected function get_settings_config(){ $new_fields = array( 'available_items' => array( 'name' => 'available_items', 'atts' => 'size="55"', 'type' => 'text', 'default' => implode(',', apply_filters('afg_product_details_available_items', array_keys( $this->features ), $this->name )), 'label' => __('Enabled attributes', 'afg'), 'hint' => __('A comma-separated list, e.g.
Title,Author,Publisher,NumberOfPages,ISBN.', 'afg'),
'help' => __('Help'),
),
'visible_items' => array(
'name' => 'visible_items',
'atts' => 'size="55"',
'type' => 'text',
'default' => implode(',', apply_filters('afg_product_details_visible_items',
isset( $this->init_params['visible_attributes'] ) ? $this->init_params['visible_attributes'] : array('Title','Author','Edition','Binding','ISBN','Publisher','NumberOfPages','PublicationDate'),
$this->name )
),
'label' => __('Visible attributes', 'afg'),
'hint' => __('A comma-separated list, e.g. Title,Author,Publisher,NumberOfPages,Binding,ISBN,PublicationDate.', 'afg'),
'help' => __('Help'),
),
'display_format' => array(
'name' => 'display_format',
'atts' => '',
'type' => 'dropdown',
'options' => array(
'table' => __('Table - labels in first column (default)', 'afg'), /* labels in the first column */
'list' => __('List - labels in front of values', 'afg'), /* labels before values */
'form' => __('Form - small labels below values', 'afg'), /* small labels under values */
'divs' => __('Generic - divs and spans', 'afg'), /* divs and spans */
),
'default' => 'table',
'label' => __('Display format', 'afg'),
'hint' => __('', 'afg'),
'help' => __('Help'),
),
);
return array_merge( parent::get_settings_config(), $new_fields );
}
function register_cmb2_fields( &$fields ){
/*$fields[] = array(
'name' => $this->settings['title'],
//'desc' => __('Title to show on the front end.', 'afg'),
'id' => AFG_META_PREFIX . $this->name .'_heading',
'type' => 'title',
'position'=> $this->settings[ 'metabox_position' ],
//'default' => $this->settings['title'],
);*/
$post_type_name = $this->meta->post_type_name;
$fields[] = array(
'name' => 'value',
'desc' => $this->settings['description'],
'id' => '_' . AFG_META_PREFIX . $this->name, //prefixed with underscore to avoid showing a new entry in Custom fields
'type' => 'afg_product_details', /* will hook to cmb2_render_afg_product_details to render this */
//'options' => array( 'textarea_rows' => $this->settings[ 'textarea_rows' ] ),
'position'=> $this->settings[ 'metabox_position' ],
'metabox' => array(
'id' => $this->control_id. '_metabox',
'title' => $this->settings['label'],
'object_types' => array( $post_type_name ), // Post type
'context' => 'normal', //side/normal/advanced
'priority' => 'low', //high/core/default/low
'show_names' => false, // Show field names on the left
'cmb_styles' => false, // false to disable the CMB stylesheet
// 'closed' => true, // true to keep the metabox closed by default
)
);
}
function front_html( array $review_data ){
$post_id = $review_data['post_fields']['ID'];
$nonce = '';
if ( current_user_can('edit_post', $post_id )){
$nonce = wp_create_nonce("afg-update-{$post_id}");
}
ob_start();
$this->render_html( $post_id, null, $this->name, $this->control_id, $nonce );
$content = ob_get_clean();
if( $content ){
return $this->front_title() . $content;
}
return;
}
function render_cmb2_field( $field_args, $value, $post_id, $object_type, $field_type_object ){
if( $field_args->args['id'] === '_'.AFG_META_PREFIX . $this->name ){
$nonce = '';
if ( current_user_can('edit_post', $post_id )){
$nonce = wp_create_nonce("afg-update-{$post_id}");
}
$this->render_html( $post_id, null, $this->name, AFG_META_PREFIX . $this->name, $nonce );
}
}
function escape_cmb2_field( $null, $meta_value, $args, $field ){
//if any non-null value is returned, dumb default escaping is avoided
//afg_log(__METHOD__, compact('null', 'meta_value', 'args', 'field'));
//short-circuit default escaping, as it results in PHP notices
//(because passed values cannot be easily converted to string)
return true;
}
protected function _prepare_items( &$items, $post_id, $fieldname ){
$encoded = false;
if( is_null( $items )){
if( $post_id && $fieldname == $this->name ){
$review_data = $this->meta->load_post( $post_id );
$items = $this->meta->pick_value( $review_data, $fieldname );
}
if( empty( $items )){
$items = $this->get_default_value( compact( 'post_id', 'fieldname' ));
}
$encoded = json_encode( $items );
} elseif( is_string( $items )){
$encoded = $items;
$items = json_decode( $items, $assoc = true );
} else {
$encoded = json_encode( $items );
}
return $encoded;
}
function render_html( $post_id, $items, $fieldname, $input_id, $nonce, $context = 'not-widget', $params = null ){
$format = $this->settings['display_format'];
printf('';
//print_r(get_post_meta($post_id));
//echo '';
}
protected function _render_items( $items, $format = 'table'){
$before = '';
$headers = '';
$between = '';
$template = '';
$after = '';
switch( $format ){
case 'divs':
$before = '';
$template = '%3$s%4$s';
$after = '';
break;
case 'list':
$before = '| %3$s | %4$s |
|---|
';
continue;
//throw new AffiGet_Exception('Unexpected attribute requested: ' . $attr );
}
$type = $this->get_attribute_type( $attr );
if( $prototype ){
$result[ $attr ] = array(
$type,
isset( $prototype[ $attr ][ self::IDX_LBL ]) ? $prototype[ $attr ][ self::IDX_LBL ]: '',
isset( $prototype[ $attr ][ self::IDX_VAL ]) ? $prototype[ $attr ][ self::IDX_VAL ]: '',
$preset ? $preset[ $attr ][ self::IDX_ACT ] : $prototype[ $attr ][ self::IDX_ACT ],
);
} else {
$result[ $attr ] = array(
$type,
$preset ? $preset[ $attr ][ self::IDX_LBL ] : $this->features[ $attr ], //standard label
$this->get_attribute_value( $attr, $type, $this->features[ $attr ], $product ),
$preset ? $preset[ $attr ][ self::IDX_ACT ] : ( in_array( $attr, $visible_attributes ) ? 1 : 0 )
);
}
// [0]: current position
// [1]: current label
// [2]: current value
// [3]: is currently visible
$i++;
}
if( $post_id && ! $prototype ){
update_post_meta( $post_id, AFG_META_PREFIX . $this->name, $result );
}
return $result;
}
protected function get_attribute_type( $attr ){
if( in_array( $attr, self::$link_attributes ) ){
return 'link';
} elseif( in_array( $attr, self::$price_attributes )){
return 'price';
} elseif('ItemDimensions' == $attr || 'PackageDimensions' == $attr ){
return 'dim';
}
return 'text';
}
protected function get_attribute_value( $attr, $type, $label, $product_data ){
$raw_value = $product_data ? $this->meta->pick_product_data_value( $product_data, $attr ) : '';
if( ! $raw_value ){
return '';
}
$value = $raw_value;
if( 'link' == $type ){
$value = array(
'href' => $value,
'title' => sprintf(
esc_attr_x('%s page on Amazon', '%s is link label, e.g. "Add To Wedding Registry"','afg'),
$label
),
'text' => $label
);
$value = apply_filters("afg_product_details_data_{$attr}", $value );
return $value;
} elseif( 'price' == $type ){
return $value['FormattedPrice']; //value contains Amount/CurrencyCode/FormattedPrice
} elseif( 'dim' == $type ){
return $value;///XXX: parse
} elseif( in_array( $attr, self::$complex_attributes )){
if( 'Languages' == $attr ){
$original = '';
$published = '';
foreach( $value as $lng ){
if( 'Published' == $lng['Type'] ){
$published = $lng['Name'];
} elseif( 'Original Language' == $lng['Type'] ){
$original = $lng['Name'];
}
}
return $published;
/*$value = '';
if( $published && $original && $published == $original ){
$value = $original;
} else {
if( $published ){
$value .= '';
$value .= _x('Published', 'label for publication language', 'afg');
$value .= ''.$published.'';
}
if( $original ){
$value .= $value ? '; ' : '';
$value .= '';
$value .= _x('Original', 'label for original language', 'afg');
$value .= ''.$original.'';
}
}
break;
*/
}
}
return $value;
}
protected function format_attribute_value( $attr, $type, $label, $value ){
if( 'link' == $type ){
$link_template = '%4$s';
$link_template = apply_filters("afg_product_details_display_template_{$attr}", $link_template );
$value = sprintf( $link_template,
esc_attr( $value['href'] ),
esc_attr( $attr ),
esc_attr( $value['title'] ),
esc_html( $value['text'] )
);
return $value;
}
if( 'price' == $type ){
//echo ''.print_r($value, true).'
';
if( ! empty( $value )){
//return esc_html( $value['FormattedPrice'] );
return esc_html( $value );
} else {
return '';
}
}
if( ! in_array( $attr, self::$complex_attributes )){
return esc_html( $value );
}
switch( $attr ){
/* case 'Languages':
$original = '';
$published = '';
foreach( $value as $lng ){
if( 'Published' == $lng['Type'] ){
$published = $lng['Name'];
} elseif( 'Original Language' == $lng['Type'] ){
$original = $lng['Name'];
}
}
$value = '';
if( $published && $original && $published == $original ){
$value = $original;
} else {
if( $published ){
$value .= '';
$value .= _x('Published', 'label for publication language', 'afg');
$value .= ''.$published.'';
}
if( $original ){
$value .= $value ? '; ' : '';
$value .= '';
$value .= _x('Original', 'label for original language', 'afg');
$value .= ''.$original.'';
}
}
break;
*/
case 'ItemDimensions':
case 'PackageDimensions':
case 'ProductTypeName':
//$value = esc_html( $value );XXX parse dimensions
break;
case 'TradeInValue':
$parts = explode('$', $value);
if( count( $parts ) == 2 ){
$value = '$' . $parts[1];//XXX support other currencies and price formats
}
break;
case 'IsEligibleForTradeIn':
$value = $value == '1' ? _x('Yes', 'eligible for trade-in', 'afg') : _x('No', 'not eligible for trade-in', 'afg');
break;
}
return esc_html( $value );
}
function inherit_from_latest_in_category( $post_id, $product_data, $is_new, $cats, $prototype_post_id ){
$params = array(
'post_id' => $post_id, //will take product_details from this post
);
if( $prototype_post_id ){
$preset = get_post_meta( $prototype_post_id, AFG_META_PREFIX . 'product_details', true );
if( $preset !== false ){
$params['widget_data'] = $preset; //will use configuration from this post's product_details
}
}
$result = $this->get_default_value( $params );
//note, the result will be cached to AFG_META_PREFIX . 'product_details'
}
function enqueue_scripts_and_styles( $hook ) {
if( $this->meta->is_review_style_needed() ){
wp_enqueue_style( 'afg-feature-list-style',
plugins_url( '/css/element.css', (__FILE__)),
array(),
AFG_VER
);
}
if( $this->meta->is_review_script_needed() ){
wp_enqueue_script( 'afg-feature-list-script',
plugins_url( '/js/element.js', (__FILE__)),
array(
'jquery',
'jquery-ui-core',
//'jquery-ui-draggable', //drag lists around
//'jquery-ui-droppable',
'jquery-ui-sortable', //sort items
'jquery-effects-core',
//'jquery-effects-pulsate' //pulsate when loosing focus without save
),
AFG_VER
);
$msg = array(
'modifyTableHint' => __('Modify product details', 'afg'),
'modifyTable' => __('Modify table', 'afg'),
'minimizeTableHint' => __('Exit the editing mode', 'afg'),
'minimizeTable' => __('Minimize table', 'afg'),
'hideItemHint' => __('Hide this item from your visitors', 'afg'),
'unhideItemHint' => __('Make this item visible to everyone', 'afg'),
'dragItemHint' => __('Drag this item to its new position', 'afg'),
);
$params = array(
'initialMode' => is_admin() ? 'editing': 'viewing',
'wpAjaxUrl' => admin_url('admin-ajax.php'),
'msg' => $msg
);
wp_localize_script('afg-feature-list-script', 'dummy;
window.affiget = window.affiget || {};
affiget.params = affiget.params || {};
affiget.params.feature_list', $params
);
}
} // end enqueue_scripts_and_styles
}
endif;
/* EOF */