PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/shopp/api/theme/storefront.php

https://bitbucket.org/sanders_nick/legacy-media
PHP | 1018 lines | 811 code | 166 blank | 41 comment | 266 complexity | a099153eadb9444e81e5cbd1f891c821 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1, GPL-2.0, BSD-3-Clause, GPL-3.0
  1. <?php
  2. /**
  3. * ShoppCatalogThemeAPI - Provided theme api tags.
  4. *
  5. * @version 1.0
  6. * @since 1.2
  7. * @package shopp
  8. * @subpackage ShoppCatalogThemeAPI
  9. *
  10. **/
  11. add_filter('shopp_themeapi_context_name', array('ShoppCatalogThemeAPI', '_context_name'));
  12. class ShoppCatalogThemeAPI implements ShoppAPI {
  13. static $context = 'Catalog'; // @todo transition to Storefront
  14. static $register = array(
  15. 'breadcrumb' => 'breadcrumb',
  16. 'businessname' => 'business_name',
  17. 'businessaddress' => 'business_address',
  18. 'categories' => 'categories',
  19. 'category' => 'category',
  20. 'collection' => 'category',
  21. 'categorylist' => 'category_list',
  22. 'display' => 'type',
  23. 'errors' => 'errors',
  24. 'type' => 'type',
  25. 'hascategories' => 'has_categories',
  26. 'isaccount' => 'is_account',
  27. 'iscart' => 'is_cart',
  28. 'iscategory' => 'is_taxonomy', // @deprecated in favor of istaxonomy
  29. 'istaxonomy' => 'is_taxonomy',
  30. 'iscollection' => 'is_collection',
  31. 'ischeckout' => 'is_checkout',
  32. 'islanding' => 'is_frontpage',
  33. 'isfrontpage' => 'is_frontpage',
  34. 'iscatalog' => 'is_catalog',
  35. 'isproduct' => 'is_product',
  36. 'orderbylist' => 'orderby_list',
  37. 'product' => 'product',
  38. 'recentshoppers' => 'recent_shoppers',
  39. 'search' => 'search',
  40. 'searchform' => 'search_form',
  41. 'sideproduct' => 'side_product',
  42. 'tagproducts' => 'tag_products',
  43. 'tagcloud' => 'tag_cloud',
  44. 'url' => 'url',
  45. 'views' => 'views',
  46. 'zoomoptions' => 'zoom_options',
  47. 'accountmenu' => 'account_menu',
  48. 'accountmenuitem' => 'account_menuitem',
  49. );
  50. static function _apicontext () { return 'catalog'; }
  51. static function _context_name ( $name ) {
  52. switch ( $name ) {
  53. case 'storefront':
  54. case 'catalog':
  55. return 'catalog';
  56. break;
  57. }
  58. return $name;
  59. }
  60. /**
  61. * _setobject - returns the global context object used in the shopp('product') call
  62. *
  63. * @author John Dillick
  64. * @since 1.2
  65. *
  66. **/
  67. static function _setobject ($Object, $object) {
  68. if ( is_object($Object) && is_a($Object, 'Catalog') ) return $Object;
  69. switch ( strtolower($object) ) {
  70. case 'storefront':
  71. case 'catalog':
  72. return ShoppCatalog();
  73. break;
  74. }
  75. return $Object; // not mine, do nothing
  76. }
  77. static function image ($result, $options, $O) {
  78. // Compatibility defaults
  79. $_size = 96;
  80. $_width = shopp_setting('gallery_thumbnail_width');
  81. $_height = shopp_setting('gallery_thumbnail_height');
  82. if (!$_width) $_width = $_size;
  83. if (!$_height) $_height = $_size;
  84. $defaults = array(
  85. 'img' => false,
  86. 'id' => false,
  87. 'index' => false,
  88. 'class' => '',
  89. 'setting' => '',
  90. 'width' => false,
  91. 'height' => false,
  92. 'size' => false,
  93. 'fit' => false,
  94. 'sharpen' => false,
  95. 'quality' => false,
  96. 'bg' => false,
  97. 'alt' => '',
  98. 'title' => '',
  99. 'zoom' => '',
  100. 'zoomfx' => 'shopp-zoom',
  101. 'property' => false
  102. );
  103. // Populate defaults from named image settings to allow specific overrides
  104. if (!empty($options['setting'])) {
  105. $setting = $options['setting'];
  106. $ImageSettings = ImageSettings::__instance();
  107. $settings = $ImageSettings->get($setting);
  108. if ($settings) $defaults = array_merge($defaults,$settings->options());
  109. }
  110. $options = array_merge($defaults,$options);
  111. extract($options);
  112. // Select image by database id
  113. if ($id !== false) {
  114. if (isset($O->images[$id])) $img = $O->images[$id];
  115. else {
  116. new ShoppError(sprintf('No %s image exists at with the specified database ID of %s.',get_class($O),$id),'',SHOPP_DEBUG_ERR);
  117. return '';
  118. }
  119. }
  120. // Select image by index position in the list
  121. if ($index !== false){
  122. $keys = array_keys($O->images);
  123. if( isset($keys[$index]) && isset($O->images[ $keys[$index] ]) )
  124. $img = $O->images[$keys[$index]];
  125. else {
  126. new ShoppError(sprintf('No %s image exists at the specified index position %s.',get_class($O),$id),'',SHOPP_DEBUG_ERR);
  127. return '';
  128. }
  129. }
  130. // Use the current image pointer by default
  131. if (!$img) $img = current($O->images);
  132. if ($size !== false) $width = $height = $size;
  133. if (!$width) $width = $_width;
  134. if (!$height) $height = $_height;
  135. $scale = $fit?array_search($fit,$img->_scaling):false;
  136. $sharpen = $sharpen?min($sharpen,$img->_sharpen):false;
  137. $quality = $quality?min($quality,$img->_quality):false;
  138. $fill = $bg?hexdec(ltrim($bg,'#')):false;
  139. if ('transparent' == strtolower($bg)) $fill = -1;
  140. list($width_a,$height_a) = array_values($img->scaled($width,$height,$scale));
  141. if ($size == "original") {
  142. $width_a = $img->width;
  143. $height_a = $img->height;
  144. }
  145. if ($width_a === false) $width_a = $width;
  146. if ($height_a === false) $height_a = $height;
  147. $alt = esc_attr(empty($alt)?(empty($img->alt)?$img->name:$img->alt):$alt);
  148. $title = empty($title)?$img->title:$title;
  149. $titleattr = empty($title)?'':' title="'.esc_attr($title).'"';
  150. $classes = empty($class)?'':' class="'.esc_attr($class).'"';
  151. $src = shoppurl($img->id,'images');
  152. if ('' != get_option('permalink_structure')) $src = trailingslashit($src).$img->filename;
  153. if ($size != "original")
  154. $src = add_query_string($img->resizing($width,$height,$scale,$sharpen,$quality,$fill),$src);
  155. switch (strtolower($property)) {
  156. case "id": return $img->id; break;
  157. case "url":
  158. case "src": return $src; break;
  159. case "title": return $title; break;
  160. case "alt": return $alt; break;
  161. case "width": return $width_a; break;
  162. case "height": return $height_a; break;
  163. case "class": return $class; break;
  164. }
  165. $imgtag = '<img src="'.$src.'"'.$titleattr.' alt="'.$alt.'" width="'.$width_a.'" height="'.$height_a.'" '.$classes.' />';
  166. if (str_true($zoom))
  167. return '<a href="'.shoppurl($img->id,'images').'/'.$img->filename.'" class="'.$zoomfx.'" rel="product-'.$O->id.'"'.$titleattr.'>'.$imgtag.'</a>';
  168. return $imgtag;
  169. }
  170. static function breadcrumb ($result, $options, $O) {
  171. global $Shopp;
  172. $defaults = array(
  173. 'separator' => '&nbsp;&raquo; ',
  174. 'depth' => 7,
  175. 'wrap' => '<ul class="breadcrumb">',
  176. 'endwrap' => '</ul>',
  177. 'before' => '<li>',
  178. 'after' => '</li>'
  179. );
  180. $options = array_merge($defaults,$options);
  181. extract($options);
  182. $linked = $before.'%2$s<a href="%3$s">%1$s</a>'.$after;
  183. $list = $before.'%2$s<strong>%1$s</strong>'.$after;
  184. $Storefront = ShoppStorefront();
  185. $pages = Storefront::pages_settings();
  186. // store front page
  187. $breadcrumb = array($pages['catalog']['title'] => shoppurl(false,'catalog'));
  188. if (is_account_page()) {
  189. $breadcrumb += array($pages['account']['title'] => shoppurl(false,'account'));
  190. $request = $Storefront->account['request'];
  191. if (isset($Storefront->dashboard[$request]))
  192. $breadcrumb += array($Storefront->dashboard[$request]->label => shoppurl(false,'account'));
  193. } elseif (is_cart_page()) {
  194. $breadcrumb += array($pages['cart']['title'] => shoppurl(false,'cart'));
  195. } elseif (is_checkout_page()) {
  196. $breadcrumb += array($pages['cart']['title'] => shoppurl(false,'cart'));
  197. $breadcrumb += array($pages['checkout']['title'] => shoppurl(false,'checkout'));
  198. } elseif (is_confirm_page()) {
  199. $breadcrumb += array($pages['cart']['title'] => shoppurl(false,'cart'));
  200. $breadcrumb += array($pages['checkout']['title'] => shoppurl(false,'checkout'));
  201. $breadcrumb += array($pages['confirm']['title'] => shoppurl(false,'confirm'));
  202. } elseif (is_thanks_page()) {
  203. $breadcrumb += array($pages['thanks']['title'] => shoppurl(false,'thanks'));
  204. } elseif (is_shopp_taxonomy()) {
  205. $taxonomy = ShoppCollection()->taxonomy;
  206. $ancestors = array_reverse(get_ancestors(ShoppCollection()->id,$taxonomy));
  207. foreach ($ancestors as $ancestor) {
  208. $term = get_term($ancestor,$taxonomy);
  209. $breadcrumb[ $term->name ] = get_term_link($term->slug,$taxonomy);
  210. }
  211. $breadcrumb[ shopp('collection','get-name') ] = shopp('collection','get-url');
  212. } elseif (is_shopp_collection()) {
  213. // collections
  214. $breadcrumb[ ShoppCollection()->name ] = shopp('collection','get-url');
  215. } elseif (is_shopp_product()) {
  216. $categories = get_the_terms(ShoppProduct()->id,ProductCategory::$taxon);
  217. if ( $categories ) {
  218. $term = array_shift($categories);
  219. $ancestors = array_reverse(get_ancestors($term->term_id,ProductCategory::$taxon));
  220. foreach ($ancestors as $ancestor) {
  221. $parent_term = get_term($ancestor,ProductCategory::$taxon);
  222. $breadcrumb[ $parent_term->name ] = get_term_link($parent_term->slug,ProductCategory::$taxon);
  223. }
  224. $breadcrumb[ $term->name ] = get_term_link($term->slug,$term->taxonomy);
  225. }
  226. $breadcrumb[ shopp('product','get-name') ] = shopp('product','get-url');
  227. }
  228. $names = array_keys($breadcrumb);
  229. $last = end($names);
  230. $trail = '';
  231. foreach ($breadcrumb as $name => $link)
  232. $trail .= sprintf(($last == $name?$list:$linked),$name,(empty($trail)?'':$separator),$link);
  233. return $wrap.$trail.$endwrap;
  234. }
  235. static function business_name ($result, $options, $O) { return esc_html(shopp_setting('business_name')); }
  236. static function business_address ($result, $options, $O) { return esc_html(shopp_setting('business_address')); }
  237. static function categories ($result, $options, $O) {
  238. $null = null;
  239. if (!isset($O->_category_loop)) {
  240. reset($O->categories);
  241. ShoppCollection(current($O->categories));
  242. $O->_category_loop = true;
  243. } else {
  244. ShoppCollection(next($O->categories));
  245. }
  246. if (current($O->categories) !== false) return true;
  247. else {
  248. unset($O->_category_loop);
  249. reset($O->categories);
  250. ShoppCollection($null);
  251. if ( is_a(ShoppStorefront()->Requested, 'ProductCollection') ) ShoppCollection(ShoppStorefront()->Requested);
  252. return false;
  253. }
  254. }
  255. static function category ($result, $options, $O) {
  256. global $Shopp;
  257. $Storefront = ShoppStorefront();
  258. if (isset($options['name'])) ShoppCollection( new ProductCategory($options['name'],'name') );
  259. else if (isset($options['slug'])) ShoppCollection( new ProductCategory($options['slug'],'slug') );
  260. else if (isset($options['id'])) ShoppCollection( new ProductCategory($options['id']) );
  261. if (isset($options['reset']))
  262. return ( is_a($Storefront->Requested, 'ProductCollection') ? ( ShoppCollection($Storefront->Requested) ) : false );
  263. if (isset($options['title'])) ShoppCollection()->name = $options['title'];
  264. if (isset($options['show'])) ShoppCollection()->loading['limit'] = $options['show'];
  265. if (isset($options['pagination'])) ShoppCollection()->loading['pagination'] = $options['pagination'];
  266. if (isset($options['order'])) ShoppCollection()->loading['order'] = $options['order'];
  267. if (isset($options['load'])) return true;
  268. if (isset($options['controls']) && !value_is_true($options['controls']))
  269. ShoppCollection()->controls = false;
  270. if (isset($options['view'])) {
  271. if ($options['view'] == "grid") ShoppCollection()->view = "grid";
  272. else ShoppCollection()->view = "list";
  273. }
  274. ob_start();
  275. $templates = array('category.php','collection.php');
  276. $ids = array('slug','id');
  277. foreach ($ids as $property) {
  278. if (isset(ShoppCollection()->$property)) $id = ShoppCollection()->$property;
  279. array_unshift($templates,'category-'.$id.'.php','collection-'.$id.'.php');
  280. }
  281. locate_shopp_template($templates,true);
  282. $content = ob_get_contents();
  283. ob_end_clean();
  284. $Shopp->Category = false; // Reset the current category
  285. if (isset($options['wrap']) && str_true($options['wrap'])) $content = shoppdiv($content);
  286. return $content;
  287. }
  288. static function category_list ($result, $options, $O) {
  289. $defaults = array(
  290. 'title' => '',
  291. 'before' => '',
  292. 'after' => '',
  293. 'class' => '',
  294. 'exclude' => '',
  295. 'orderby' => 'name',
  296. 'order' => 'ASC',
  297. 'depth' => 0,
  298. 'level' => 0,
  299. 'childof' => 0,
  300. 'section' => false,
  301. 'parent' => false,
  302. 'showall' => false,
  303. 'linkall' => false,
  304. 'linkcount' => false,
  305. 'dropdown' => false,
  306. 'default' => __('Select category&hellip;','Shopp'),
  307. 'hierarchy' => false,
  308. 'products' => false,
  309. 'wraplist' => true,
  310. 'showsmart' => false
  311. );
  312. $options = array_merge($defaults,$options);
  313. extract($options, EXTR_SKIP);
  314. $taxonomy = 'shopp_category';
  315. $termargs = array('hide_empty' => 0,'fields'=>'id=>parent','orderby'=>$orderby,'order'=>$order);
  316. $baseparent = 0;
  317. if (str_true($section)) {
  318. if (!isset(ShoppCollection()->id)) return false;
  319. $sectionterm = ShoppCollection()->id;
  320. if (ShoppCollection()->parent == 0) $baseparent = $sectionterm;
  321. else $baseparent = end(get_ancestors($sectionterm,$taxonomy));
  322. }
  323. if (0 != $childof) $termargs['child_of'] = $baseparent = $childof;
  324. $O->categories = array(); $count = 0;
  325. $terms = get_terms( $taxonomy, $termargs );
  326. $children = _get_term_hierarchy($taxonomy);
  327. ProductCategory::tree($taxonomy,$terms,$children,$count,$O->categories,1,0,$baseparent);
  328. if ($showsmart == "before" || $showsmart == "after")
  329. $O->collections($showsmart);
  330. $categories = $O->categories;
  331. $string = "";
  332. if ($depth > 0) $level = $depth;
  333. $levellimit = $level;
  334. $exclude = explode(",",$exclude);
  335. $classes = ' class="shopp-categories-menu'.(empty($class)?'':' '.$class).'"';
  336. $wraplist = str_true($wraplist);
  337. $hierarchy = str_true($hierarchy);
  338. if (str_true($dropdown)) {
  339. if (!isset($default)) $default = __('Select category&hellip;','Shopp');
  340. $string .= $title;
  341. $string .= '<form action="/" method="get"><select name="shopp_cats" '.$classes.'>';
  342. $string .= '<option value="">'.$default.'</option>';
  343. foreach ($categories as &$category) {
  344. $link = $padding = $total = '';
  345. if ( ! isset($category->smart) ) {
  346. // If the parent of this category was excluded, add this to the excludes and skip
  347. if (!empty($category->parent) && in_array($category->parent,$exclude)) {
  348. $exclude[] = $category->id;
  349. continue;
  350. }
  351. if (!empty($category->id) && in_array($category->id,$exclude)) continue; // Skip excluded categories
  352. if ($category->count == 0 && !isset($category->smart) && !$category->_children && ! str_true($showall)) continue; // Only show categories with products
  353. if ($levellimit && $category->level >= $levellimit) continue;
  354. if ($hierarchy && $category->level > $level) {
  355. $parent = &$previous;
  356. if (!isset($parent->path)) $parent->path = '/'.$parent->slug;
  357. }
  358. if ($hierarchy)
  359. $padding = str_repeat("&nbsp;",$category->level*3);
  360. $term_id = $category->term_id;
  361. $link = get_term_link( (int) $category->term_id, $category->taxonomy);
  362. if (is_wp_error($link)) $link = '';
  363. $total = '';
  364. if ( str_true($products) && $category->count > 0) $total = ' ('.$category->count.')';
  365. } else {
  366. $category->level = 1;
  367. $namespace = get_class_property( 'SmartCollection' ,'namespace');
  368. $taxonomy = get_class_property( 'SmartCollection' ,'taxon');
  369. $prettyurls = ( '' != get_option('permalink_structure') );
  370. $link = shoppurl( $prettyurls ? "$namespace/{$category->slug}" : array($taxonomy=>$category->slug),false );
  371. }
  372. $string .=
  373. '<option value="'.$link.'">'.$padding.$category->name.$total.'</option>';
  374. $previous = &$category;
  375. $level = $category->level;
  376. }
  377. $string .= '</select></form>';
  378. } else {
  379. $depth = 0;
  380. $string .= $title;
  381. if ($wraplist) $string .= '<ul'.$classes.'>';
  382. $Collection = ShoppCollection();
  383. foreach ($categories as &$category) {
  384. if (!isset($category->count)) $category->count = 0;
  385. if (!isset($category->level)) $category->level = 0;
  386. // If the parent of this category was excluded, add this to the excludes and skip
  387. if (!empty($category->parent) && in_array($category->parent,$exclude)) {
  388. $exclude[] = $category->id;
  389. continue;
  390. }
  391. if (!empty($category->id) && in_array($category->id,$exclude)) continue; // Skip excluded categories
  392. if ($levellimit && $category->level >= $levellimit) continue;
  393. if ($hierarchy && $category->level > $depth) {
  394. $parent = &$previous;
  395. if (!isset($parent->path)) $parent->path = $parent->slug;
  396. if (substr($string,-5,5) == "</li>") // Keep everything but the
  397. $string = substr($string,0,-5); // last </li> to re-open the entry
  398. $active = '';
  399. if (isset($Collection->uri) && !empty($parent->slug)
  400. && preg_match('/(^|\/)'.$parent->path.'(\/|$)/',$Collection->uri)) {
  401. $active = ' active';
  402. }
  403. $subcategories = '<ul class="children'.$active.'">';
  404. $string .= $subcategories;
  405. }
  406. if ($hierarchy && $category->level < $depth) {
  407. for ($i = $depth; $i > $category->level; $i--) {
  408. if (substr($string,strlen($subcategories)*-1) == $subcategories) {
  409. // If the child menu is empty, remove the <ul> to avoid breaking standards
  410. $string = substr($string,0,strlen($subcategories)*-1).'</li>';
  411. } else $string .= '</ul></li>';
  412. }
  413. }
  414. if ( ! isset($category->smart) ) {
  415. $link = get_term_link( (int) $category->term_id,$category->taxonomy);
  416. if (is_wp_error($link)) $link = '';
  417. } else {
  418. $namespace = get_class_property( 'SmartCollection' ,'namespace');
  419. $taxonomy = get_class_property( 'SmartCollection' ,'taxon');
  420. $prettyurls = ( '' != get_option('permalink_structure') );
  421. $link = shoppurl( $prettyurls ? "$namespace/{$category->slug}" : array($taxonomy=>$category->slug),false );
  422. }
  423. $total = '';
  424. if ( str_true($products) && $category->count > 0 ) $total = ' <span>('.$category->count.')</span>';
  425. $current = '';
  426. if (isset($Collection->slug) && $Collection->slug == $category->slug)
  427. $current = ' class="current"';
  428. $listing = '';
  429. if (!empty($link) && ($category->count > 0 || isset($category->smart) || str_true($linkall)))
  430. $listing = '<a href="'.$link.'"'.$current.'>'.esc_html($category->name).($linkcount?$total:'').'</a>'.(!$linkcount?$total:'');
  431. else $listing = $category->name;
  432. if (str_true($showall) ||
  433. $category->count > 0 ||
  434. isset($category->smart) ||
  435. $category->_children)
  436. $string .= '<li'.$current.'>'.$listing.'</li>';
  437. $previous = &$category;
  438. $depth = $category->level;
  439. }
  440. if ($hierarchy && $depth > 0)
  441. for ($i = $depth; $i > 0; $i--) {
  442. if (substr($string,strlen($subcategories)*-1) == $subcategories) {
  443. // If the child menu is empty, remove the <ul> to avoid breaking standards
  444. $string = substr($string,0,strlen($subcategories)*-1).'</li>';
  445. } else $string .= '</ul></li>';
  446. }
  447. if ($wraplist) $string .= '</ul>';
  448. }
  449. return $string;
  450. break;
  451. }
  452. static function errors ($result, $options, $O) {
  453. $Errors = ShoppErrors();
  454. if (!$Errors->exist(SHOPP_COMM_ERR)) return false;
  455. $errors = $Errors->get(SHOPP_COMM_ERR);
  456. $defaults = array(
  457. 'before' => '<li>',
  458. 'after' => '</li>'
  459. );
  460. $options = array_merge($defaults,$options);
  461. extract($options);
  462. $result = "";
  463. foreach ( (array) $errors as $error )
  464. if ( is_a($error, 'ShoppError') && ! $error->blank() ) $result .= $before.$error->message(true).$after;
  465. return $result;
  466. }
  467. static function type ($result, $options, $O) { return $O->type; }
  468. static function has_categories ($result, $options, $O) {
  469. $showsmart = isset($options['showsmart'])?$options['showsmart']:false;
  470. if (empty($O->categories)) $O->load_categories(array('where'=>'true'),$showsmart);
  471. if (count($O->categories) > 0) return true; else return false;
  472. }
  473. static function is_account ($result, $options, $O) { return is_account_page(); }
  474. static function is_cart ($result, $options, $O) { return is_cart_page(); }
  475. static function is_catalog ($result, $options, $O) { return is_catalog_page(); }
  476. static function is_checkout ($result, $options, $O) { return is_checkout_page(); }
  477. static function is_collection ($result, $options, $O) { return is_shopp_collection(); }
  478. static function is_frontpage ($result, $options, $O) { return is_catalog_frontpage(); }
  479. static function is_product ($result, $options, $O) { return is_shopp_product(); }
  480. static function is_taxonomy ($result, $options, $O) { return is_shopp_taxonomy(); }
  481. static function orderby_list ($result, $options, $O) {
  482. $Collection = ShoppCollection();
  483. if (isset($Collection->controls)) return false;
  484. if (isset($Collection->loading['order']) || isset($Collection->loading['sortorder'])) return false;
  485. $menuoptions = ProductCategory::sortoptions();
  486. // Don't show custom product order for smart categories
  487. if ($Collection->smart) unset($menuoptions['custom']);
  488. $title = "";
  489. $string = "";
  490. $dropdown = isset($options['dropdown'])?$options['dropdown']:true;
  491. $default = shopp_setting('default_product_order');
  492. if (empty($default)) $default = "title";
  493. if (isset($options['default'])) $default = $options['default'];
  494. if (isset($options['title'])) $title = $options['title'];
  495. if (value_is_true($dropdown)) {
  496. $Storefront = ShoppStorefront();
  497. if (isset($Storefront->browsing['sortorder']))
  498. $default = $Storefront->browsing['sortorder'];
  499. $string .= $title;
  500. $string .= '<form action="'.esc_url($_SERVER['REQUEST_URI']).'" method="get" id="shopp-'.$Collection->slug.'-orderby-menu">';
  501. if ( '' == get_option('permalink_structure') ) {
  502. foreach ($_GET as $key => $value)
  503. if ($key != 's_ob') $string .= '<input type="hidden" name="'.$key.'" value="'.$value.'" />';
  504. }
  505. $string .= '<select name="s_so" class="shopp-orderby-menu">';
  506. $string .= menuoptions($menuoptions,$default,true);
  507. $string .= '</select>';
  508. $string .= '</form>';
  509. } else {
  510. $link = "";
  511. $query = "";
  512. if (strpos($_SERVER['REQUEST_URI'],"?") !== false)
  513. list($link,$query) = explode("\?",$_SERVER['REQUEST_URI']);
  514. $query = $_GET;
  515. unset($query['s_ob']);
  516. $query = http_build_query($query);
  517. if (!empty($query)) $query .= '&';
  518. foreach($menuoptions as $value => $option) {
  519. $label = $option;
  520. $href = esc_url(add_query_arg(array('s_so' => $value),$link));
  521. $string .= '<li><a href="'.$href.'">'.$label.'</a></li>';
  522. }
  523. }
  524. return $string;
  525. }
  526. static function product ($result, $options, $O) {
  527. global $Shopp;
  528. $Storefront = ShoppStorefront();
  529. if (isset($options['name'])) ShoppProduct(new Product($options['name'],'name'));
  530. else if (isset($options['slug'])) ShoppProduct(new Product($options['slug'],'slug'));
  531. else if (isset($options['id'])) ShoppProduct(new Product($options['id']));
  532. if (isset($options['reset']))
  533. return ( $Storefront->Requested && is_a($Storefront->Requested, 'Product') ? ShoppProduct($Storefront->Requested) : false );
  534. if (isset(ShoppProduct()->id) && isset($Shopp->Category->slug)) {
  535. $Category = clone($Shopp->Category);
  536. if (isset($options['load'])) {
  537. if ($options['load'] == "next") ShoppProduct($Category->adjacent_product(1));
  538. elseif ($options['load'] == "previous") ShoppProduct($Category->adjacent_product(-1));
  539. } else {
  540. if (isset($options['next']) && value_is_true($options['next']))
  541. ShoppProduct($Category->adjacent_product(1));
  542. elseif (isset($options['previous']) && value_is_true($options['previous']))
  543. ShoppProduct($Category->adjacent_product(-1));
  544. }
  545. }
  546. if (isset($options['load'])) return true;
  547. $Product = ShoppProduct();
  548. // Expand base template file names to support product-id and product-slug specific versions
  549. // product-id templates will be highest priority, followed by slug versions and the generic names
  550. $templates = isset($options['template']) ? $options['template'] : array('product.php');
  551. if (!is_array($templates)) $templates = explode(',',$templates);
  552. $idslugs = array();
  553. $reversed = array_reverse($templates);
  554. foreach ($reversed as $template) {
  555. list($basename,$php) = explode('.',$template);
  556. if (!empty($Product->slug)) array_unshift($idslugs,"$basename-$Product->slug.$php");
  557. if (!empty($Product->id)) array_unshift($idslugs,"$basename-$Product->id.$php");
  558. }
  559. $templates = array_merge($idslugs,$templates);
  560. ob_start();
  561. locate_shopp_template($templates,true);
  562. $content = ob_get_contents();
  563. ob_end_clean();
  564. return $content;
  565. }
  566. static function recent_shoppers ($result, $options, $O) {
  567. $defaults = array(
  568. 'abbr' => 'firstname',
  569. 'city' => true,
  570. 'state' => true,
  571. 'avatar' => true,
  572. 'size' => 48,
  573. 'show' => 5
  574. );
  575. $options = array_merge($defaults,$options);
  576. extract($options);
  577. $pt = DatabaseObject::tablename(Purchase::$table);
  578. $shoppers = DB::query("SELECT firstname,lastname,email,city,state FROM $pt AS pt GROUP BY customer ORDER BY created DESC LIMIT $show",'array');
  579. if (empty($shoppers)) return '';
  580. $_ = array();
  581. $_[] = '<ul>';
  582. foreach ($shoppers as $shopper) {
  583. if ('' == $shopper->firstname.$shopper->lastname) continue;
  584. if ('lastname' == $abbr) $name = "$shopper->firstname ".$shopper->lastname{0}.".";
  585. else $name = $shopper->firstname{0}.". $shopper->lastname";
  586. $img = '';
  587. if ($avatar) $img = get_avatar($shopper->email,$size,'',$name);
  588. $loc = '';
  589. if ($state || $province) $loc = $shopper->state;
  590. if ($city) $loc = "$shopper->city, $loc";
  591. $_[] = "<li><div>$img</div>$name <em>$loc</em></li>";
  592. }
  593. $_[] = '</ul>';
  594. return join('',$_);
  595. }
  596. static function search ($result, $options, $O) {
  597. $Storefront =& ShoppStorefront();
  598. global $wp;
  599. $defaults = array(
  600. 'type' => 'hidden',
  601. 'option' => 'shopp',
  602. 'blog_option' => __('Search the blog','Shopp'),
  603. 'shop_option' => __('Search the shop','Shopp'),
  604. 'label_before' => '',
  605. 'label_after' => '',
  606. 'checked' => false
  607. );
  608. $options = array_merge($defaults,$options);
  609. extract($options);
  610. $searching = is_search(); // Flag when searching (the blog or shopp)
  611. $shopsearch = ($Storefront !== false && $Storefront->searching); // Flag when searching shopp
  612. $allowed = array('accesskey','alt','checked','class','disabled','format', 'id',
  613. 'minlength','maxlength','readonly','required','size','src','tabindex','title','value');
  614. $options['value'] = ($option == 'shopp');
  615. // Reset the checked option
  616. unset($options['checked']);
  617. // If searching the blog, check the non-store search option
  618. if ($searching && !$shopsearch && $option != 'shopp') $options['checked'] = 'checked';
  619. // If searching the storefront, mark the store search option
  620. if ($shopsearch && $option == 'shopp') $options['checked'] = 'checked';
  621. // Override any other settings with the supplied default 'checked' option
  622. if (!$searching && $checked) $options['checked'] = $checked;
  623. switch ($type) {
  624. case 'checkbox':
  625. $input = '<input type="checkbox" name="s_cs"'.inputattrs($options,$allowed).' />';
  626. break;
  627. case 'radio':
  628. $input = '<input type="radio" name="s_cs"'.inputattrs($options,$allowed).' />';
  629. break;
  630. case 'menu':
  631. $allowed = array('accesskey','alt','class','disabled','format', 'id',
  632. 'readonly','required','size','tabindex','title');
  633. $input = '<select name="s_cs"'.inputattrs($options,$allowed).'>';
  634. $input .= '<option value="">'.$blog_option.'</option>';
  635. $input .= '<option value="1"'.($shopsearch || (!$searching && $option == 'shopp')?' selected="selected"':'').'>'.$shop_option.'</option>';
  636. $input .= '</select>';
  637. break;
  638. default:
  639. $allowed = array('alt','class','disabled','format','id','readonly','title','value');
  640. $input = '<input type="hidden" name="s_cs"'.inputattrs($options,$allowed).' />';
  641. break;
  642. }
  643. $before = (!empty($label_before))?'<label>'.$label_before:'<label>';
  644. $after = (!empty($label_after))?$label_after.'</label>':'</label>';
  645. return $before.$input.$after;
  646. }
  647. static function search_form ($result, $options, $O) {
  648. ob_start();
  649. get_search_form();
  650. $content = ob_get_contents();
  651. ob_end_clean();
  652. preg_match('/^(.*?<form[^>]*>)(.*?)(<\/form>.*?)$/is',$content,$_);
  653. list($all,$open,$content,$close) = $_;
  654. $markup = array(
  655. $open,
  656. $content,
  657. '<div><input type="hidden" name="s_cs" value="true" /></div>',
  658. $close
  659. );
  660. return join('',$markup);
  661. }
  662. static function side_product ($result, $options, $O) {
  663. global $Shopp;
  664. $content = false;
  665. $source = isset($options['source'])?$options['source']:'product';
  666. if ($source == 'product' && isset($options['product'])) {
  667. // Save original requested product
  668. if ($Shopp->Product) $Requested = $Shopp->Product;
  669. $products = explode(',',$options['product']);
  670. if (!is_array($products)) $products = array($products);
  671. foreach ($products as $product) {
  672. $product = trim($product);
  673. if (empty($product)) continue;
  674. if (preg_match('/^\d+$/',$product))
  675. $Shopp->Product = new Product($product);
  676. else $Shopp->Product = new Product($product,'slug');
  677. if (empty($Shopp->Product->id)) continue;
  678. if (isset($options['load'])) return true;
  679. ob_start();
  680. locate_shopp_template(array('sideproduct-'.$Shopp->Product->id.'.php','sideproduct.php'),true);
  681. $content .= ob_get_contents();
  682. ob_end_clean();
  683. }
  684. // Restore original requested Product
  685. if (!empty($Requested)) $Shopp->Product = $Requested;
  686. else $Shopp->Product = false;
  687. }
  688. if ($source == 'category' && isset($options['category'])) {
  689. // Save original requested category
  690. if ($Shopp->Category) $Requested = $Shopp->Category;
  691. if ($Shopp->Product) $RequestedProduct = $Shopp->Product;
  692. if (empty($options['category'])) return false;
  693. if ( in_array($options['category'],array_keys($Shopp->Collections)) ) {
  694. $Category = Catalog::load_collection($options['category'],$options);
  695. ShoppCollection($Category);
  696. } elseif ( intval($options['category']) > 0) { // By ID
  697. ShoppCollection( new ProductCategory($options['category']) );
  698. } else {
  699. ShoppCollection( new ProductCategory($options['category'],'slug') );
  700. }
  701. if (isset($options['load'])) return true;
  702. $options['load'] = array('coverimages');
  703. ShoppCollection()->load($options);
  704. $template = locate_shopp_template(array('sideproduct-'.$Shopp->Category->slug.'.php','sideproduct.php'));
  705. ob_start();
  706. foreach (ShoppCollection()->products as &$product) {
  707. ShoppProduct($product);
  708. load_template($template,false);
  709. }
  710. $content = ob_get_contents();
  711. ob_end_clean();
  712. // Restore original requested category
  713. if (!empty($Requested)) $Shopp->Category = $Requested;
  714. else $Shopp->Category = false;
  715. if (!empty($RequestedProduct)) $Shopp->Product = $RequestedProduct;
  716. else $Shopp->Product = false;
  717. }
  718. return $content;
  719. }
  720. static function tag_products ($result, $options, $O) {
  721. ShoppCollection( new TagProducts($options) );
  722. return self::category($result, $options, $O);
  723. }
  724. static function tag_cloud ($result, $options, $O) {
  725. $defaults = array(
  726. 'orderby' => 'name',
  727. 'order' => false,
  728. 'number' => 45,
  729. 'levels' => 7,
  730. 'format' => 'list',
  731. 'link' => 'view'
  732. );
  733. $options = array_merge($defaults,$options);
  734. extract($options);
  735. $tags = get_terms( ProductTag::$taxon, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number) );
  736. if (empty($tags)) return false;
  737. $min = $max = false;
  738. foreach ($tags as &$tag) {
  739. $min = !$min?$tag->count:min($min,$tag->count);
  740. $max = !$max?$tag->count:max($max,$tag->count);
  741. $link_function = ('edit' == $link?'get_edit_tag_link':'get_term_link');
  742. $tag->link = $link_function(intval($tag->term_id),ProductTag::$taxon);
  743. }
  744. // Sorting
  745. $sorted = apply_filters( 'tag_cloud_sort', $tags, $options );
  746. if ( $sorted != $tags ) $tags = &$sorted;
  747. else {
  748. if ( 'RAND' == $order ) shuffle($tags);
  749. else {
  750. if ( 'name' == $orderby )
  751. uasort( $tags, create_function('$a, $b', 'return strnatcasecmp($a->name, $b->name);') );
  752. else
  753. uasort( $tags, create_function('$a, $b', 'return ($a->count > $b->count);') );
  754. if ( 'DESC' == $order ) $tags = array_reverse( $tags, true );
  755. }
  756. }
  757. // Markup
  758. if ('inline' == $format) $markup = '<div class="shopp tagcloud">';
  759. if ('list' == $format) $markup = '<ul class="shopp tagcloud">';
  760. foreach ((array)$tags as $tag) {
  761. $level = floor((1-$tag->count/$max)*$levels)+1;
  762. if ('list' == $format) $markup .= '<li class="level-'.$level.'">';
  763. $markup .= '<a href="'.esc_url($tag->link).'" rel="tag">'.$tag->name.'</a>';
  764. if ('list' == $format) $markup .= '</li> ';
  765. }
  766. if ('list' == $format) $markup .= '</ul>';
  767. if ('inline' == $format) $markup .= '</div>';
  768. return $markup;
  769. }
  770. static function url ($result, $options, $O) { return shoppurl(false,'catalog'); }
  771. static function views ($result, $options, $O) {
  772. global $Shopp;
  773. if (isset($Shopp->Category->controls)) return false;
  774. $string = "";
  775. $string .= '<ul class="views">';
  776. if (isset($options['label'])) $string .= '<li>'.$options['label'].'</li>';
  777. $string .= '<li><button type="button" class="grid"></button></li>';
  778. $string .= '<li><button type="button" class="list"></button></li>';
  779. $string .= '</ul>';
  780. return $string;
  781. }
  782. static function zoom_options ($result, $options, $O) {
  783. $defaults = array( // Colorbox 1.3.15
  784. 'transition' => 'elastic', // The transition type. Can be set to 'elastic', 'fade', or 'none'.
  785. 'speed' => 350, // Sets the speed of the fade and elastic transitions, in milliseconds.
  786. 'href' => false, // This can be used as an alternative anchor URL or to associate a URL for non-anchor elements such as images or form buttons. Example: $('h1').colorbox({href:'welcome.html'})
  787. 'title' => false, // This can be used as an anchor title alternative for ColorBox.
  788. 'rel' => false, // This can be used as an anchor rel alternative for ColorBox. This allows the user to group any combination of elements together for a gallery, or to override an existing rel so elements are not grouped together. Example: $('#example a').colorbox({rel:'group1'}) Note: The value can also be set to 'nofollow' to disable grouping.
  789. 'width' => false, // Set a fixed total width. This includes borders and buttons. Example: '100%', '500px', or 500
  790. 'height' => false, // Set a fixed total height. This includes borders and buttons. Example: '100%', '500px', or 500
  791. 'innerWidth' => false, // This is an alternative to 'width' used to set a fixed inner width. This excludes borders and buttons. Example: '50%', '500px', or 500
  792. 'innerHeight' => false, // This is an alternative to 'height' used to set a fixed inner height. This excludes borders and buttons. Example: '50%', '500px', or 500
  793. 'initialWidth' => 300, // Set the initial width, prior to any content being loaded.
  794. 'initialHeight' => 100, // Set the initial height, prior to any content being loaded.
  795. 'maxWidth' => false, // Set a maximum width for loaded content. Example: '100%', 500, '500px'
  796. 'maxHeight' => false, // Set a maximum height for loaded content. Example: '100%', 500, '500px'
  797. 'scalePhotos' => true, // If 'true' and if maxWidth, maxHeight, innerWidth, innerHeight, width, or height have been defined, ColorBox will scale photos to fit within the those values.
  798. 'scrolling' => true, // If 'false' ColorBox will hide scrollbars for overflowing content. This could be used on conjunction with the resize method (see below) for a smoother transition if you are appending content to an already open instance of ColorBox.
  799. 'iframe' => false, // If 'true' specifies that content should be displayed in an iFrame.
  800. 'inline' => false, // If 'true' a jQuery selector can be used to display content from the current page. Example: $('#inline').colorbox({inline:true, href:'#myForm'});
  801. 'html' => false, // This allows an HTML string to be used directly instead of pulling content from another source (ajax, inline, or iframe). Example: $.colorbox({html:'<p>Hello</p>'});
  802. 'photo' => false, // If true, this setting forces ColorBox to display a link as a photo. Use this when automatic photo detection fails (such as using a url like 'photo.php' instead of 'photo.jpg', 'photo.jpg#1', or 'photo.jpg?pic=1')
  803. 'opacity' => 0.85, // The overlay opacity level. Range: 0 to 1.
  804. 'open' => false, // If true, the lightbox will automatically open with no input from the visitor.
  805. 'returnFocus' => true, // If true, focus will be returned when ColorBox exits to the element it was launched from.
  806. 'preloading' => true, // Allows for preloading of 'Next' and 'Previous' content in a shared relation group (same values for the 'rel' attribute), after the current content has finished loading. Set to 'false' to disable.
  807. 'overlayClose' => true, // If false, disables closing ColorBox by clicking on the background overlay.
  808. 'escKey' => true, // If false, will disable closing colorbox on esc key press.
  809. 'arrowKey' => true, // If false, will disable the left and right arrow keys from navigating between the items in a group.
  810. 'loop' => true, // If false, will disable the ability to loop back to the beginning of the group when on the last element.
  811. 'slideshow' => false, // If true, adds an automatic slideshow to a content group / gallery.
  812. 'slideshowSpeed' => 2500, // Sets the speed of the slideshow, in milliseconds.
  813. 'slideshowAuto' => true, // If true, the slideshow will automatically start to play.
  814. 'slideshowStart' => __('start slideshow','Shopp'), // Text for the slideshow start button.
  815. 'slideshowStop' => __('stop slideshow','Shopp'), // Text for the slideshow stop button
  816. 'previous' => __('previous','Shopp'), // Text for the previous button in a shared relation group (same values for 'rel' attribute).
  817. 'next' => __('next','Shopp'), // Text for the next button in a shared relation group (same values for 'rel' attribute).
  818. 'close' => __('close','Shopp'), // Text for the close button. The 'Esc' key will also close ColorBox.
  819. // Text format for the content group / gallery count. {current} and {total} are detected and replaced with actual numbers while ColorBox runs.
  820. 'current' => sprintf(__('image %s of %s','Shopp'),'{current}','{total}'),
  821. 'onOpen' => false, // Callback that fires right before ColorBox begins to open.
  822. 'onLoad' => false, // Callback that fires right before attempting to load the target content.
  823. 'onComplete' => false, // Callback that fires right after loaded content is displayed.
  824. 'onCleanup' => false, // Callback that fires at the start of the close process.
  825. 'onClosed' => false // Callback that fires once ColorBox is closed.
  826. );
  827. $options = array_diff($options, $defaults);
  828. $js = 'var cbo = '.json_encode($options).';';
  829. add_storefrontjs($js,true);
  830. }
  831. static function account_menu ($result, $options, $O) {
  832. $Storefront = ShoppStorefront();
  833. if (!isset($Storefront->_menu_looping)) {
  834. reset($Storefront->menus);
  835. $Storefront->_menu_looping = true;
  836. } else next($Storefront->menus);
  837. if (current($Storefront->menus) !== false) return true;
  838. else {
  839. unset($Storefront->_menu_looping);
  840. reset($Storefront->menus);
  841. return false;
  842. }
  843. }
  844. static function account_menuitem ($result, $options, $O) {
  845. $Storefront = ShoppStorefront();
  846. $page = current($Storefront->menus);
  847. if (array_key_exists('url',$options)) return add_query_arg($page->request,'',shoppurl(false,'account'));
  848. if (array_key_exists('action',$options)) return $page->request;
  849. return $page->label;
  850. }
  851. }
  852. ?>