function __construct () { parent::__construct(); global $Ecart; $this->urls['schema'] = 'http://checkout.google.com/schema/2'; $this->urls['checkout'] = array( 'live' => 'https://%s:%s@checkout.google.com/api/checkout/v2/merchantCheckout/Merchant/%s', 'test' => 'https://%s:%s@sandbox.google.com/checkout/api/checkout/v2/merchantCheckout/Merchant/%s' ); $this->urls['order'] = array( 'live' => 'https://%s:%s@checkout.google.com/api/checkout/v2/request/Merchant/%s', 'test' => 'https://%s:%s@sandbox.google.com/checkout/api/checkout/v2/request/Merchant/%s' ); $this->urls['button'] = array( 'live' => (is_ecart_secure()?'https':'http').'://checkout.google.com/buttons/checkout.gif', 'test' => (is_ecart_secure()?'https':'http').'://sandbox.google.com/checkout/buttons/checkout.gif' ); $this->merchant_calc_url = esc_url(add_query_string('_txnupdate=gc',ecarturl(false,'catalog',true))); $this->setup('id','key','apiurl'); $this->settings['merchant_email'] = $Ecart->Settings->get('merchant_email'); $this->settings['location'] = "en_US"; $base = $Ecart->Settings->get('base_operations'); if ($base['country'] == "GB") $this->settings['location'] = "en_UK"; $this->settings['base_operations'] = $Ecart->Settings->get('base_operations'); $this->settings['currency'] = $this->settings['base_operations']['currency']['code']; if (empty($this->settings['currency'])) $this->settings['currency'] = "USD"; $this->settings['taxes'] = $Ecart->Settings->get('taxrates'); if (isset($_GET['gctest'])) $this->order(''); add_action('ecart_txn_update',array(&$this,'notifications')); add_filter('ecart_checkout_submit_button',array(&$this,'submit'),10,3); add_action('get_header',array(&$this,'analytics')); add_filter('ecart_tag_cart_google',array($this,'cartcheckout')); add_action('parse_request',array(&$this,'intercept_cartcheckout')); }
/** * Provides support for the ecart('cartitem') tags * * @since 1.1 * * @return mixed **/ function tag ($id,$property,$options=array()) { global $Ecart; // Return strings with no options switch ($property) { case "id": return $id; case "product": return $this->product; case "name": return $this->name; case "type": return $this->type; case "link": case "url": return ecarturl(ECART_PRETTYURLS?$this->slug:array('ecart_pid'=>$this->product)); case "sku": return $this->sku; } $taxes = isset($options['taxes'])?value_is_true($options['taxes']):null; if (in_array($property,array('price','newprice','unitprice','total','tax','options'))) $taxes = ecart_taxrate($taxes,$this->taxable,$this) > 0?true:false; // Handle currency values $result = ""; switch ($property) { case "discount": $result = (float)$this->discount; break; case "unitprice": $result = (float)$this->unitprice+($taxes?$this->unittax:0); break; case "unittax": $result = (float)$this->unittax; break; case "discounts": $result = (float)$this->discounts; break; case "tax": $result = (float)$this->tax; break; case "total": $result = (float)$this->total+($taxes?($this->unittax*$this->quantity):0); break; } if (is_float($result)) { if (isset($options['currency']) && !value_is_true($options['currency'])) return $result; else return money($result); } // Handle values with complex options switch ($property) { case "taxrate": return percentage($this->taxrate*100,array('precision' => 1)); break; case "quantity": $result = $this->quantity; if ($this->type == "Donation" && $this->donation['var'] == "on") return $result; if (isset($options['input']) && $options['input'] == "menu") { if (!isset($options['value'])) $options['value'] = $this->quantity; if (!isset($options['options'])) $values = "1-15,20,25,30,35,40,45,50,60,70,80,90,100"; else $values = $options['options']; if (strpos($values,",") !== false) $values = explode(",",$values); else $values = array($values); $qtys = array(); foreach ($values as $value) { if (strpos($value,"-") !== false) { $value = explode("-",$value); if ($value[0] >= $value[1]) $qtys[] = $value[0]; else for ($i = $value[0]; $i < $value[1]+1; $i++) $qtys[] = $i; } else $qtys[] = $value; } $result = '<select name="items['.$id.']['.$property.']">'; foreach ($qtys as $qty) $result .= '<option'.(($qty == $this->quantity)?' selected="selected"':'').' value="'.$qty.'">'.$qty.'</option>'; $result .= '</select>'; } elseif (isset($options['input']) && valid_input($options['input'])) { if (!isset($options['size'])) $options['size'] = 5; if (!isset($options['value'])) $options['value'] = $this->quantity; $result = '<input type="'.$options['input'].'" name="items['.$id.']['.$property.']" id="items-'.$id.'-'.$property.'" '.inputattrs($options).'/>'; } else $result = $this->quantity; break; case "remove": $label = __("Remove"); if (isset($options['label'])) $label = $options['label']; if (isset($options['class'])) $class = ' class="'.$options['class'].'"'; else $class = ' class="remove"'; if (isset($options['input'])) { switch ($options['input']) { case "button": $result = '<button type="submit" name="remove['.$id.']" value="'.$id.'"'.$class.' tabindex="">'.$label.'</button>'; break; case "checkbox": $result = '<input type="checkbox" name="remove['.$id.']" value="'.$id.'"'.$class.' tabindex="" title="'.$label.'"/>'; break; } } else { $result = '<a href="'.href_add_query_arg(array('cart'=>'update','item'=>$id,'quantity'=>0),ecarturl(false,'cart')).'"'.$class.'>'.$label.'</a>'; } break; case "optionlabel": $result = $this->option->label; break; case "options": $class = ""; if (!isset($options['before'])) $options['before'] = ''; if (!isset($options['after'])) $options['after'] = ''; if (isset($options['show']) && strtolower($options['show']) == "selected") return (!empty($this->option->label))? $options['before'].$this->option->label.$options['after']:''; if (isset($options['class'])) $class = ' class="'.$options['class'].'" '; if (count($this->variations) > 1) { $result .= $options['before']; $result .= '<input type="hidden" name="items['.$id.'][product]" value="'.$this->product.'"/>'; $result .= ' <select name="items['.$id.'][price]" id="items-'.$id.'-price"'.$class.'>'; $result .= $this->options($this->priceline); $result .= '</select>'; $result .= $options['after']; } break; case "addons-list": case "addonslist": if (empty($this->addons)) return false; $defaults = array( 'before' => '', 'after' => '', 'class' => '', 'exclude' => '', 'prices' => true, ); $options = array_merge($defaults,$options); extract($options); $classes = !empty($class)?' class="'.join(' ',$class).'"':''; $excludes = explode(',',$exclude); $prices = value_is_true($prices); $result .= $before.'<ul'.$classes.'>'; foreach ($this->addons as $id => $addon) { if (in_array($addon->label,$excludes)) continue; $price = ($addon->onsale?$addon->promoprice:$addon->price); if ($this->taxrate > 0) $price = $price+($price*$this->taxrate); if ($prices) $pricing = " (".($addon->unitprice < 0?'-':'+').money($price).")"; $result .= '<li>'.$addon->label.$pricing.'</li>'; } $result .= '</ul>'.$after; return $result; break; case "hasinputs": case "has-inputs": return (count($this->data) > 0); break; case "inputs": if (!isset($this->_data_loop)) { reset($this->data); $this->_data_loop = true; } else next($this->data); if (current($this->data) !== false) return true; else { unset($this->_data_loop); reset($this->data); return false; } break; case "input": $data = current($this->data); $name = key($this->data); if (isset($options['name'])) return $name; return $data; break; case "inputs-list": case "inputslist": if (empty($this->data)) return false; $before = ""; $after = ""; $classes = ""; $excludes = array(); if (!empty($options['class'])) $classes = ' class="'.$options['class'].'"'; if (!empty($options['exclude'])) $excludes = explode(",",$options['exclude']); if (!empty($options['before'])) $before = $options['before']; if (!empty($options['after'])) $after = $options['after']; $result .= $before.'<ul'.$classes.'>'; foreach ($this->data as $name => $data) { if (in_array($name,$excludes)) continue; $result .= '<li><strong>'.$name.'</strong>: '.$data.'</li>'; } $result .= '</ul>'.$after; return $result; break; case "coverimage": case "thumbnail": $defaults = array( 'class' => '', 'width' => 48, 'height' => 48, 'size' => false, 'fit' => false, 'sharpen' => false, 'quality' => false, 'bg' => false, 'alt' => false, 'title' => false ); $options = array_merge($defaults,$options); extract($options); if ($this->image !== false) { $img = $this->image; if ($size !== false) $width = $height = $size; $scale = (!$fit)?false:esc_attr(array_search($fit,$img->_scaling)); $sharpen = (!$sharpen)?false:esc_attr(min($sharpen,$img->_sharpen)); $quality = (!$quality)?false:esc_attr(min($quality,$img->_quality)); $fill = (!$bg)?false:esc_attr(hexdec(ltrim($bg,'#'))); $scaled = $img->scaled($width,$height,$scale); $alt = empty($alt)?$img->alt:$alt; $title = empty($title)?$img->title:$title; $title = empty($title)?'':' title="'.esc_attr($title).'"'; $class = !empty($class)?' class="'.esc_attr($class).'"':''; if (!empty($options['title'])) $title = ' title="'.esc_attr($options['title']).'"'; $alt = esc_attr(!empty($img->alt)?$img->alt:$this->name); return '<img src="'.add_query_string($img->resizing($width,$height,$scale,$sharpen,$quality,$fill),ecarturl($img->id,'images')).'"'.$title.' alt="'.$alt.'" width="'.$scaled['width'].'" height="'.$scaled['height'].'"'.$class.' />'; } break; } if (!empty($result)) return $result; return false; }
/** * ecart('category','...') tags * * @since 1.0 * @version 1.1 * * @param string $property The property to handle * @param array $options (optional) The tag options to process * @return mixed **/ function tag ($property,$options=array()) { global $Ecart; $db = DB::get(); switch ($property) { case "link": case "url": return ecarturl(ECART_PRETTYURLS?'category/'.$this->uri:array('ecart_category'=>$this->id)); break; case "feed-url": case "feedurl": $uri = 'category/'.$this->uri; if ($this->slug == "tag") $uri = $this->slug.'/'.$this->tag; return ecarturl(ECART_PRETTYURLS?"$uri/feed":array('ecart_category'=>urldecode($this->uri),'src'=>'category_rss')); case "id": return $this->id; break; case "parent": return $this->parent; break; case "name": return $this->name; break; case "slug": return urldecode($this->slug); break; case "description": return wpautop($this->description); break; case "total": return $this->loaded?$this->total:false; break; case "has-products": case "loadproducts": case "load-products": case "hasproducts": if (empty($this->id) && empty($this->slug)) return false; if (isset($options['load'])) { $dataset = explode(",",$options['load']); $options['load'] = array(); foreach ($dataset as $name) $options['load'][] = trim($name); } else { $options['load'] = array('prices'); } if (!$this->loaded) $this->load_products($options); if (count($this->products) > 0) return true; else return false; break; case "products": if (!isset($this->_product_loop)) { reset($this->products); $Ecart->Product = current($this->products); $this->_pindex = 0; $this->_rindex = false; $this->_product_loop = true; } else { $Ecart->Product = next($this->products); $this->_pindex++; } if (current($this->products) !== false) return true; else { unset($this->_product_loop); $this->_pindex = 0; return false; } break; case "row": if (!isset($this->_rindex) || $this->_rindex === false) $this->_rindex = 0; else $this->_rindex++; if (empty($options['products'])) $options['products'] = $Ecart->Settings->get('row_products'); if (isset($this->_rindex) && $this->_rindex > 0 && $this->_rindex % $options['products'] == 0) return true; else return false; break; case "has-categories": case "hascategories": if (empty($this->children)) $this->load_children(); return (!empty($this->children)); break; case "is-subcategory": case "issubcategory": return ($this->parent != 0); break; case "subcategories": if (!isset($this->_children_loop)) { reset($this->children); $this->child = current($this->children); $this->_cindex = 0; $this->_children_loop = true; } else { $this->child = next($this->children); $this->_cindex++; } if ($this->child !== false) return true; else { unset($this->_children_loop); $this->_cindex = 0; $this->child = false; return false; } break; case "subcategory-list": if (isset($Ecart->Category->controls)) return false; $defaults = array( 'title' => '', 'before' => '', 'after' => '', 'class' => '', 'exclude' => '', 'orderby' => 'name', 'order' => 'ASC', 'depth' => 0, 'childof' => 0, 'parent' => false, 'showall' => false, 'linkall' => false, 'linkcount' => false, 'dropdown' => false, 'hierarchy' => false, 'products' => false, 'wraplist' => true, 'showsmart' => false ); $options = array_merge($defaults,$options); extract($options, EXTR_SKIP); if (!$this->children) $this->load_children(array('orderby'=>$orderby,'order'=>$order)); if (empty($this->children)) return false; $string = ""; $depthlimit = $depth; $depth = 0; $exclude = explode(",",$exclude); $classes = ' class="ecart_categories'.(empty($class)?'':' '.$class).'"'; $wraplist = value_is_true($wraplist); if (value_is_true($dropdown)) { $count = 0; $string .= $title; $string .= '<select name="ecart_cats" id="ecart-'.$this->slug.'-subcategories-menu" class="ecart-categories-menu">'; $string .= '<option value="">'.__('Select a sub-category…','Ecart').'</option>'; foreach ($this->children as &$category) { if (!empty($show) && $count+1 > $show) break; if (value_is_true($hierarchy) && $depthlimit && $category->depth >= $depthlimit) continue; if ($category->products == 0) continue; // Only show categories with products if (value_is_true($hierarchy) && $category->depth > $depth) { $parent = &$previous; if (!isset($parent->path)) $parent->path = '/'.$parent->slug; } $padding = str_repeat(" ",$category->depth*3); $category_uri = empty($category->id)?$category->uri:$category->id; $link = ECART_PRETTYURLS?ecarturl("category/$category->uri"):ecarturl(array('ecart_category'=>$category_uri)); $total = ''; if (value_is_true($products)) $total = ' ('.$category->products.')'; $string .= '<option value="'.htmlentities($link).'">'.$padding.$category->name.$total.'</option>'; $previous = &$category; $depth = $category->depth; $count++; } $string .= '</select>'; } else { if (!empty($class)) $classes = ' class="'.$class.'"'; $string .= $title.'<ul'.$classes.'>'; $count = 0; foreach ($this->children as &$category) { if (!isset($category->total)) $category->total = 0; if (!isset($category->depth)) $category->depth = 0; if (!empty($category->id) && in_array($category->id,$exclude)) continue; // Skip excluded categories if ($depthlimit && $category->depth >= $depthlimit) continue; if (value_is_true($hierarchy) && $category->depth > $depth) { $parent = &$previous; if (!isset($parent->path)) $parent->path = $parent->slug; $string = substr($string,0,-5); // Remove the previous </li> $active = ''; if (isset($Ecart->Category) && !empty($parent->slug) && preg_match('/(^|\/)'.$parent->path.'(\/|$)/',$Ecart->Category->uri)) { $active = ' active'; } $subcategories = '<ul class="children'.$active.'">'; $string .= $subcategories; } if (value_is_true($hierarchy) && $category->depth < $depth) { for ($i = $depth; $i > $category->depth; $i--) { if (substr($string,strlen($subcategories)*-1) == $subcategories) { // If the child menu is empty, remove the <ul> to avoid breaking standards $string = substr($string,0,strlen($subcategories)*-1).'</li>'; } else $string .= '</ul></li>'; } } $category_uri = empty($category->id)?$category->uri:$category->id; $link = ECART_PRETTYURLS? ecarturl("category/$category->uri"): ecarturl(array('ecart_category'=>$category_uri)); $total = ''; if (value_is_true($products) && $category->total > 0) $total = ' <span>('.$category->total.')</span>'; $current = ''; if (isset($Ecart->Category) && $Ecart->Category->slug == $category->slug) $current = ' class="current"'; $listing = ''; if ($category->total > 0 || isset($category->smart) || $linkall) $listing = '<a href="'.$link.'"'.$current.'>'.$category->name.($linkcount?$total:'').'</a>'.(!$linkcount?$total:''); else $listing = $category->name; if (value_is_true($showall) || $category->total > 0 || isset($category->smart) || $category->children) $string .= '<li'.$current.'>'.$listing.'</li>'; $previous = &$category; $depth = $category->depth; $count++; } if (value_is_true($hierarchy) && $depth > 0) for ($i = $depth; $i > 0; $i--) { if (substr($string,strlen($subcategories)*-1) == $subcategories) { // If the child menu is empty, remove the <ul> to avoid breaking standards $string = substr($string,0,strlen($subcategories)*-1).'</li>'; } else $string .= '</ul></li>'; } if ($wraplist) $string .= '</ul>'; } return $string; break; case "section-list": if (empty($this->id)) return false; if (isset($Ecart->Category->controls)) return false; if (empty($Ecart->Catalog->categories)) $Ecart->Catalog->load_categories(array("where"=>"(pd.status='publish' OR pd.id IS NULL)")); if (empty($Ecart->Catalog->categories)) return false; if (!$this->children) $this->load_children(); $defaults = array( 'title' => '', 'before' => '', 'after' => '', 'class' => '', 'classes' => '', 'exclude' => '', 'total' => '', 'current' => '', 'listing' => '', 'depth' => 0, 'parent' => false, 'showall' => false, 'linkall' => false, 'dropdown' => false, 'hierarchy' => false, 'products' => false, 'wraplist' => true ); $options = array_merge($defaults,$options); extract($options, EXTR_SKIP); $string = ""; $depthlimit = $depth; $depth = 0; $wraplist = value_is_true($wraplist); $exclude = explode(",",$exclude); $section = array(); // Identify root parent if (empty($this->id)) return false; $parent = '_'.$this->id; while($parent != 0) { if (!isset($Ecart->Catalog->categories[$parent])) break; if ($Ecart->Catalog->categories[$parent]->parent == 0 || $Ecart->Catalog->categories[$parent]->parent == $parent) break; $parent = '_'.$Ecart->Catalog->categories[$parent]->parent; } $root = $Ecart->Catalog->categories[$parent]; if ($this->id == $parent && empty($this->children)) return false; // Build the section $section[] = $root; $in = false; foreach ($Ecart->Catalog->categories as &$c) { if ($in && $c->depth == $root->depth) break; // Done if ($in) $section[] = $c; if (!$in && isset($c->id) && $c->id == $root->id) $in = true; } if (value_is_true($dropdown)) { $string .= $title; $string .= '<select name="ecart_cats" id="ecart-'.$this->slug.'-subcategories-menu" class="ecart-categories-menu">'; $string .= '<option value="">'.__('Select a sub-category…','Ecart').'</option>'; foreach ($section as &$category) { if (value_is_true($hierarchy) && $depthlimit && $category->depth >= $depthlimit) continue; if (in_array($category->id,$exclude)) continue; // Skip excluded categories if ($category->products == 0) continue; // Only show categories with products if (value_is_true($hierarchy) && $category->depth > $depth) { $parent = &$previous; if (!isset($parent->path)) $parent->path = '/'.$parent->slug; } $padding = str_repeat(" ",$category->depth*3); $category_uri = empty($category->id)?$category->uri:$category->id; $link = ECART_PRETTYURLS?ecarturl("category/$category->uri"):ecarturl(array('ecart_category'=>$category_uri)); $total = ''; if (value_is_true($products)) $total = ' ('.$category->total.')'; $string .= '<option value="'.htmlentities($link).'">'.$padding.$category->name.$total.'</option>'; $previous = &$category; $depth = $category->depth; } $string .= '</select>'; } else { if (!empty($class)) $classes = ' class="'.$class.'"'; $string .= $title; if ($wraplist) $string .= '<ul'.$classes.'>'; foreach ($section as &$category) { if (in_array($category->id,$exclude)) continue; // Skip excluded categories if (value_is_true($hierarchy) && $depthlimit && $category->depth >= $depthlimit) continue; if (value_is_true($hierarchy) && $category->depth > $depth) { $parent = &$previous; if (!isset($parent->path) && isset($parent->slug)) $parent->path = $parent->slug; $string = substr($string,0,-5); $string .= '<ul class="children">'; } if (value_is_true($hierarchy) && $category->depth < $depth) $string .= '</ul></li>'; $category_uri = empty($category->id)?$category->uri:$category->id; $link = ECART_PRETTYURLS?ecarturl("category/$category->uri"):ecarturl(array('ecart_category'=>$category_uri)); if (value_is_true($products)) $total = ' <span>('.$category->total.')</span>'; if ($category->total > 0 || isset($category->smart) || $linkall) $listing = '<a href="'.$link.'"'.$current.'>'.$category->name.$total.'</a>'; else $listing = $category->name; if (value_is_true($showall) || $category->total > 0 || $category->children) $string .= '<li>'.$listing.'</li>'; $previous = &$category; $depth = $category->depth; } if (value_is_true($hierarchy) && $depth > 0) for ($i = $depth; $i > 0; $i--) $string .= '</ul></li>'; if ($wraplist) $string .= '</ul>'; } return $string; break; case "pagination": if (!$this->paged) return ""; $defaults = array( 'label' => __("Pages:","Ecart"), 'next' => __("next","Ecart"), 'previous' => __("previous","Ecart"), 'jumpback' => '«', 'jumpfwd' => '»', 'show' => 1000, 'before' => '<div>', 'after' => '</div>' ); $options = array_merge($defaults,$options); extract($options); $_ = array(); if (isset($this->alpha) && $this->paged) { $_[] = $before.$label; $_[] = '<ul class="paging">'; foreach ($this->alpha as $alpha) { $link = $this->pagelink($alpha->letter); if ($alpha->total > 0) $_[] = '<li><a href="'.$link.'">'.$alpha->letter.'</a></li>'; else $_[] = '<li><span>'.$alpha->letter.'</span></li>'; } $_[] = '</ul>'; $_[] = $after; return join("\n",$_); } if ($this->pages > 1) { if ( $this->pages > $show ) $visible_pages = $show + 1; else $visible_pages = $this->pages + 1; $jumps = ceil($visible_pages/2); $_[] = $before.$label; $_[] = '<ul class="paging">'; if ( $this->page <= floor(($show) / 2) ) { $i = 1; } else { $i = $this->page - floor(($show) / 2); $visible_pages = $this->page + floor(($show) / 2) + 1; if ($visible_pages > $this->pages) $visible_pages = $this->pages + 1; if ($i > 1) { $link = $this->pagelink(1); $_[] = '<li><a href="'.$link.'">1</a></li>'; $pagenum = ($this->page - $jumps); if ($pagenum < 1) $pagenum = 1; $link = $this->pagelink($pagenum); $_[] = '<li><a href="'.$link.'">'.$jumpback.'</a></li>'; } } // Add previous button if (!empty($previous) && $this->page > 1) { $prev = $this->page-1; $link = $this->pagelink($prev); $_[] = '<li class="previous"><a href="'.$link.'">'.$previous.'</a></li>'; } else $_[] = '<li class="previous disabled">'.$previous.'</li>'; // end previous button while ($i < $visible_pages) { $link = $this->pagelink($i); if ( $i == $this->page ) $_[] = '<li class="active">'.$i.'</li>'; else $_[] = '<li><a href="'.$link.'">'.$i.'</a></li>'; $i++; } if ($this->pages > $visible_pages) { $pagenum = ($this->page + $jumps); if ($pagenum > $this->pages) $pagenum = $this->pages; $link = $this->pagelink($pagenum); $_[] = '<li><a href="'.$link.'">'.$jumpfwd.'</a></li>'; $_[] = '<li><a href="'.$link.'">'.$this->pages.'</a></li>'; } // Add next button if (!empty($next) && $this->page < $this->pages) { $pagenum = $this->page+1; $link = $this->pagelink($pagenum); $_[] = '<li class="next"><a href="'.$link.'">'.$next.'</a></li>'; } else $_[] = '<li class="next disabled">'.$next.'</li>'; $_[] = '</ul>'; $_[] = $after; } return join("\n",$_); break; case "has-faceted-menu": return ($this->facetedmenus == "on"); break; case "faceted-menu": if ($this->facetedmenus == "off") return; $output = ""; $CategoryFilters =& $Ecart->Flow->Controller->browsing[$this->slug]; $link = $_SERVER['REQUEST_URI']; if (!isset($options['cancel'])) $options['cancel'] = "X"; if (strpos($_SERVER['REQUEST_URI'],"?") !== false) list($link,$query) = explode("?",$_SERVER['REQUEST_URI']); $query = $_GET; $query = http_build_query($query); $link = esc_url($link).'?'.$query; $list = ""; if (is_array($CategoryFilters)) { foreach($CategoryFilters AS $facet => $filter) { $href = add_query_arg('ecart_catfilters['.urlencode($facet).']','',$link); if (preg_match('/^(.*?(\d+[\.\,\d]*).*?)\-(.*?(\d+[\.\,\d]*).*)$/',$filter,$matches)) { $label = $matches[1].' — '.$matches[3]; if ($matches[2] == 0) $label = __('Under ','Ecart').$matches[3]; if ($matches[4] == 0) $label = $matches[1].' '.__('and up','Ecart'); } else $label = $filter; if (!empty($filter)) $list .= '<li><strong>'.$facet.'</strong>: '.stripslashes($label).' <a href="'.$href.'=" class="cancel">'.$options['cancel'].'</a></li>'; } $output .= '<ul class="filters enabled">'.$list.'</ul>'; } if ($this->pricerange == "auto" && empty($CategoryFilters['Price'])) { if (!$this->loaded) $this->load_products(); $list = ""; $this->priceranges = auto_ranges($this->pricing['average'],$this->pricing['max'],$this->pricing['min']); foreach ($this->priceranges as $range) { $href = add_query_arg('ecart_catfilters[Price]',urlencode(money($range['min']).'-'.money($range['max'])),$link); $label = money($range['min']).' — '.money($range['max']-0.01); if ($range['min'] == 0) $label = __('Under ','Ecart').money($range['max']); elseif ($range['max'] == 0) $label = money($range['min']).' '.__('and up','Ecart'); $list .= '<li><a href="'.$href.'">'.$label.'</a></li>'; } if (!empty($this->priceranges)) $output .= '<h4>'.__('Price Range','Ecart').'</h4>'; $output .= '<ul>'.$list.'</ul>'; } $catalogtable = DatabaseObject::tablename(Catalog::$table); $producttable = DatabaseObject::tablename(Product::$table); $spectable = DatabaseObject::tablename(Spec::$table); $query = "SELECT spec.name,spec.value, IF(spec.numeral > 0,spec.name,spec.value) AS merge, count(*) AS total,avg(numeral) AS avg,max(numeral) AS max,min(numeral) AS min FROM $catalogtable AS cat LEFT JOIN $producttable AS p ON cat.product=p.id LEFT JOIN $spectable AS spec ON p.id=spec.parent AND spec.context='product' AND spec.type='spec' WHERE cat.parent=$this->id AND cat.type='category' AND spec.value != '' AND spec.value != '0' GROUP BY merge ORDER BY spec.name,merge"; $results = $db->query($query,AS_ARRAY); $specdata = array(); foreach ($results as $data) { if (isset($specdata[$data->name])) { if (!is_array($specdata[$data->name])) $specdata[$data->name] = array($specdata[$data->name]); $specdata[$data->name][] = $data; } else $specdata[$data->name] = $data; } if (is_array($this->specs)) { foreach ($this->specs as $spec) { $list = ""; if (!empty($CategoryFilters[$spec['name']])) continue; // For custom menu presets if ($spec['facetedmenu'] == "custom" && !empty($spec['options'])) { foreach ($spec['options'] as $option) { $href = add_query_arg('ecart_catfilters['.$spec['name'].']',urlencode($option['name']),$link); $list .= '<li><a href="'.$href.'">'.$option['name'].'</a></li>'; } $output .= '<h4>'.$spec['name'].'</h4><ul>'.$list.'</ul>'; // For preset ranges } elseif ($spec['facetedmenu'] == "ranges" && !empty($spec['options'])) { foreach ($spec['options'] as $i => $option) { $matches = array(); $format = '%s-%s'; $next = 0; if (isset($spec['options'][$i+1])) { if (preg_match('/(\d+[\.\,\d]*)/',$spec['options'][$i+1]['name'],$matches)) $next = $matches[0]; } $matches = array(); $range = array("min" => 0,"max" => 0); if (preg_match('/^(.*?)(\d+[\.\,\d]*)(.*)$/',$option['name'],$matches)) { $base = $matches[2]; $format = $matches[1].'%s'.$matches[3]; if (!isset($spec['options'][$i+1])) $range['min'] = $base; else $range = array("min" => $base, "max" => ($next-1)); } if ($i == 1) { $href = add_query_arg('ecart_catfilters['.$spec['name'].']', urlencode(sprintf($format,'0',$range['min'])),$link); $label = __('Under ','Ecart').sprintf($format,$range['min']); $list .= '<li><a href="'.$href.'">'.$label.'</a></li>'; } $href = add_query_arg('ecart_catfilters['.$spec['name'].']', urlencode(sprintf($format,$range['min'],$range['max'])), $link); $label = sprintf($format,$range['min']).' — '.sprintf($format,$range['max']); if ($range['max'] == 0) $label = sprintf($format,$range['min']).' '.__('and up','Ecart'); $list .= '<li><a href="'.$href.'">'.$label.'</a></li>'; } $output .= '<h4>'.$spec['name'].'</h4><ul>'.$list.'</ul>'; // For automatically building the menu options } elseif ($spec['facetedmenu'] == "auto" && isset($specdata[$spec['name']])) { if (is_array($specdata[$spec['name']])) { // Generate from text values foreach ($specdata[$spec['name']] as $option) { $href = add_query_arg('ecart_catfilters['.$spec['name'].']',urlencode($option->value),$link); $list .= '<li><a href="'.$href.'">'.$option->value.'</a></li>'; } $output .= '<h4>'.$spec['name'].'</h4><ul>'.$list.'</ul>'; } else { // Generate number ranges $format = '%s'; if (preg_match('/^(.*?)(\d+[\.\,\d]*)(.*)$/',$specdata[$spec['name']]->content,$matches)) $format = $matches[1].'%s'.$matches[3]; $ranges = auto_ranges($specdata[$spec['name']]->avg,$specdata[$spec['name']]->max,$specdata[$spec['name']]->min); foreach ($ranges as $range) { $href = add_query_arg('ecart_catfilters['.$spec['name'].']', urlencode($range['min'].'-'.$range['max']), $link); $label = sprintf($format,$range['min']).' — '.sprintf($format,$range['max']); if ($range['min'] == 0) $label = __('Under ','Ecart').sprintf($format,$range['max']); elseif ($range['max'] == 0) $label = sprintf($format,$range['min']).' '.__('and up','Ecart'); $list .= '<li><a href="'.$href.'">'.$label.'</a></li>'; } if (!empty($list)) $output .= '<h4>'.$spec['name'].'</h4>'; $output .= '<ul>'.$list.'</ul>'; } } } } return $output; break; case "hasimages": case "has-images": if (empty($this->images)) $this->load_images(); if (empty($this->images)) return false; return true; break; case "images": if (!isset($this->_images_loop)) { reset($this->images); $this->_images_loop = true; } else next($this->images); if (current($this->images) !== false) return true; else { unset($this->_images_loop); return false; } break; case "coverimage": case "thumbnail": // deprecated // Force select the first loaded image unset($options['id']); $options['index'] = 0; case "image": if (empty($this->images)) $this->load_images(); if (!(count($this->images) > 0)) return ""; // Compatibility defaults $_size = 96; $_width = $Ecart->Settings->get('gallery_thumbnail_width'); $_height = $Ecart->Settings->get('gallery_thumbnail_height'); if (!$_width) $_width = $_size; if (!$_height) $_height = $_size; $defaults = array( 'img' => false, 'id' => false, 'index' => false, 'class' => '', 'width' => false, 'height' => false, 'width_a' => false, 'height_a' => false, 'size' => false, 'fit' => false, 'sharpen' => false, 'quality' => false, 'bg' => false, 'alt' => '', 'title' => '', 'zoom' => '', 'zoomfx' => 'ecart-zoom', 'property' => false ); $options = array_merge($defaults,$options); extract($options); // Select image by database id if ($id !== false) { for ($i = 0; $i < count($this->images); $i++) { if ($img->id == $id) { $img = $this->images[$i]; break; } } if (!$img) return ""; } // Select image by index position in the list if ($index !== false && isset($this->images[$index])) $img = $this->images[$index]; // Use the current image pointer by default if (!$img) $img = current($this->images); if ($size !== false) $width = $height = $size; if (!$width) $width = $_width; if (!$height) $height = $_height; $scale = $fit?array_search($fit,$img->_scaling):false; $sharpen = $sharpen?min($sharpen,$img->_sharpen):false; $quality = $quality?min($quality,$img->_quality):false; $fill = $bg?hexdec(ltrim($bg,'#')):false; list($width_a,$height_a) = array_values($img->scaled($width,$height,$scale)); if ($size == "original") { $width_a = $img->width; $height_a = $img->height; } if ($width_a === false) $width_a = $width; if ($height_a === false) $height_a = $height; $alt = esc_attr(empty($alt)?(empty($img->alt)?$img->name:$img->alt):$alt); $title = empty($title)?$img->title:$title; $titleattr = empty($title)?'':' title="'.esc_attr($title).'"'; $classes = empty($class)?'':' class="'.esc_attr($class).'"'; $src = ecarturl($img->id,'images'); if ($size != "original") { $src = add_query_string( $img->resizing($width,$height,$scale,$sharpen,$quality,$fill), trailingslashit(ecarturl($img->id,'images')).$img->filename ); } switch (strtolower($property)) { case "id": return $img->id; break; case "url": case "src": return $src; break; case "title": return $title; break; case "alt": return $alt; break; case "width": return $width_a; break; case "height": return $height_a; break; case "class": return $class; break; } $imgtag = '<img src="'.$src.'"'.$titleattr.' alt="'.$alt.'" width="'.$width_a.'" height="'.$height_a.'" '.$classes.' />'; if (value_is_true($zoom)) return '<a href="'.ecarturl($img->id,'images').'/'.$img->filename.'" class="'.$zoomfx.'" rel="product-'.$this->id.'">'.$imgtag.'</a>'; return $imgtag; break; case "slideshow": $options['load'] = array('images'); if (!$this->loaded) $this->load_products($options); if (count($this->products) == 0) return false; $defaults = array( 'width' => '440', 'height' => '180', 'fit' => 'crop', 'fx' => 'fade', 'duration' => 1000, 'delay' => 7000, 'order' => 'normal' ); $options = array_merge($defaults,$options); extract($options, EXTR_SKIP); $href = ecarturl(ECART_PERMALINKS?trailingslashit('000'):'000','images'); $imgsrc = add_query_string("$width,$height",$href); $string = '<ul class="slideshow '.$fx.'-fx '.$order.'-order duration-'.$duration.' delay-'.$delay.'">'; $string .= '<li class="clear"><img src="'.$imgsrc.'" width="'.$width.'" height="'.$height.'" /></li>'; foreach ($this->products as $Product) { if (empty($Product->images)) continue; $string .= '<li><a href="'.$Product->tag('url').'">'; $string .= $Product->tag('image',array('width'=>$width,'height'=>$height,'fit'=>$fit)); $string .= '</a></li>'; } $string .= '</ul>'; return $string; break; case "carousel": $options['load'] = array('images'); if (!$this->loaded) $this->load_products($options); if (count($this->products) == 0) return false; $defaults = array( 'imagewidth' => '96', 'imageheight' => '96', 'fit' => 'all', 'duration' => 500 ); $options = array_merge($defaults,$options); extract($options, EXTR_SKIP); $string = '<div class="carousel duration-'.$duration.'">'; $string .= '<div class="frame">'; $string .= '<ul>'; foreach ($this->products as $Product) { if (empty($Product->images)) continue; $string .= '<li><a href="'.$Product->tag('url').'">'; $string .= $Product->tag('image',array('width'=>$imagewidth,'height'=>$imageheight,'fit'=>$fit)); $string .= '</a></li>'; } $string .= '</ul></div>'; $string .= '<button type="button" name="left" class="left"> </button>'; $string .= '<button type="button" name="right" class="right"> </button>'; $string .= '</div>'; return $string; break; } }
function tag ($property,$options=array()) { global $Ecart; $select_attrs = array('title','required','class','disabled','required','size','tabindex','accesskey'); $submit_attrs = array('title','class','value','disabled','tabindex','accesskey'); switch ($property) { case "link": case "url": return ecarturl(ECART_PRETTYURLS?$this->slug:array('ecart_pid'=>$this->id)); break; case "found": if (empty($this->id)) return false; $load = array('prices','images','specs','tags','categories'); if (isset($options['load'])) $load = explode(",",$options['load']); $this->load_data($load); return true; break; case "relevance": return (string)$this->score; break; case "id": return $this->id; break; case "name": return apply_filters('ecart_product_name',$this->name); break; case "slug": return $this->slug; break; case "summary": return apply_filters('ecart_product_summary',$this->summary); break; case "description": return apply_filters('ecart_product_description',$this->description); case "isfeatured": case "is-featured": return ($this->featured == "on"); break; case "price": case "saleprice": if (empty($this->prices)) $this->load_data(array('prices')); $defaults = array( 'taxes' => null, 'starting' => '' ); $options = array_merge($defaults,$options); extract($options); if (!is_null($taxes)) $taxes = value_is_true($taxes); $min = $this->min[$property]; $mintax = $this->min[$property.'_tax']; $max = $this->max[$property]; $maxtax = $this->max[$property.'_tax']; $taxrate = ecart_taxrate($taxes,$this->prices[0]->tax,$this); if ("saleprice" == $property) $pricetag = $this->prices[0]->promoprice; else $pricetag = $this->prices[0]->price; if (count($this->options) > 0) { $taxrate = ecart_taxrate($taxes,true,$this); $mintax = $mintax?$min*$taxrate:0; $maxtax = $maxtax?$max*$taxrate:0; if ($min == $max) return money($min+$mintax); else { if (!empty($starting)) return "$starting ".money($min+$mintax); return money($min+$mintax)." — ".money($max+$maxtax); } } else return money($pricetag+($pricetag*$taxrate)); break; case "taxrate": return ecart_taxrate(null,true,$this); break; case "weight": if(empty($this->prices)) $this->load_data(array('prices')); $defaults = array( 'unit' => $Ecart->Settings->get('weight_unit'), 'min' => $this->min['weight'], 'max' => $this->max['weight'], 'units' => true, 'convert' => false ); $options = array_merge($defaults,$options); extract($options); if(!isset($this->min['weight'])) return false; if ($convert !== false) { $min = convert_unit($min,$convert); $max = convert_unit($max,$convert); if (is_null($units)) $units = true; $unit = $convert; } $range = false; if ($min != $max) { $range = array($min,$max); sort($range); } $string = ($min == $max)?round($min,3):round($range[0],3)." - ".round($range[1],3); $string .= value_is_true($units) ? " $unit" : ""; return $string; break; case "onsale": if (empty($this->prices)) $this->load_data(array('prices')); if (empty($this->prices)) return false; return $this->onsale; break; case "has-savings": return ($this->onsale && $this->min['saved'] > 0); break; case "savings": if (empty($this->prices)) $this->load_data(array('prices')); if (!isset($options['taxes'])) $options['taxes'] = null; $taxrate = ecart_taxrate($options['taxes']); $range = false; if (!isset($options['show'])) $options['show'] = ''; if ($options['show'] == "%" || $options['show'] == "percent") { if ($this->options > 1) { if (round($this->min['savings']) != round($this->max['savings'])) { $range = array($this->min['savings'],$this->max['savings']); sort($range); } if (!$range) return percentage($this->min['savings'],array('precision' => 0)); // No price range else return percentage($range[0],array('precision' => 0))." — ".percentage($range[1],array('precision' => 0)); } else return percentage($this->max['savings'],array('precision' => 0)); } else { if ($this->options > 1) { if (round($this->min['saved']) != round($this->max['saved'])) { $range = array($this->min['saved'],$this->max['saved']); sort($range); } if (!$range) return money($this->min['saved']+($this->min['saved']*$taxrate)); // No price range else return money($range[0]+($range[0]*$taxrate))." — ".money($range[1]+($range[1]*$taxrate)); } else return money($this->max['saved']+($this->max['saved']*$taxrate)); } break; case "freeshipping": if (empty($this->prices)) $this->load_data(array('prices')); return $this->freeshipping; case "hasimages": case "has-images": if (empty($this->images)) $this->load_data(array('images')); return (!empty($this->images)); break; case "images": if (!$this->images) return false; if (!isset($this->_images_loop)) { reset($this->images); $this->_images_loop = true; } else next($this->images); if (current($this->images) !== false) return true; else { unset($this->_images_loop); return false; } break; case "coverimage": // Force select the first loaded image unset($options['id']); $options['index'] = 0; case "thumbnail": // deprecated case "image": if (empty($this->images)) $this->load_data(array('images')); if (!(count($this->images) > 0)) return ""; // Compatibility defaults $_size = 96; $_width = $Ecart->Settings->get('gallery_thumbnail_width'); $_height = $Ecart->Settings->get('gallery_thumbnail_height'); if (!$_width) $_width = $_size; if (!$_height) $_height = $_size; $defaults = array( 'img' => false, 'id' => false, 'index' => false, 'class' => '', 'width' => false, 'height' => false, 'size' => false, 'fit' => false, 'sharpen' => false, 'quality' => false, 'bg' => false, 'alt' => '', 'title' => '', 'zoom' => '', 'zoomfx' => 'ecart-zoom', 'property' => false ); $options = array_merge($defaults,$options); extract($options); // Select image by database id if ($id !== false) { for ($i = 0; $i < count($this->images); $i++) { if ($img->id == $id) { $img = $this->images[$i]; break; } } if (!$img) return ""; } // Select image by index position in the list if ($index !== false && isset($this->images[$index])) $img = $this->images[$index]; // Use the current image pointer by default if (!$img) $img = current($this->images); if ($size !== false) $width = $height = $size; if (!$width) $width = $_width; if (!$height) $height = $_height; $scale = $fit?array_search($fit,$img->_scaling):false; $sharpen = $sharpen?min($sharpen,$img->_sharpen):false; $quality = $quality?min($quality,$img->_quality):false; $fill = $bg?hexdec(ltrim($bg,'#')):false; list($width_a,$height_a) = array_values($img->scaled($width,$height,$scale)); if ($size == "original") { $width_a = $img->width; $height_a = $img->height; } if ($width_a === false) $width_a = $width; if ($height_a === false) $height_a = $height; $alt = esc_attr(empty($alt)?(empty($img->alt)?$img->name:$img->alt):$alt); $title = empty($title)?$img->title:$title; $titleattr = empty($title)?'':' title="'.esc_attr($title).'"'; $classes = empty($class)?'':' class="'.esc_attr($class).'"'; $src = ecarturl($img->id,'images'); if (ECART_PERMALINKS) $src = trailingslashit($src).$img->filename; if ($size != "original") $src = add_query_string($img->resizing($width,$height,$scale,$sharpen,$quality,$fill),$src); switch (strtolower($property)) { case "id": return $img->id; break; case "url": case "src": return $src; break; case "title": return $title; break; case "alt": return $alt; break; case "width": return $width_a; break; case "height": return $height_a; break; case "class": return $class; break; } $imgtag = '<img src="'.$src.'"'.$titleattr.' alt="'.$alt.'" width="'.$width_a.'" height="'.$height_a.'" '.$classes.' />'; if (value_is_true($zoom)) return '<a href="'.ecarturl($img->id,'images').'/'.$img->filename.'" class="'.$zoomfx.'" rel="product-'.$this->id.'">'.$imgtag.'</a>'; return $imgtag; break; case "gallery": if (empty($this->images)) $this->load_data(array('images')); if (empty($this->images)) return false; $styles = ''; $_size = 240; $_width = $Ecart->Settings->get('gallery_small_width'); $_height = $Ecart->Settings->get('gallery_small_height'); if (!$_width) $_width = $_size; if (!$_height) $_height = $_size; $defaults = array( // Layout settings 'margins' => 20, 'rowthumbs' => false, // 'thumbpos' => 'after', // Preview image settings 'p.size' => false, 'p.width' => false, 'p.height' => false, 'p.fit' => false, 'p.sharpen' => false, 'p.quality' => false, 'p.bg' => false, 'p.link' => true, 'rel' => '', // Thumbnail image settings 'thumbsize' => false, 'thumbwidth' => false, 'thumbheight' => false, 'thumbfit' => false, 'thumbsharpen' => false, 'thumbquality' => false, 'thumbbg' => false, // Effects settings 'zoomfx' => 'ecart-zoom', 'preview' => 'click', 'colorbox' => '{}' ); $optionset = array_merge($defaults,$options); // Translate dot names $options = array(); $keys = array_keys($optionset); foreach ($keys as $key) $options[str_replace('.','_',$key)] = $optionset[$key]; extract($options); if ($p_size > 0) $_width = $_height = $p_size; $width = $p_width > 0?$p_width:$_width; $height = $p_height > 0?$p_height:$_height; $preview_width = $width; $previews = '<ul class="previews">'; $firstPreview = true; // Find the max dimensions to use for the preview spacing image $maxwidth = $maxheight = 0; foreach ($this->images as $img) { $scale = $p_fit?false:array_search($p_fit,$img->_scaling); $scaled = $img->scaled($width,$height,$scale); $maxwidth = max($maxwidth,$scaled['width']); $maxheight = max($maxheight,$scaled['height']); } if ($maxwidth == 0) $maxwidth = $width; if ($maxheight == 0) $maxheight = $height; $p_link = value_is_true($p_link); foreach ($this->images as $img) { $scale = $p_fit?array_search($p_fit,$img->_scaling):false; $sharpen = $p_sharpen?min($p_sharpen,$img->_sharpen):false; $quality = $p_quality?min($p_quality,$img->_quality):false; $fill = $p_bg?hexdec(ltrim($p_bg,'#')):false; $scaled = $img->scaled($width,$height,$scale); if ($firstPreview) { // Adds "filler" image to reserve the dimensions in the DOM $href = ecarturl(ECART_PERMALINKS?trailingslashit('000'):'000','images'); $previews .= '<li id="preview-fill"'.(($firstPreview)?' class="fill"':'').'>'; $previews .= '<img src="'.add_query_string("$maxwidth,$maxheight",$href).'" alt=" " width="'.$maxwidth.'" height="'.$maxheight.'" />'; $previews .= '</li>'; } $title = !empty($img->title)?' title="'.esc_attr($img->title).'"':''; $alt = esc_attr(!empty($img->alt)?$img->alt:$img->filename); $previews .= '<li id="preview-'.$img->id.'"'.(($firstPreview)?' class="active"':'').'>'; $href = ecarturl(ECART_PERMALINKS?trailingslashit($img->id).$img->filename:$img->id,'images'); if ($p_link) $previews .= '<a href="'.$href.'" class="gallery product_'.$this->id.' '.$options['zoomfx'].'"'.(!empty($rel)?' rel="'.$rel.'"':'').'>'; // else $previews .= '<a name="preview-'.$img->id.'">'; // If links are turned off, leave the <a> so we don't break layout $previews .= '<img src="'.add_query_string($img->resizing($width,$height,$scale,$sharpen,$quality,$fill),ecarturl($img->id,'images')).'"'.$title.' alt="'.$alt.'" width="'.$scaled['width'].'" height="'.$scaled['height'].'" />'; if ($p_link) $previews .= '</a>'; $previews .= '</li>'; $firstPreview = false; } $previews .= '</ul>'; $thumbs = ""; $twidth = $preview_width+$margins; if (count($this->images) > 1) { $default_size = 64; $_thumbwidth = $Ecart->Settings->get('gallery_thumbnail_width'); $_thumbheight = $Ecart->Settings->get('gallery_thumbnail_height'); if (!$_thumbwidth) $_thumbwidth = $default_size; if (!$_thumbheight) $_thumbheight = $default_size; if ($thumbsize > 0) $thumbwidth = $thumbheight = $thumbsize; $width = $thumbwidth > 0?$thumbwidth:$_thumbwidth; $height = $thumbheight > 0?$thumbheight:$_thumbheight; $firstThumb = true; $thumbs = '<ul class="thumbnails">'; foreach ($this->images as $img) { $scale = $thumbfit?array_search($thumbfit,$img->_scaling):false; $sharpen = $thumbsharpen?min($thumbsharpen,$img->_sharpen):false; $quality = $thumbquality?min($thumbquality,$img->_quality):false; $fill = $thumbbg?hexdec(ltrim($thumbbg,'#')):false; $scaled = $img->scaled($width,$height,$scale); $title = !empty($img->title)?' title="'.esc_attr($img->title).'"':''; $alt = esc_attr(!empty($img->alt)?$img->alt:$img->name); $thumbs .= '<li id="thumbnail-'.$img->id.'" class="preview-'.$img->id.(($firstThumb)?' first':'').'">'; $thumbs .= '<img src="'.add_query_string($img->resizing($width,$height,$scale,$sharpen,$quality,$fill),ecarturl($img->id,'images')).'"'.$title.' alt="'.$alt.'" width="'.$scaled['width'].'" height="'.$scaled['height'].'" />'; $thumbs .= '</li>'."\n"; $firstThumb = false; } $thumbs .= '</ul>'; } if ($rowthumbs > 0) $twidth = ($width+$margins+2)*(int)$rowthumbs; $result = '<div id="gallery-'.$this->id.'" class="gallery">'.$previews.$thumbs.'</div>'; $script = "\t".'EcartGallery("#gallery-'.$this->id.'","'.$preview.'"'.($twidth?",$twidth":"").');'; add_storefrontjs($script); return $result; break; case "has-categories": if (empty($this->categories)) $this->load_data(array('categories')); if (count($this->categories) > 0) return true; else return false; break; case "categories": if (!isset($this->_categories_loop)) { reset($this->categories); $this->_categories_loop = true; } else next($this->categories); if (current($this->categories) !== false) return true; else { unset($this->_categories_loop); return false; } break; case "in-category": if (empty($this->categories)) $this->load_data(array('categories')); if (isset($options['id'])) $field = "id"; if (isset($options['name'])) $field = "name"; if (isset($options['slug'])) $field = "slug"; foreach ($this->categories as $category) if ($category->{$field} == $options[$field]) return true; return false; case "category": $category = current($this->categories); if (isset($options['show'])) { if ($options['show'] == "id") return $category->id; if ($options['show'] == "slug") return $category->slug; } return $category->name; break; case "hastags": case "has-tags": if (empty($this->tags)) $this->load_data(array('tags')); if (count($this->tags) > 0) return true; else return false; break; case "tags": if (!isset($this->_tags_loop)) { reset($this->tags); $this->_tags_loop = true; } else next($this->tags); if (current($this->tags) !== false) return true; else { unset($this->_tags_loop); return false; } break; case "tagged": if (empty($this->tags)) $this->load_data(array('tags')); if (isset($options['id'])) $field = "id"; if (isset($options['name'])) $field = "name"; foreach ($this->tags as $tag) if ($tag->{$field} == $options[$field]) return true; return false; case "tag": $tag = current($this->tags); if (isset($options['show'])) { if ($options['show'] == "id") return $tag->id; } return $tag->name; break; case "hasspecs": case "has-specs": if (empty($this->specs)) $this->load_data(array('specs')); if (count($this->specs) > 0) { $this->merge_specs(); return true; } else return false; break; case "specs": if (!isset($this->_specs_loop)) { reset($this->specs); $this->_specs_loop = true; } else next($this->specs); if (current($this->specs) !== false) return true; else { unset($this->_specs_loop); return false; } break; case "spec": $string = ""; $separator = ": "; $delimiter = ", "; if (isset($options['separator'])) $separator = $options['separator']; if (isset($options['delimiter'])) $separator = $options['delimiter']; $spec = current($this->specs); if (is_array($spec->value)) $spec->value = join($delimiter,$spec->value); if (isset($options['name']) && !empty($options['name']) && isset($this->specskey[$options['name']])) { $spec = $this->specskey[$options['name']]; if (is_array($spec)) { if (isset($options['index'])) { foreach ($spec as $index => $entry) if ($index+1 == $options['index']) $content = $entry->value; } else { foreach ($spec as $entry) $contents[] = $entry->value; $content = join($delimiter,$contents); } } else $content = $spec->value; $string = apply_filters('ecart_product_spec',$content); return $string; } if (isset($options['name']) && isset($options['content'])) $string = "{$spec->name}{$separator}".apply_filters('ecart_product_spec',$spec->value); elseif (isset($options['name'])) $string = $spec->name; elseif (isset($options['content'])) $string = apply_filters('ecart_product_spec',$spec->value); else $string = "{$spec->name}{$separator}".apply_filters('ecart_product_spec',$spec->value); return $string; break; case "has-variations": return ($this->variations == "on" && (!empty($this->options['v']) || !empty($this->options))); break; case "variations": $string = ""; if (!isset($options['mode'])) { if (!isset($this->_prices_loop)) { reset($this->prices); $this->_prices_loop = true; } else next($this->prices); $price = current($this->prices); if ($price && ($price->type == 'N/A' || $price->context != 'variation')) next($this->prices); if (current($this->prices) !== false) return true; else { unset($this->_prices_loop); return false; } return true; } if ($this->outofstock) return false; // Completely out of stock, hide menus if (!isset($options['taxes'])) $options['taxes'] = null; $defaults = array( 'defaults' => '', 'disabled' => 'show', 'pricetags' => 'show', 'before_menu' => '', 'after_menu' => '', 'label' => 'on', 'required' => __('You must select the options for this item before you can add it to your shopping cart.','Ecart') ); $options = array_merge($defaults,$options); if ($options['mode'] == "single") { if (!empty($options['before_menu'])) $string .= $options['before_menu']."\n"; if (value_is_true($options['label'])) $string .= '<label for="product-options'.$this->id.'">'. __('Options').': </label> '."\n"; $string .= '<select name="products['.$this->id.'][price]" id="product-options'.$this->id.'">'; if (!empty($options['defaults'])) $string .= '<option value="">'.$options['defaults'].'</option>'."\n"; foreach ($this->prices as $pricetag) { if ($pricetag->context != "variation") continue; if (!isset($options['taxes'])) $taxrate = ecart_taxrate(null,$pricetag->tax); else $taxrate = ecart_taxrate(value_is_true($options['taxes']),$pricetag->tax); $currently = ($pricetag->sale == "on")?$pricetag->promoprice:$pricetag->price; $disabled = ($pricetag->inventory == "on" && $pricetag->stock == 0)?' disabled="disabled"':''; $price = ' ('.money($currently).')'; if ($pricetag->type != "N/A") $string .= '<option value="'.$pricetag->id.'"'.$disabled.'>'.$pricetag->label.$price.'</option>'."\n"; } $string .= '</select>'; if (!empty($options['after_menu'])) $string .= $options['after_menu']."\n"; } else { if (!isset($this->options)) return; $menuoptions = $this->options; if (!empty($this->options['v'])) $menuoptions = $this->options['v']; $baseop = $Ecart->Settings->get('base_operations'); $precision = $baseop['currency']['format']['precision']; if (!isset($options['taxes'])) $taxrate = ecart_taxrate(null,true,$this); else $taxrate = ecart_taxrate(value_is_true($options['taxes']),true,$this); $pricekeys = array(); foreach ($this->pricekey as $key => $pricing) { $filter = array(''); $_ = new StdClass(); if ($pricing->type != "Donation") $_->p = ((isset($pricing->onsale) && $pricing->onsale == "on")? (float)$pricing->promoprice: (float)$pricing->price); $_->i = ($pricing->inventory == "on"); $_->s = ($pricing->inventory == "on")?$pricing->stock:false; $_->tax = ($pricing->tax == "on"); $_->t = $pricing->type; $pricekeys[$key] = $_; } ob_start(); ?><?php if (!empty($options['defaults'])): ?> sjss.opdef = true; <?php endif; ?> <?php if (!empty($options['required'])): ?> sjss.opreq = "<?php echo $options['required']; ?>"; <?php endif; ?> pricetags[<?php echo $this->id; ?>] = <?php echo json_encode($pricekeys); ?>; new ProductOptionsMenus('select<?php if (!empty($Ecart->Category->slug)) echo ".category-".$Ecart->Category->slug; ?>.product<?php echo $this->id; ?>.options',{<?php if ($options['disabled'] == "hide") echo "disabled:false,"; ?><?php if ($options['pricetags'] == "hide") echo "pricetags:false,"; ?><?php if (!empty($taxrate)) echo "taxrate:$taxrate,"?>prices:pricetags[<?php echo $this->id; ?>]}); <?php $script = ob_get_contents(); ob_end_clean(); add_storefrontjs($script); foreach ($menuoptions as $id => $menu) { if (!empty($options['before_menu'])) $string .= $options['before_menu']."\n"; if (value_is_true($options['label'])) $string .= '<label for="options-'.$menu['id'].'">'.$menu['name'].'</label> '."\n"; $category_class = isset($Ecart->Category->slug)?'category-'.$Ecart->Category->slug:''; $string .= '<select name="products['.$this->id.'][options][]" class="'.$category_class.' product'.$this->id.' options" id="options-'.$menu['id'].'">'; if (!empty($options['defaults'])) $string .= '<option value="">'.$options['defaults'].'</option>'."\n"; foreach ($menu['options'] as $key => $option) $string .= '<option value="'.$option['id'].'">'.$option['name'].'</option>'."\n"; $string .= '</select>'; } if (!empty($options['after_menu'])) $string .= $options['after_menu']."\n"; } return $string; break; case "variation": $variation = current($this->prices); if (!isset($options['taxes'])) $options['taxes'] = null; else $options['taxes'] = value_is_true($options['taxes']); $taxrate = ecart_taxrate($options['taxes'],$variation->tax,$this); $weightunit = (isset($options['units']) && !value_is_true($options['units']) ) ? false : $Ecart->Settings->get('weight_unit'); $string = ''; if (array_key_exists('id',$options)) $string .= $variation->id; if (array_key_exists('label',$options)) $string .= $variation->label; if (array_key_exists('type',$options)) $string .= $variation->type; if (array_key_exists('sku',$options)) $string .= $variation->sku; if (array_key_exists('price',$options)) $string .= money($variation->price+($variation->price*$taxrate)); if (array_key_exists('saleprice',$options)) { if (isset($options['promos']) && !value_is_true($options['promos'])) { $string .= money($variation->saleprice+($variation->saleprice*$taxrate)); } else $string .= money($variation->promoprice+($variation->promoprice*$taxrate)); } if (array_key_exists('stock',$options)) $string .= $variation->stock; if (array_key_exists('weight',$options)) $string .= round($variation->weight, 3) . ($weightunit ? " $weightunit" : false); if (array_key_exists('shipfee',$options)) $string .= money(floatvalue($variation->shipfee)); if (array_key_exists('sale',$options)) return ($variation->sale == "on"); if (array_key_exists('shipping',$options)) return ($variation->shipping == "on"); if (array_key_exists('tax',$options)) return ($variation->tax == "on"); if (array_key_exists('inventory',$options)) return ($variation->inventory == "on"); return $string; break; case "has-addons": return ($this->addons == "on" && !empty($this->options['a'])); break; break; case "addons": $string = ""; if (!isset($options['mode'])) { if (!$this->priceloop) { reset($this->prices); $this->priceloop = true; } else next($this->prices); $thisprice = current($this->prices); if ($thisprice && $thisprice->type == "N/A") next($this->prices); if ($thisprice && $thisprice->context != "addon") next($this->prices); if (current($this->prices) !== false) return true; else { $this->priceloop = false; return false; } return true; } if ($this->outofstock) return false; // Completely out of stock, hide menus if (!isset($options['taxes'])) $options['taxes'] = null; $defaults = array( 'defaults' => '', 'disabled' => 'show', 'before_menu' => '', 'after_menu' => '' ); $options = array_merge($defaults,$options); if (!isset($options['label'])) $options['label'] = "on"; if (!isset($options['required'])) $options['required'] = __('You must select the options for this item before you can add it to your shopping cart.','Ecart'); if ($options['mode'] == "single") { if (!empty($options['before_menu'])) $string .= $options['before_menu']."\n"; if (value_is_true($options['label'])) $string .= '<label for="product-options'.$this->id.'">'. __('Options').': </label> '."\n"; $string .= '<select name="products['.$this->id.'][price]" id="product-options'.$this->id.'">'; if (!empty($options['defaults'])) $string .= '<option value="">'.$options['defaults'].'</option>'."\n"; foreach ($this->prices as $pricetag) { if ($pricetag->context != "addon") continue; if (isset($options['taxes'])) $taxrate = ecart_taxrate(value_is_true($options['taxes']),$pricetag->tax,$this); else $taxrate = ecart_taxrate(null,$pricetag->tax,$this); $currently = ($pricetag->sale == "on")?$pricetag->promoprice:$pricetag->price; $disabled = ($pricetag->inventory == "on" && $pricetag->stock == 0)?' disabled="disabled"':''; $price = ' ('.money($currently).')'; if ($pricetag->type != "N/A") $string .= '<option value="'.$pricetag->id.'"'.$disabled.'>'.$pricetag->label.$price.'</option>'."\n"; } $string .= '</select>'; if (!empty($options['after_menu'])) $string .= $options['after_menu']."\n"; } else { if (!isset($this->options['a'])) return; $taxrate = ecart_taxrate($options['taxes'],true,$this); // Index addon prices by option $pricing = array(); foreach ($this->prices as $pricetag) { if ($pricetag->context != "addon") continue; $pricing[$pricetag->options] = $pricetag; } foreach ($this->options['a'] as $id => $menu) { if (!empty($options['before_menu'])) $string .= $options['before_menu']."\n"; if (value_is_true($options['label'])) $string .= '<label for="options-'.$menu['id'].'">'.$menu['name'].'</label> '."\n"; $category_class = isset($Ecart->Category->slug)?'category-'.$Ecart->Category->slug:''; $string .= '<select name="products['.$this->id.'][addons][]" class="'.$category_class.' product'.$this->id.' addons" id="addons-'.$menu['id'].'">'; if (!empty($options['defaults'])) $string .= '<option value="">'.$options['defaults'].'</option>'."\n"; foreach ($menu['options'] as $key => $option) { $pricetag = $pricing[$option['id']]; if (isset($options['taxes'])) $taxrate = ecart_taxrate(value_is_true($options['taxes']),$pricetag->tax,$this); else $taxrate = ecart_taxrate(null,$pricetag->tax,$this); $currently = ($pricetag->sale == "on")?$pricetag->promoprice:$pricetag->price; if ($taxrate > 0) $currently = $currently+($currently*$taxrate); $string .= '<option value="'.$option['id'].'">'.$option['name'].' (+'.money($currently).')</option>'."\n"; } $string .= '</select>'; } if (!empty($options['after_menu'])) $string .= $options['after_menu']."\n"; } return $string; break; case "donation": case "amount": case "quantity": if ($this->outofstock) return false; $inputs = array('text','menu'); $defaults = array( 'value' => 1, 'input' => 'text', // accepts text,menu 'labelpos' => 'before', 'label' => '', 'options' => '1-15,20,25,30,40,50,75,100', 'size' => 3 ); $options = array_merge($defaults,$options); $_options = $options; extract($options); unset($_options['label']); // Interferes with the text input value when passed to inputattrs() $labeling = '<label for="quantity-'.$this->id.'">'.$label.'</label>'; if (!isset($this->_prices_loop)) reset($this->prices); $variation = current($this->prices); $_ = array(); if ("before" == $labelpos) $_[] = $labeling; if ("menu" == $input) { if ($this->inventory && $this->max['stock'] == 0) return ""; if (strpos($options,",") !== false) $options = explode(",",$options); else $options = array($options); $qtys = array(); foreach ((array)$options as $v) { if (strpos($v,"-") !== false) { $v = explode("-",$v); if ($v[0] >= $v[1]) $qtys[] = $v[0]; else for ($i = $v[0]; $i < $v[1]+1; $i++) $qtys[] = $i; } else $qtys[] = $v; } $_[] = '<select name="products['.$this->id.'][quantity]" id="quantity-'.$this->id.'">'; foreach ($qtys as $qty) { $amount = $qty; $selection = (isset($this->quantity))?$this->quantity:1; if ($variation->type == "Donation" && $variation->donation['var'] == "on") { if ($variation->donation['min'] == "on" && $amount < $variation->price) continue; $amount = money($amount); $selection = $variation->price; } else { if ($this->inventory && $amount > $this->max['stock']) continue; } $selected = ($qty==$selection)?' selected="selected"':''; $_[] = '<option'.$selected.' value="'.$qty.'">'.$amount.'</option>'; } $_[] = '</select>'; } elseif (valid_input($input)) { if ($variation->type == "Donation" && $variation->donation['var'] == "on") { if ($variation->donation['min']) $_options['value'] = $variation->price; $_options['class'] .= " currency"; } $_[] = '<input type="'.$input.'" name="products['.$this->id.'][quantity]" id="quantity-'.$this->id.'"'.inputattrs($_options).' />'; } if ("after" == $labelpos) $_[] = $labeling; return join("\n",$_); break; case "input": if (!isset($options['type']) || ($options['type'] != "menu" && $options['type'] != "textarea" && !valid_input($options['type']))) $options['type'] = "text"; if (!isset($options['name'])) return ""; if ($options['type'] == "menu") { $result = '<select name="products['.$this->id.'][data]['.$options['name'].']" id="data-'.$options['name'].'-'.$this->id.'"'.inputattrs($options,$select_attrs).'>'; if (isset($options['options'])) $menuoptions = preg_split('/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/',$options['options']); if (is_array($menuoptions)) { foreach($menuoptions as $option) { $selected = ""; $option = trim($option,'"'); if (isset($options['default']) && $options['default'] == $option) $selected = ' selected="selected"'; $result .= '<option value="'.$option.'"'.$selected.'>'.$option.'</option>'; } } $result .= '</select>'; } elseif ($options['type'] == "textarea") { if (isset($options['cols'])) $cols = ' cols="'.$options['cols'].'"'; if (isset($options['rows'])) $rows = ' rows="'.$options['rows'].'"'; $result .= '<textarea name="products['.$this->id.'][data]['.$options['name'].']" id="data-'.$options['name'].'-'.$this->id.'"'.$cols.$rows.inputattrs($options).'>'.$options['value'].'</textarea>'; } else { $result = '<input type="'.$options['type'].'" name="products['.$this->id.'][data]['.$options['name'].']" id="data-'.$options['name'].'-'.$this->id.'"'.inputattrs($options).' />'; } return $result; break; case "outofstock": if ($this->outofstock) { $label = isset($options['label'])?$options['label']:$Ecart->Settings->get('outofstock_text'); $string = '<span class="outofstock">'.$label.'</span>'; return $string; } else return false; break; case "buynow": if (!isset($options['value'])) $options['value'] = __("Buy Now","Ecart"); case "addtocart": if (!isset($options['class'])) $options['class'] = "addtocart"; else $options['class'] .= " addtocart"; if (!isset($options['value'])) $options['value'] = __("Add to Cart","Ecart"); $string = ""; if ($this->outofstock) { $string .= '<span class="outofstock">'.$Ecart->Settings->get('outofstock_text').'</span>'; return $string; } if (isset($options['redirect']) && !isset($options['ajax'])) $string .= '<input type="hidden" name="redirect" value="'.$options['redirect'].'" />'; $string .= '<input type="hidden" name="products['.$this->id.'][product]" value="'.$this->id.'" />'; if (!empty($this->prices[0]) && $this->prices[0]->type != "N/A") $string .= '<input type="hidden" name="products['.$this->id.'][price]" value="'.$this->prices[0]->id.'" />'; if (!empty($Ecart->Category)) { if (ECART_PRETTYURLS) $string .= '<input type="hidden" name="products['.$this->id.'][category]" value="'.$Ecart->Category->uri.'" />'; else $string .= '<input type="hidden" name="products['.$this->id.'][category]" value="'.((!empty($Ecart->Category->id))?$Ecart->Category->id:$Ecart->Category->slug).'" />'; } $string .= '<input type="hidden" name="cart" value="add" />'; if (isset($options['ajax'])) { if ($options['ajax'] == "html") $options['class'] .= ' ajax-html'; else $options['class'] .= " ajax"; $string .= '<input type="hidden" name="ajax" value="true" />'; $string .= '<input type="button" name="addtocart" '.inputattrs($options).' />'; } else { $string .= '<input type="submit" name="addtocart" '.inputattrs($options).' />'; } return $string; } }
/** * Iterates loaded products in buffered batches and generates a feed-friendly item record * * NOTE: To modify the output of the RSS generator, use * the filter hooks provided in a separate plugin or * in the theme functions.php file. * * @author Jonathan Davis * @since 1.0 * @version 1.1 * * @return string A feed item record **/ public function feed() { $paged = 100; // Buffer 100 products at a time. $loop = false; $product = ShoppProduct(); if ($product) { $loop = shopp($this, 'products'); if (!$loop) { $product = false; } else { $product = ShoppProduct(); } } if (!($product || $loop)) { if (!$this->products) { $page = 1; } else { $page = $this->page + 1; } if ($this->pages > 0 && $page > $this->pages) { return false; } $this->load(array('load' => array('prices', 'specs', 'categories', 'coverimages'), 'paged' => $paged, 'page' => $page)); $loop = shopp($this, 'products'); if (!$loop) { return false; } // Loop ended, bail out $product = ShoppProduct(); if (!$product) { return false; } // No products, bail } $item = array(); $item['guid'] = shopp($product, 'get-id'); $item['title'] = $product->name; $item['link'] = shopp($product, 'get-url'); $item['pubDate'] = date('D, d M Y H:i O', $product->publish); // Item Description $item['description'] = ''; $item['description'] .= '<table><tr>'; $Image = current($product->images); if (!empty($Image)) { $item['description'] .= '<td><a href="' . $item['link'] . '" title="' . $product->name . '">'; $item['description'] .= '<img src="' . esc_attr(add_query_string($Image->resizing(75, 75, 0), Shopp::url($Image->id, 'images'))) . '" alt="' . $product->name . '" width="75" height="75" />'; $item['description'] .= '</a></td>'; } $pricing = ""; $priceindex = 'price'; if (Shopp::str_true($product->sale)) { $priceindex = 'saleprice'; } if ($product->min[$priceindex] != $product->max[$priceindex]) { $pricing .= Shopp::__('from') . ' '; } $pricing .= money($product->min[$priceindex]); $item['description'] .= "<td><p><big>{$pricing}</big></p>"; $item['description'] .= apply_filters('shopp_rss_description', $product->summary, $product) . '</td></tr></table>'; $item['description'] = '<![CDATA[' . $item['description'] . ']]>'; // Google Base Namespace // http://www.google.com/support/merchants/bin/answer.py?hl=en&answer=188494 // Below are Google Base specific attributes // You can use the shopp_rss_item filter hook to add new item attributes or change the existing attributes if ($Image) { $item['g:image_link'] = add_query_string($Image->resizing(400, 400, 0), Shopp::url($Image->id, 'images')); } $item['g:condition'] = 'new'; $item['g:availability'] = shopp_setting_enabled('inventory') && $product->outofstock ? 'out of stock' : 'in stock'; $price = Shopp::floatval(Shopp::str_true($product->sale) ? $product->min['saleprice'] : $product->min['price']); if (!empty($price)) { $item['g:price'] = $price; $item['g:price_type'] = "starting"; } // Include product_type using Shopp category taxonomies foreach ($product->categories as $category) { $ancestry = array($category->name); $ancestors = get_ancestors($category->term_id, $category->taxonomy); foreach ((array) $ancestors as $ancestor) { $term = get_term($ancestor, $category->taxonomy); if ($term) { array_unshift($ancestry, $term->name); } } $item['g:product_type[' . $category->term_id . ']'] = join(' > ', $ancestry); } $brand = shopp($product, 'get-spec', 'name=Brand'); if (!empty($brand)) { $item['g:brand'] = $brand; } $gtins = array('UPC', 'EAN', 'JAN', 'ISBN-13', 'ISBN-10', 'ISBN'); foreach ($gtins as $id) { $gtin = shopp($product, 'get-spec', 'name=' . $id); if (!empty($gtin)) { $item['g:gtin'] = $gtin; break; } } $mpn = shopp($product, 'get-spec', 'name=MPN'); if (!empty($mpn)) { $item['g:mpn'] = $mpn; } // Check the product specs for matching Google Base information $g_props = array('MPN' => 'mpn', 'Color' => 'color', 'Material' => 'material', 'Pattern' => 'pattern', 'Size' => 'size', 'Gender' => 'gender', 'Age Group' => 'age_group', 'Google Product Category' => 'google_product_category'); foreach (apply_filters('shopp_googlebase_spec_map', $g_props) as $name => $key) { $value = shopp($product, 'get-spec', 'name=' . $name); if (!empty($value)) { $item["g:{$key}"] = $value; } } return apply_filters('shopp_rss_item', $item, $product); }
/** * Provides markup for a slideshow of cover images for products in the collection * * @api `shopp('collection.slideshow')` * @since 1.1 * * @param string $result The output * @param array $options The options * @param ShoppCollection $O The working object * @return string The slideshow markup **/ public static function slideshow($result, $options, $O) { $options['load'] = array('images'); if (!$O->loaded) { $O->load($options); } if (count($O->products) == 0) { return false; } $defaults = array('fx' => 'fade', 'duration' => 1000, 'delay' => 7000, 'order' => 'normal'); $imgdefaults = array('setting' => false, 'width' => '580', 'height' => '200', 'size' => false, 'fit' => 'crop', 'sharpen' => false, 'quality' => false, 'bg' => false); $options = array_merge($defaults, $imgdefaults, $options); extract($options, EXTR_SKIP); $href = Shopp::url('' != get_option('permalink_structure') ? trailingslashit('000') : '000', 'images'); $imgsrc = add_query_string("{$width},{$height}", $href); $string = '<ul class="slideshow ' . $fx . '-fx ' . $order . '-order duration-' . $duration . ' delay-' . $delay . '">'; $string .= '<li class="clear"><img src="' . $imgsrc . '" width="' . $width . '" height="' . $height . '" /></li>'; foreach ($O->products as $Product) { if (empty($Product->images)) { continue; } $string .= '<li><a href="' . $Product->tag('url') . '">'; $imgoptions = array_filter(array_intersect_key($options, $imgdefaults)); $string .= shopp($Product, 'get-image', $imgoptions); $string .= '</a></li>'; } $string .= '</ul>'; return $string; }