/** * Initializes the Shopp dashboard widgets * * @author Jonathan Davis * @since 1.0 * * @return void **/ public static function init() { $dashboard = shopp_setting('dashboard'); if (!(current_user_can('shopp_financials') && Shopp::str_true($dashboard))) { return false; } wp_add_dashboard_widget('dashboard_shopp_stats', __('Sales Stats', 'Shopp'), array(__CLASS__, 'stats_widget'), array('all_link' => '', 'feed_link' => '', 'width' => 'half', 'height' => 'single')); wp_add_dashboard_widget('dashboard_shopp_orders', __('Recent Orders', 'Shopp'), array(__CLASS__, 'orders_widget'), array('all_link' => 'admin.php?page=' . ShoppAdmin::pagename('orders'), 'feed_link' => '', 'width' => 'half', 'height' => 'single')); if (shopp_setting_enabled('inventory')) { wp_add_dashboard_widget('dashboard_shopp_inventory', __('Inventory Monitor', 'Shopp'), array(__CLASS__, 'inventory_widget'), array('all_link' => 'admin.php?page=' . ShoppAdmin::pagename('products'), 'feed_link' => '', 'width' => 'half', 'height' => 'single')); } add_action('admin_print_styles-index.php', array(__CLASS__, 'styles')); }
public function updates() { $builtin_path = SHOPP_PATH . '/templates'; $theme_path = sanitize_path(STYLESHEETPATH . '/shopp'); if (Shopp::str_true($this->form('theme_templates')) && !is_dir($theme_path)) { $this->form['theme_templates'] = 'off'; $this->notice(Shopp::__("Shopp theme templates can't be used because they don't exist."), 'error'); } if (empty($this->form('catalog_pagination'))) { $this->form['catalog_pagination'] = 0; } // Recount terms when this setting changes if ($this->form('outofstock_catalog') != shopp_setting('outofstock_catalog')) { $taxonomy = ProductCategory::$taxon; $terms = get_terms($taxonomy, array('hide_empty' => 0, 'fields' => 'ids')); if (!empty($terms)) { wp_update_term_count_now($terms, $taxonomy); } } shopp_set_formsettings(); $this->notice(Shopp::__('Presentation settings saved.'), 'notice', 20); }
if (!$even) { $classes[] = 'alternate'; } $even = !$even; if ($edit !== false && $edit === $index) { $conditions = array(); foreach ($rules as $ruleid => $rule) { $condition_template_data = array('${id}' => $edit, '${ruleid}' => $ruleid, '${property_menu}' => menuoptions($propertymenu, $rule['p'], true), '${rulevalue}' => esc_attr($rule['v'])); $conditions[] = str_replace(array_keys($condition_template_data), $condition_template_data, $conditional); } $localrates = array(); foreach ($locals as $localename => $localerate) { $localrateui_data = array('${id}' => $edit, '${localename}' => $localename, '${localerate}' => (double) $localerate); $localrates[] = str_replace(array_keys($localrateui_data), $localrateui_data, $localrateui); } $data = array('${id}' => $edit, '${rate}' => $rate, '${countries}' => menuoptions($countries, $country, true), '${zones}' => !empty($zones[$country]) ? menuoptions(array_merge(array('' => ''), $zones[$country]), $zone, true) : '', '${conditions}' => join('', $conditions), '${haslocals}' => $haslocals, '${localrates}' => join('', $localrates), '${errors}' => $localerror ? '<p class="error">' . $localerror . '</p>' : '', '${compounded}' => Shopp::str_true($compound) ? 'checked="checked"' : '', '${cancel_href}' => $this->url); if ($conditions) { $data['no-conditions'] = ''; } if (!empty($zones[$country])) { $data['no-zones'] = ''; } if ($haslocals) { $data['no-local-rates'] = ''; } else { $data['has-local-rates'] = ''; } if (count($locals) > 0) { $data['instructions'] = 'hidden'; } echo ShoppUI::template($editor, $data);
public function __construct(ShoppReportFramework $Report) { $this->ReportClass = get_class($Report); $this->options = $Report->options; $Report->load(); $this->columns = $Report->columns(); $this->data = $Report->data; $this->records = $Report->total; $report = $this->options['report']; $settings = shopp_setting("{$report}_report_export"); $this->headings = Shopp::str_true($settings['headers']); $this->selected = $settings['columns']; }
public function editor($Item) { extract($Item); $conditions = array(); foreach ($rules as $ruleid => $rule) { $conditionals = array('${id}' => $edit, '${ruleid}' => $ruleid, '${property_menu}' => $this->property_menu($rule['p']), '${rulevalue}' => esc_attr($rule['v'])); $conditions[] = str_replace(array_keys($conditionals), $conditionals, $this->template_conditional()); } $localrates = array(); foreach ($locals as $localename => $localerate) { $localrate_data = array('${id}' => $edit, '${localename}' => $localename, '${localerate}' => (double) $localerate); $localrates[] = str_replace(array_keys($localrate_data), $localrate_data, $this->template_localrate()); } $data = array('${id}' => $id, '${rate}' => percentage($rate, array('precision' => 4)), '${countries}' => menuoptions($this->countries, $country, true), '${zones}' => !empty($zones[$country]) ? menuoptions($zones[$country], $zone, true) : '', '${conditions}' => join('', $conditions), '${haslocals}' => $haslocals, '${localrates}' => join('', $localrates), '${instructions}' => $localerror ? '<p class="error">' . $localerror . '</p>' : $instructions, '${compounded}' => Shopp::str_true($compound) ? 'checked="checked"' : '', '${cancel_href}' => add_query_arg(array('id' => null, '_wpnonce' => null))); if ($conditions) { $data['no-conditions'] = ''; } if (!empty($zones[$country])) { $data['no-zones'] = ''; } if ($haslocals) { $data['no-local-rates'] = ''; } else { $data['has-local-rates'] = ''; } if (count($locals) > 0) { $data['instructions'] = 'hidden'; } echo ShoppUI::template($this->editor, $data); }
/** * Returns true or false if the setting is toggled on or off * * @api * @since 1.2 * * @param string $name The name of the setting * @return boolean True is enabled, false is disabled **/ function shopp_setting_enabled($name) { $setting = shopp_setting($name); return Shopp::str_true($setting); }
/** * Provides the subtotal amount of the cart * * @api `shopp('cart.subtotal')` * @since 1.0 * * @param string $result The output * @param array $options The options * - **wrap**: `on` (on, off) Wrap the amount in DOM-accessible markup * - **money**: `on` (on, off) Format the amount in the current currency format * - **number**: `off` (on, off) Provide the unformatted number (floating point) * - **taxes**: `on` (on, off) Include taxes in the subtotal amount when inclusive taxes are used (or off to exclude them) * @param ShoppCart $O The working object * @return string The subtotal amount **/ public static function subtotal($result, $options, $O) { $defaults = array('taxes' => 'on'); $options = array_merge($defaults, $options); extract($options, EXTR_SKIP); $subtotal = $O->total('order'); // Handle no-tax option for tax inclusive storefronts if (!Shopp::str_true($taxes) && shopp_setting_enabled('tax_inclusive')) { $tax = $O->Totals->entry('tax', 'Tax'); if (is_a($tax, 'OrderAmountItemTax')) { $subtotal -= $tax->amount(); } } return (double) $subtotal; }
/** * Provides a checkbox toggle to mark the shipping address as a residential address * * @api `shopp('checkout.residential-shipping-address')` * @since 1.2 * * @param string $result The output * @param array $options The options * - **label**: `Residential shipping address` The label for the checkbox input * - **checked**: `on` (on, off) Specifies that an `<input>` element should be pre-selected when the page loads * - **class**: The class attribute specifies one or more class-names for an element * - **title**: Specifies extra information about an element * @param ShoppOrder $O The working object * @return string Markup for the residential address checkbox toggle **/ public static function residential_shipping_address($result, $options, $O) { $allowed = array('class', 'checked', 'title'); $defaults = array('label' => Shopp::__('Residential shipping address'), 'checked' => 'on'); $options = array_merge($defaults, $options); extract($options); if (isset($O->Shipping->residential) && !Shopp::str_true($O->Shipping->residential) || !Shopp::str_true($checked)) { $options['checked'] = 'off'; } $_ = array(); $_[] = '<label for="residential-shipping">'; $_[] = '<input type="hidden" name="shipping[residential]" value="no" />'; $_[] = '<input type="checkbox" name="shipping[residential]" value="yes" id="residential-shipping"' . inputattrs($options, $allowed) . ' />'; $_[] = " {$label}</label>"; return join('', $_); }
function settings_meta_box($Product) { $Shopp = Shopp::object(); $Admin =& $Shopp->Flow->Admin; ?> <p><input type="hidden" name="featured" value="off" /><input type="checkbox" name="featured" value="on" id="featured" tabindex="12" <?php if ($Product->featured == "on") { echo ' checked="checked"'; } ?> /><label for="featured"> <?php _e('Featured Product', 'Shopp'); ?> </label></p> <p><input type="hidden" name="variants" value="off" /><input type="checkbox" name="variants" value="on" id="variations-setting" tabindex="13"<?php if ($Product->variants == "on") { echo ' checked="checked"'; } ?> /><label for="variations-setting"> <?php _e('Variants', 'Shopp'); echo $Admin->boxhelp('product-editor-variations'); ?> </label></p> <p><input type="hidden" name="addons" value="off" /><input type="checkbox" name="addons" value="on" id="addons-setting" tabindex="13"<?php if ($Product->addons == "on") { echo ' checked="checked"'; } ?> /><label for="addons-setting"> <?php _e('Add-ons', 'Shopp'); echo $Admin->boxhelp('product-editor-addons'); ?> </label></p> <?php if (shopp_setting_enabled('tax_inclusive')) { ?> <p><input type="hidden" name="meta[excludetax]" value="off" /><input type="checkbox" name="meta[excludetax]" value="on" id="excludetax-setting" tabindex="18" <?php if (isset($Product->meta['excludetax']) && Shopp::str_true($Product->meta['excludetax']->value)) { echo 'checked="checked"'; } ?> /> <label for="excludetax-setting"><?php _e('Exclude Taxes', 'Shopp'); ?> </label></p> <?php } ?> <?php if ($Shopp->Shipping->realtime) { ?> <p><input type="hidden" name="meta[packaging]" value="off" /><input type="checkbox" name="meta[packaging]" value="on" id="packaging-setting" tabindex="18" <?php if (isset($Product->meta['packaging']) && $Product->meta['packaging']->value == "on") { echo 'checked="checked"'; } ?> /> <label for="packaging-setting"><?php _e('Separate Packaging', 'Shopp'); ?> </label></p> <?php } ?> <p><input type="hidden" name="comment_status" value="closed" /><input type="checkbox" name="comment_status" value="open" id="allow-comments" tabindex="18" <?php if (Shopp::str_true($Product->comment_status)) { echo 'checked="checked"'; } ?> /> <label for="allow-comments"><?php _e('Comments', 'Shopp'); ?> </label> <p><input type="hidden" name="ping_status" value="closed" /><input type="checkbox" name="ping_status" value="open" id="allow-trackpings" tabindex="18" <?php if (Shopp::str_true($Product->ping_status)) { echo 'checked="checked"'; } ?> /> <label for="allow-trackpings"><?php _e('Trackbacks & Pingbacks', 'Shopp'); ?> </label> <p><input type="hidden" name="meta[processing]" value="off" /><input type="checkbox" name="meta[processing]" value="on" id="process-time" tabindex="18" <?php if (isset($Product->meta['processing']) && Shopp::str_true($Product->meta['processing']->value)) { echo 'checked="checked"'; } ?> /> <label for="process-time"><?php _e('Processing Time', 'Shopp'); ?> </label> <div id="processing" class="hide-if-js"> <select name="meta[minprocess]"><?php echo menuoptions(Lookup::timeframes_menu(), isset($Product->meta['minprocess']) ? $Product->meta['minprocess']->value : false, true); ?> </select> — <select name="meta[maxprocess]"><?php echo menuoptions(Lookup::timeframes_menu(), isset($Product->meta['maxprocess']) ? $Product->meta['maxprocess']->value : false, true); ?> </select> </div> </p> <?php }
/** * Helper to apply or exclude taxes from a single amount based on inclusive tax settings and the tax option * * @author Jonathan Davis * @since 1.3 * * @param float $amount The amount to add taxes to, or exclude taxes from * @param ShoppProduct $O The product to get properties from * @param boolean $istaxed Whether the amount can be taxed * @param boolean $taxoption The Theme API tax option given the the tag * @param array $taxrates A list of taxrates that apply to the product and amount * @return float The amount with tax added or tax excluded **/ private static function _taxed($amount, ShoppProduct $O, $istaxed, $taxoption = null, array $taxrates = array()) { if (!$istaxed) { return $amount; } if (empty($taxrates)) { $taxrates = Shopp::taxrates($O); } if (isset($taxoption)) { $taxoption = Shopp::str_true($taxoption); } $inclusivetax = self::_inclusive_taxes($O); if ($inclusivetax) { $adjustment = ShoppTax::adjustment($taxrates); if (1 != $adjustment && false !== $taxoption) { // Only adjust when taxes are not excluded @see #3041 return (double) ($amount / $adjustment); } } // Handle inclusive/exclusive tax presentation options (product editor setting or api option) // If the 'taxes' option is specified and the item either has inclusive taxes that apply, // or the 'taxes' option is forced on (but not both) then handle taxes by either adding or excluding taxes // This is an exclusive or known as XOR, the lesser known brother of Thor that gets left out of the family get togethers if (isset($taxoption) && $inclusivetax ^ $taxoption) { if ($taxoption) { return ShoppTax::calculate($taxrates, (double) $amount); } else { return ShoppTax::exclusive($taxrates, (double) $amount); } } return $amount; }
/** * Checks if the current category has a faceted menu setup * * @api `shopp('collection.has-faceted-menu')` * @since 1.1 * * @param string $result The output * @param array $options The options * @param ShoppCollection $O The working object * @return bool True if there are faceted menus, false otherwise **/ public static function has_faceted_menu($result, $options, $O) { if (!is_a($O, 'ProductCategory')) { return false; } if (empty($O->meta)) { $O->load_meta(); } if (property_exists($O, 'facetedmenus') && Shopp::str_true($O->facetedmenus)) { $O->load_facets(); return true; } return false; }
_e('Comments', 'Shopp'); ?> </label> <p><input type="hidden" name="ping_status" value="closed" /><input type="checkbox" name="ping_status" value="open" id="allow-trackpings" tabindex="18" <?php if (Shopp::str_true($Product->ping_status)) { echo 'checked="checked"'; } ?> /> <label for="allow-trackpings"><?php _e('Trackbacks & Pingbacks', 'Shopp'); ?> </label> <p><input type="hidden" name="meta[processing]" value="off" /><input type="checkbox" name="meta[processing]" value="on" id="process-time" tabindex="18" <?php if (isset($Product->meta['processing']) && Shopp::str_true($Product->meta['processing']->value)) { echo 'checked="checked"'; } ?> /> <label for="process-time"><?php _e('Processing Time', 'Shopp'); ?> </label> <div id="processing" class="hide-if-js"> <select name="meta[minprocess]"><?php echo menuoptions(Lookup::timeframes_menu(), isset($Product->meta['minprocess']) ? $Product->meta['minprocess']->value : false, true); ?> </select> — <select name="meta[maxprocess]"><?php echo menuoptions(Lookup::timeframes_menu(), isset($Product->meta['maxprocess']) ? $Product->meta['maxprocess']->value : false, true);
/** * Generates attribute markup for HTML inputs based on specified options * * @author Jonathan Davis * @since 1.0 * * @param array $options An associative array of options * @param array $allowed (optional) Allowable attribute options for the element * @return string Attribute markup fragment **/ public static function inputattrs($options, array $allowed = array()) { if (!is_array($options)) { return ''; } if (empty($allowed)) { $allowed = array('autocomplete', 'accesskey', 'alt', 'checked', 'class', 'disabled', 'format', 'minlength', 'maxlength', 'placeholder', 'readonly', 'required', 'size', 'src', 'tabindex', 'cols', 'rows', 'title', 'value'); } $allowed = apply_filters('shopp_allowed_inputattrs', $allowed, $options); $string = ""; $classes = ""; if (isset($options['label']) && !isset($options['value'])) { $options['value'] = $options['label']; } foreach ($options as $key => $value) { if (!in_array($key, $allowed)) { continue; } switch ($key) { case "class": $classes .= " {$value}"; break; case "checked": if (Shopp::str_true($value)) { $string .= ' checked="checked"'; } break; case "disabled": if (Shopp::str_true($value)) { $classes .= " disabled"; $string .= ' disabled="disabled"'; } break; case "readonly": if (Shopp::str_true($value)) { $classes .= " readonly"; $string .= ' readonly="readonly"'; } break; case "required": if (Shopp::str_true($value)) { $classes .= " required"; } break; case "minlength": $classes .= " min{$value}"; break; case "format": $classes .= " {$value}"; break; default: $string .= ' ' . $key . '="' . esc_attr($value) . '"'; } } if (!empty($classes)) { $string .= ' class="' . esc_attr(trim($classes)) . '"'; } return $string; }
/** * Build the category menu * * @since 1.3.1 * * @param string $output Passed by reference. Used to append additional content. * @param object $category Category data object. * @param int $depth Depth of category. Used for padding. * @param array $args Uses 'selected' and 'products' keys, if they exist. @see wp_dropdown_categories() */ public function start_el(&$output, $category, $depth = 0, $args = array(), $id = 0) { $pad = str_repeat(' ', $depth * 3); $link = get_term_link($category); $cat_name = apply_filters('shopp_storefront_categorylist_option', $category->name, $category); $output .= "\t<option class=\"level-{$depth}\" value=\"" . $link . "\""; if ($category->term_id == $args['selected']) { $output .= ' selected="selected"'; } $output .= '>'; $output .= $pad . $cat_name; if (Shopp::str_true($args['products']) && isset($category->count)) { $output .= ' (' . $category->count . ')'; } $output .= "</option>\n"; }
/** * packager add item * * @author John Dillick * @since 1.2 * * @param Item $item the item to add to packages **/ public function add_item($CartItem) { $Item = new ShippingPackageItem($CartItem, $CartItem->quantity); if (Shopp::str_true($Item->packaging)) { do_action_ref_array('shopp_packager_add_piece', array($Item, $this)); } else { do_action_ref_array('shopp_packager_add_' . $this->pack, array($Item, $this)); } }
/** * Handles rendering the [product-buynow] shortcode * * @author Jonathan Davis * @since 1.1 * * @param array $attrs The parsed shortcode attributes * @return string The processed content **/ static function buynow(array $atts = array()) { $properties = array('name', 'slug', 'id'); foreach ($properties as $prop) { if (!isset($atts[$prop])) { continue; } $Product = new ShoppProduct($atts[$prop], $prop); } if (!empty($Product->id)) { ShoppProduct($Product); } elseif (!isset(ShoppProduct()->id)) { return ""; } ob_start(); ?> <form action="<?php shopp('cart.url'); ?> " method="post" class="shopp product"> <input type="hidden" name="redirect" value="checkout" /> <?php if (isset($atts['variations'])) { ?> <?php if (shopp('product.has-variations')) { ?> <ul class="variations"> <?php shopp('product.variations', 'mode=multiple&label=true&defaults=' . __('Select an option', 'Shopp') . '&before_menu=<li>&after_menu=</li>'); ?> </ul> <?php } ?> <?php } ?> <?php if (isset($atts['addons'])) { ?> <?php if (shopp('product.has-addons')) { ?> <ul class="addons"> <?php shopp('product.addons', 'mode=menu&label=true&defaults=' . __('Select an add-on', 'Shopp') . '&before_menu=<li>&after_menu=</li>'); ?> </ul> <?php } ?> <?php } ?> <p><?php if (isset($atts['quantity'])) { $quantity = empty($atts['quantity']) ? 'class=selectall&input=menu' : html_entity_decode($atts['quantity']); ?> <?php shopp('product.quantity', $quantity); ?> <?php } ?> <?php $button = 'label=' . (isset($atts['label']) ? $atts['label'] : __('Buy Now', 'Shopp')); $button .= isset($atts['ajax']) && Shopp::str_true($atts['ajax']) ? '&ajax=on' : ''; if (isset($atts['button'])) { $button = html_entity_decode($atts['button']); } ?> <?php shopp('product.addtocart', $button); ?> </p> </form> <?php $markup = ob_get_contents(); ob_end_clean(); ShoppStorefront()->shortcoded[] = get_the_ID(); return apply_filters('shopp_buynow_shortcode', $markup); }
/** * Detects if the cart item is on sale * * An on sale item either has the sale price enabled or a discount is applied * to it. * * @api `shopp('cartitem.onsale')` * @since 1.2 * * @param string $result The output * @param array $options The options * @param ShoppCartItem $O The working object * @return bool True if the cart item is on sale, false otherwise * **/ public static function onsale($result, $options, $O) { return Shopp::str_true($O->sale); }
$stockclass[] = "lowstock {$Product->lowstock}"; } echo '<span class="' . join(' ', $stockclass) . '">' . $Product->stock . '</span>'; } ?> </td> <?php break; case 'featured': ?> <td class="<?php echo esc_attr(join(' ', $classes)); ?> "> <span class="feature<?php echo Shopp::str_true($Product->featured) ? ' featured ' : ' '; ?> shoppui-star"><span class="hidden"><?php Shopp::_e('Featured'); ?> </span></span> </td> <?php break; } // end switch ($column) } // end foreach ($columns) ?> <!-- <th scope="row" class='move-column'><button type="button" name="top" alt="<?php
<div class="checkbox<?php echo $enabled ? ' checked' : ''; ?> " title="<?php echo $title; ?> "><span class="hidden"><?php echo $title; ?> </div> </td> <?php break; case 'menus': $classes[] = 'num'; $enabled = isset($Category->facetedmenus) && Shopp::str_true($Category->facetedmenus); $title = $enabled ? Shopp::__('Faceted search menus enabled') : ''; ?> <td width="5%" class="<?php echo esc_attr(join(' ', $classes)); ?> "> <div class="checkbox<?php echo $enabled ? ' checked' : ''; ?> " title="<?php echo $title; ?> "><span class="hidden"><?php echo $title; ?>
/** * Verify the authenticity of a PDT message sent by PayPal * * @author Jonathan Davis, John Dillick * @since 1.0 * * @return boolean True if valid, false otherwise **/ protected function pdtvalid() { $ids = array($this->id(), 'PPS'); // 'PPS' is a backwards compatible ID for PDT requests if (!in_array($_REQUEST['rmtpay'], $ids)) { return false; } // not PDT message shopp_debug('Processing PDT request: ' . json_encode($_REQUEST)); if (!Shopp::str_true($this->settings['pdtverify']) || !isset($_REQUEST['tx'])) { ShoppOrder()->success(); return true; // if PDT verify is off, skip this process } $_ = array(); $_['cmd'] = '_notify-synch'; $_['at'] = $this->settings['pdttoken']; $_['tx'] = $_REQUEST['tx']; $message = $this->encode($_); // Build the request $response = $this->send($message); // Send it $response = $this->pdtreply($response); // Parse the response into a ShoppPayPalStandardMessage-compatible structure shopp_debug('PayPal PDT _notify-synch reply: ' . json_encode($response)); // Shift the first element off to get the verification status and have a clean data array for ShoppPayPalStandardMessage if ('SUCCESS' != array_shift($response)) { shopp_debug('The transaction was not verified by PayPal.'); // We run the success() method here to reset the shopping session and // redirect the shopper to the "thanks" page with an "order in progress" message // so the cart will be ready for a new order. Otherwise, the customer could resubmit the // prior order and PayPal will give them "that transaction has already been completed" message. ShoppOrder()->success(); return false; } $this->Message = new ShoppPayPalStandardMessage($response); shopp_debug('PayPal PDT response protocol: ' . _object_r($this->Message)); // Everything looks good, return true and let the order PDT order processing handle it from here return true; }
public static function unstock(UnstockOrderEvent $Event) { if (empty($Event->order)) { return shopp_debug('Can not unstock. No event order.'); } $Purchase = $Event->order(); if (!$Purchase->stocked) { return true; } // no inventory in purchase $prices = array(); $allocated = array(); foreach ($Purchase->purchased as $Purchased) { if (is_a($Purchased->addons, 'ObjectMeta') && !empty($Purchased->addons->meta)) { foreach ($Purchased->addons->meta as $index => $Addon) { if (!Shopp::str_true($Addon->value->inventory)) { continue; } $allocated[$Addon->value->id] = new PurchaseStockAllocation(array('purchased' => $Purchased->id, 'addon' => $index, 'sku' => $Addon->value->sku, 'price' => $Addon->value->id, 'quantity' => $Purchased->quantity)); $prices[$Addon->value->id] = array($Purchased->name, isset($prices[$Addon->value->id]) ? $prices[$Addon->value->id][1] + $Purchased->quantity : $Purchased->quantity); } } if (!Shopp::str_true($Purchased->inventory)) { continue; } $allocated[$Purchased->id] = new PurchaseStockAllocation(array('purchased' => $Purchased->id, 'sku' => $Purchased->sku, 'price' => $Purchased->price, 'quantity' => $Purchased->quantity)); $prices[$Purchased->price] = array($Purchased->name, isset($prices[$Purchased->price]) ? $prices[$Purchased->price][1] + $Purchased->quantity : $Purchased->quantity); } if (empty($allocated)) { return; } $pricetable = ShoppDatabaseObject::tablename(ShoppPrice::$table); $lowlevel = shopp_setting('lowstock_level'); foreach ($prices as $price => $data) { list($productname, $qty) = $data; sDB::query("UPDATE {$pricetable} SET stock=(stock-" . (int) $qty . ") WHERE id='{$price}' LIMIT 1"); $inventory = sDB::query("SELECT label, stock, stocked FROM {$pricetable} WHERE id='{$price}' LIMIT 1", 'auto'); $product = "{$productname}, {$inventory->label}"; if (0 == $inventory->stock) { shopp_add_error(Shopp::__('%s is now out-of-stock!', $product), SHOPP_STOCK_ERR); } elseif ($inventory->stock / $inventory->stocked * 100 <= $lowlevel) { shopp_add_error(Shopp::__('%s has low stock levels and should be re-ordered soon.', $product), SHOPP_STOCK_ERR); } } $Event->unstocked($allocated); // If out of stock products should be hidden from catalog, // go ahead and invalidate the cache after unstock if (!Shopp::str_true(shopp_setting('outofstock_catalog'))) { Shopp::invalidate_cache(); } }
public function smart(array $options = array()) { $this->name = __('Customers also bought…', 'Shopp'); $this->controls = false; $where = array("true=false"); $scope = array(); $Product = ShoppProduct(); $Order = ShoppOrder(); $Cart = $Order->Cart; // Use the current product is available if (!empty($Product->id)) { $this->product = $Product; } // Or load a product specified if (!empty($options['product'])) { if ('recent-cartitem' == $options['product']) { // Use most recently added item in the cart $this->product = new ShoppProduct($Cart->added()->product); } elseif (preg_match('/^[\\d+]$/', $options['product'])) { // Load by specified id $this->product = new ShoppProduct($options['product']); } else { $this->product = new ShoppProduct($options['product'], 'slug'); // Load by specified slug } } if (empty($this->product->id)) { $loading = compact('where'); $this->loading = array_merge($options, $loading); return; } $this->name = Shopp::__('Customers that bought "%s" also bought…', $this->product->name); $purchased = ShoppDatabaseObject::tablename(Purchased::$table); $query = "SELECT p2,((psum - (sum1 * sum2 / n)) / sqrt((sum1sq - pow(sum1, 2.0) / n) * (sum2sq - pow(sum2, 2.0) / n))) AS r, n\n\t\t\t\t\t\t\t\tFROM (\n\t\t\t\t\t\t\t\t\tSELECT n1.product AS p1,n2.product AS p2,SUM(n1.quantity) AS sum1,SUM(n2.quantity) AS sum2,\n\t\t\t\t\t\t\t\t\t\tSUM(n1.quantity * n1.quantity) AS sum1sq,SUM(n2.quantity * n2.quantity) AS sum2sq,\n\t\t\t\t\t\t\t\t\t\tSUM(n1.quantity * n2.quantity) AS psum,COUNT(*) AS n\n\t\t\t\t\t\t\t\t\tFROM {$purchased} AS n1\n\t\t\t\t\t\t\t\t\tLEFT JOIN {$purchased} AS n2 ON n1.purchase = n2.purchase\n\t\t\t\t\t\t\t\t\tWHERE n1.product != n2.product\n\t\t\t\t\t\t\t\t\tGROUP BY n1.product,n2.product\n\t\t\t\t\t\t\t\t) AS step1\n\t\t\t\t\t\t\t\tORDER BY r DESC, n DESC"; $cachehash = 'alsobought_' . md5($query); $cached = Shopp::cache_get($cachehash, 'shopp_collection_alsobought'); if ($cached) { $matches = $cached; } else { $matches = sDB::query($query, 'array', 'col', 'p2'); Shopp::cache_set($cachehash, $matches, 'shopp_collection_alsobought', 14400); //Expires in 4 hours } if (empty($matches)) { $loading = compact('where'); $this->loading = array_merge($options, $loading); return; } $where = array("p.id IN (" . join(',', $matches) . ")"); $loading = compact('columns', 'joins', 'where', 'groupby', 'order'); $this->loading = array_merge($options, $loading); if (isset($options['controls']) && Shopp::str_true($options['controls'])) { unset($this->controls); } }
?> </strong></label></li> <li<?php if ($even) { echo ' class="odd"'; } $even = !$even; ?> ><input type="hidden" name="settings[<?php echo $report; ?> _report_export][headers]" value="off" /><input type="checkbox" name="settings[<?php echo $report; ?> _report_export][headers]" id="export_headers" value="on" <?php echo Shopp::str_true($settings['headers']) ? ' checked="checked"' : ''; ?> /><label for="export_headers"><strong><?php _e('Include column headings', 'Shopp'); ?> </strong></label></li> <?php $even = true; foreach ($columns as $name => $label) { ?> <li<?php if ($even) { echo ' class="odd"'; } $even = !$even; ?>
/** * Saves generated stats to the product record * * @author Jonathan Davis * @since 1.2 * * @param array $stats The stat properties to update * @return void **/ public function sumup() { if (empty($this->id)) { return; } $Summary = new ProductSummary(); $properties = array_keys($Summary->_datatypes); $minmax = array('min', 'max'); $ignore = array('product', 'modified'); $checksum = false; foreach ($properties as $property) { if ($property[0] == '_') { continue; } if (in_array($property, $ignore)) { continue; } switch ($property) { case 'minprice': $this->minprice = (double) $this->min[Shopp::str_true($this->sale) ? 'saleprice' : 'price']; break; case 'maxprice': $this->maxprice = (double) $this->max[Shopp::str_true($this->sale) ? 'saleprice' : 'price']; break; case 'ranges': $ranges = array(); foreach ($minmax as $m) { $attr = $this->{$m}; foreach (ProductSummary::$_ranges as $name) { if (isset($attr[$name])) { $ranges[] = (double) $attr[$name]; } } } break; case 'taxed': $taxable = array('price', 'saleprice'); $taxed = array(); foreach ($minmax as $m) { $attr = $this->{$m}; foreach ($taxable as $name) { if (isset($attr[$name . '_tax']) && $attr[$name . '_tax']) { $taxed[] = "{$m} {$name}"; } } } break; default: } if (isset($this->{$property})) { if ('float' == $Summary->_datatypes[$property]) { $checksum .= (double) $this->{$property}; } else { $checksum .= $this->{$property}; } } } if (md5($checksum) == $this->checksum) { return; } $Summary->copydata($this); if (isset($this->summed)) { $Summary->modified = $this->summed; } $Summary->product = $this->id; $Summary->ranges = join(',', $ranges); $Summary->taxed = join(',', $taxed); $Summary->save(); }
/** * Interface processor for the order manager * * @author Jonathan Davis * @return void **/ public function manager() { global $Shopp, $Notes; global $is_IIS; if (!current_user_can('shopp_orders')) { wp_die(__('You do not have sufficient permissions to access this page.', 'Shopp')); } $Purchase = ShoppPurchase(); $Purchase->Customer = new ShoppCustomer($Purchase->customer); $Gateway = $Purchase->gateway(); if (!empty($_POST["send-note"])) { $user = wp_get_current_user(); shopp_add_order_event($Purchase->id, 'note', array('note' => stripslashes($_POST['note']), 'user' => $user->ID)); $Purchase->load_events(); } // Handle Order note processing if (!empty($_POST['note'])) { $this->addnote($Purchase->id, stripslashes($_POST['note']), !empty($_POST['send-note'])); } if (!empty($_POST['delete-note'])) { $noteid = key($_POST['delete-note']); $Note = new ShoppMetaObject(array('id' => $noteid, 'type' => 'order_note')); $Note->delete(); } if (!empty($_POST['edit-note'])) { $noteid = key($_POST['note-editor']); $Note = new ShoppMetaObject(array('id' => $noteid, 'type' => 'order_note')); $Note->value->message = stripslashes($_POST['note-editor'][$noteid]); $Note->save(); } $Notes = new ObjectMeta($Purchase->id, 'purchase', 'order_note'); if (isset($_POST['submit-shipments']) && isset($_POST['shipment']) && !empty($_POST['shipment'])) { $shipments = $_POST['shipment']; foreach ((array) $shipments as $shipment) { shopp_add_order_event($Purchase->id, 'shipped', array('tracking' => $shipment['tracking'], 'carrier' => $shipment['carrier'])); } $updated = __('Shipping notice sent.', 'Shopp'); // Save shipping carrier default preference for the user $userid = get_current_user_id(); $setting = 'shopp_shipping_carrier'; if (!get_user_meta($userid, $setting, true)) { add_user_meta($userid, $setting, $shipment['carrier']); } else { update_user_meta($userid, $setting, $shipment['carrier']); } unset($_POST['ship-notice']); $Purchase->load_events(); } if (isset($_POST['order-action']) && 'refund' == $_POST['order-action']) { if (!current_user_can('shopp_refund')) { wp_die(__('You do not have sufficient permissions to carry out this action.', 'Shopp')); } $user = wp_get_current_user(); $reason = (int) $_POST['reason']; $amount = Shopp::floatval($_POST['amount']); $Purchase->load_events(); if (!empty($_POST['message'])) { $message = $_POST['message']; $Purchase->message['note'] = $message; } if ($amount <= $Purchase->captured - $Purchase->refunded) { if (!Shopp::str_true($_POST['send'])) { // Force the order status shopp_add_order_event($Purchase->id, 'notice', array('user' => $user->ID, 'kind' => 'refunded', 'notice' => __('Marked Refunded', 'Shopp'))); shopp_add_order_event($Purchase->id, 'refunded', array('txnid' => $Purchase->txnid, 'gateway' => $Gateway->module, 'amount' => $amount)); shopp_add_order_event($Purchase->id, 'voided', array('txnorigin' => $Purchase->txnid, 'txnid' => time(), 'gateway' => $Gateway->module)); } else { shopp_add_order_event($Purchase->id, 'refund', array('txnid' => $Purchase->txnid, 'gateway' => $Gateway->module, 'amount' => $amount, 'reason' => $reason, 'user' => $user->ID)); } if (!empty($_POST['message'])) { $this->addnote($Purchase->id, $_POST['message']); } $Purchase->load_events(); } else { $this->notice(Shopp::__('Refund failed. Cannot refund more than the current balance.'), 'error'); } } if (isset($_POST['order-action']) && 'cancel' == $_POST['order-action']) { if (!current_user_can('shopp_void')) { wp_die(__('You do not have sufficient permissions to carry out this action.', 'Shopp')); } // unset($_POST['refund-order']); $user = wp_get_current_user(); $reason = (int) $_POST['reason']; $message = ''; if (!empty($_POST['message'])) { $message = $_POST['message']; $Purchase->message['note'] = $message; } else { $message = 0; } if (!Shopp::str_true($_POST['send'])) { // Force the order status shopp_add_order_event($Purchase->id, 'notice', array('user' => $user->ID, 'kind' => 'cancelled', 'notice' => __('Marked Cancelled', 'Shopp'))); shopp_add_order_event($Purchase->id, 'voided', array('txnorigin' => $Purchase->txnid, 'txnid' => time(), 'gateway' => $Gateway->module)); } else { shopp_add_order_event($Purchase->id, 'void', array('txnid' => $Purchase->txnid, 'gateway' => $Gateway->module, 'reason' => $reason, 'user' => $user->ID, 'note' => $message)); } if (!empty($_POST['message'])) { $this->addnote($Purchase->id, $_POST['message']); } $Purchase->load_events(); } if (isset($_POST['billing']) && is_array($_POST['billing'])) { $Purchase->updates($_POST['billing']); $Purchase->save(); } if (isset($_POST['shipping']) && is_array($_POST['shipping'])) { $shipping = array(); foreach ($_POST['shipping'] as $name => $value) { $shipping["ship{$name}"] = $value; } $Purchase->updates($shipping); $Purchase->shipname = $shipping['shipfirstname'] . ' ' . $shipping['shiplastname']; $Purchase->save(); } if (isset($_POST['order-action']) && 'update-customer' == $_POST['order-action'] && !empty($_POST['customer'])) { $Purchase->updates($_POST['customer']); $Purchase->save(); } if (isset($_POST['cancel-edit-customer'])) { unset($_POST['order-action'], $_POST['edit-customer'], $_POST['select-customer']); } if (isset($_POST['order-action']) && 'new-customer' == $_POST['order-action'] && !empty($_POST['customer']) && !isset($_POST['cancel-edit-customer'])) { $Customer = new ShoppCustomer(); $Customer->updates($_POST['customer']); $Customer->password = wp_generate_password(12, true); if ('wordpress' == shopp_setting('account_system')) { $Customer->create_wpuser(); } else { unset($_POST['loginname']); } $Customer->save(); if ((int) $Customer->id > 0) { $Purchase->copydata($Customer); $Purchase->save(); } else { $this->notice(__('An unknown error occured. The customer could not be created.', 'Shopp'), 'error'); } } if (isset($_GET['order-action']) && 'change-customer' == $_GET['order-action'] && !empty($_GET['customerid'])) { $Customer = new ShoppCustomer((int) $_GET['customerid']); if ((int) $Customer->id > 0) { $Purchase->copydata($Customer); $Purchase->customer = $Customer->id; $Purchase->save(); } else { $this->notice(__('The selected customer was not found.', 'Shopp'), 'error'); } } if (isset($_POST['save-item']) && !empty($_POST['lineid'])) { // Create a cart representation of the order to recalculate order totals $Cart = new ShoppCart(); foreach ($Purchase->purchased as $OrderItem) { $CartItem = new Item($OrderItem); $Cart->contents[$OrderItem->id] = $CartItem; } $purchasedid = (int) $_POST['lineid']; $Purchased = $Purchase->purchased[$purchasedid]; if ($Purchased->id) { $override_total = Shopp::floatval($_POST['total']) != $Purchased->total; // Override total $Item = $Cart->contents[$purchasedid]; $Item->quantity($_POST['quantity']); $Item->unitprice = Shopp::floatval($_POST['unitprice']); $Item->retotal(); $Purchased->quantity = $Item->quantity; $Purchased->unitprice = $Item->unitprice; $Purchased->unittax = $Item->unittax; $Purchased->total = $Item->total; if ($override_total) { $Purchased->total = Shopp::floatval($_POST['total']); } $Purchased->save(); } $Cart->retotal = true; $Cart->totals(); $Purchase->copydata($Cart->Totals); $Purchase->save(); } if (isset($_POST['charge']) && $Gateway && $Gateway->captures) { if (!current_user_can('shopp_capture')) { wp_die(__('You do not have sufficient permissions to carry out this action.', 'Shopp')); } $user = wp_get_current_user(); shopp_add_order_event($Purchase->id, 'capture', array('txnid' => $Purchase->txnid, 'gateway' => $Purchase->gateway, 'amount' => $Purchase->capturable(), 'user' => $user->ID)); $Purchase->load_events(); } $base = shopp_setting('base_operations'); $targets = shopp_setting('target_markets'); $countries = array('' => ' '); $countrydata = Lookup::countries(); foreach ($countrydata as $iso => $c) { if ($base['country'] == $iso) { $base_region = $c['region']; } $countries[$iso] = $c['name']; } $Purchase->_countries = $countries; $regions = Lookup::country_zones(); $Purchase->_billing_states = array_merge(array('' => ' '), (array) $regions[$Purchase->country]); $Purchase->_shipping_states = array_merge(array('' => ' '), (array) $regions[$Purchase->shipcountry]); // Setup shipping carriers menu and JS data $carriers_menu = $carriers_json = array(); $shipping_carriers = (array) shopp_setting('shipping_carriers'); // The store-preferred shipping carriers $shipcarriers = Lookup::shipcarriers(); // The full list of available shipping carriers $notrack = Shopp::__('No Tracking'); // No tracking label $default = get_user_meta(get_current_user_id(), 'shopp_shipping_carrier', true); if (isset($shipcarriers[$default])) { $carriers_menu[$default] = $shipcarriers[$default]->name; $carriers_json[$default] = array($shipcarriers[$default]->name, $shipcarriers[$default]->trackpattern); } else { $carriers_menu['NOTRACKING'] = $notrack; $carriers_json['NOTRACKING'] = array($notrack, false); } $serviceareas = array('*', $base['country']); foreach ($shipcarriers as $code => $carrier) { if ($code == $default) { continue; } if (!empty($shipping_carriers) && !in_array($code, $shipping_carriers)) { continue; } if (!in_array($carrier->areas, $serviceareas)) { continue; } $carriers_menu[$code] = $carrier->name; $carriers_json[$code] = array($carrier->name, $carrier->trackpattern); } if (isset($shipcarriers[$default])) { $carriers_menu['NOTRACKING'] = $notrack; $carriers_json['NOTRACKING'] = array($notrack, false); } if (empty($statusLabels)) { $statusLabels = array(''); } include $this->ui('order.php'); }
/** * Renders a checkbox input * * @author Jonathan Davis * @since 1.1 * * @param int $column The table column to add the element to * @param array $attributes Element attributes; use 'checked' to set whether the element is toggled on or not * * @return void **/ public function checkbox($column = 0, array $attributes = array()) { $defaults = array('label' => '', 'type' => 'checkbox', 'normal' => 'off', 'value' => 'on', 'checked' => false, 'class' => ''); $attributes = array_merge($defaults, $attributes); $attributes['checked'] = Shopp::str_true($attributes['checked']) ? true : false; extract($attributes); $id = "{$this->id}-" . sanitize_title_with_dashes($name); if (!empty($class)) { $class = ' class="' . esc_attr($class) . '"'; } $this->ui('<div><label for="' . $id . '">', $column); $this->ui('<input type="hidden" name="settings[' . $this->module . '][' . $name . ']" value="' . $normal . '" id="' . $id . '-default" />', $column); $this->ui('<input type="' . $type . '" name="settings[' . $this->module . '][' . $name . ']" value="' . $value . '"' . $class . ' id="' . $id . '"' . ($checked ? ' checked="checked"' : '') . ' />', $column); if (!empty($label)) { $this->ui(' ' . $label, $column); } $this->ui('</label></div>', $column); }
/** * Loads the theme templates `shopp/functions.php` if present * * If theme content templates are enabled, checks for and includes a functions.php file (if present). * This allows developers to add Shopp-specific presentation logic with the added convenience of knowing * that shopp_init has run. * * @author Barry Hughes * @since 1.3 * * @return void **/ public static function functions() { if (!Shopp::str_true(shopp_setting('theme_templates'))) { return; } Shopp::locate_template(array('functions.php'), true); }
/** * has_trial() * * Tests if item is recurring and has a trial period * * @author John Dillick * @since 1.2 * * @return bool true if recurring and has trial, false otherwise **/ public function has_trial() { $trial = false; if ($this->is_recurring() && Shopp::str_true($this->option->recurring['trial'])) { $trial = true; } return apply_filters('shopp_cartitem_hastrial', $trial, $this); }
/** * Provides a checkbox toggle to mark the shipping address as a residential address * * @api `shopp('customer.residential-shipping-address')` * @since 1.2 * * @param string $result The output * @param array $options The options * - **label**: `Residential shipping address` The label for the checkbox input * - **checked**: `on` (on, off) Specifies that an `<input>` element should be pre-selected when the page loads * - **class**: The class attribute specifies one or more class-names for an element * - **title**: Specifies extra information about an element * @param ShoppCustomer $O The working object * @return string Markup for the residential address checkbox toggle **/ public static function residential_shipping_address($result, $options, $O) { $label = Shopp::__('Residential shipping address'); if (isset($options['label'])) { $label = $options['label']; } if (isset($options['checked']) && Shopp::str_true($options['checked'])) { $checked = ' checked="checked"'; } $output = '<label for="residential-shipping"><input type="hidden" name="shipping[residential]" value="no" /><input type="checkbox" name="shipping[residential]" value="yes" id="residential-shipping" ' . $checked . ' /> ' . $label . '</label>'; return $output; }
/** * Defines the shopp() 'tag' handler for complete template customization * * Appropriately routes tag calls to the tag handler for the requested object. * * @api * @since 1.0 * * @param mixed $context The object label or Object to get the tag property from * @param string $property The property of the object to get/output * @param string|array $options Custom options for the property result in query form * (option1=value&option2=value&...) or alternatively as an associative array * @return void|bool|string Boolean values or string result or nothing if the string is output */ function shopp($context, $property = false, $options = false) { $Object = false; $result = false; $parameters = array('first', 'second', 'third'); // Parameter prototype $num = func_num_args(); // Determine number of arguments provided $fargs = func_get_args(); $context = $tag = false; // object API to use and tag name $options = array(); // options to pass to API call if ($num < 1) { // Not enough arguments to do anything, bail shopp_add_error(Shopp::__('shopp() theme tag syntax error: no object property specified.'), SHOPP_PHP_ERR); return; } // Grab the arguments (up to 3) $args = array_combine(array_slice($parameters, 0, $num), $fargs); extract($args); if (is_object($first)) { // Handle Object instances as first argument $Object = $first; $context = isset($Object->api) ? $Object->api : strtolower(get_class($Object)); $tag = strtolower($second); } elseif (false !== strpos($first, '.')) { // Handle object.tag first argument list($context, $tag) = explode('.', strtolower($first)); if ($num > 1) { $options = shopp_parse_options($second); } } elseif ('' == $context . $tag) { // Normal tag handler list($context, $tag) = array_map('strtolower', array($first, $second)); } if ($num > 2) { $options = shopp_parse_options($third); } // strip hypens from tag names $tag = str_replace('-', '', $tag); // strip get prefix from requested tag $get = false; if ('get' == substr($tag, 0, 3)) { $tag = substr($tag, 3); $get = true; } $Object = apply_filters('shopp_themeapi_object', $Object, $context, $tag); $Object = apply_filters('shopp_tag_domain', $Object, $context); // @deprecated if ('hascontext' == $tag) { return $Object; } if (!$Object) { shopp_add_error(Shopp::__("The shopp('%s') tag cannot be used in this context because the object responsible for handling it doesn't exist.", $context), SHOPP_PHP_ERR); } $themeapi = apply_filters('shopp_themeapi_context_name', $context); $result = apply_filters('shopp_themeapi_' . strtolower($themeapi . '_' . $tag), $result, $options, $Object); // tag specific tag filter $result = apply_filters('shopp_tag_' . strtolower($context . '_' . $tag), $result, $options, $Object); // @deprecated use shopp_themeapi_{api}_{tag} $result = apply_filters('shopp_themeapi_' . strtolower($themeapi), $result, $options, $tag, $Object); // global object tag filter $result = apply_filters('shopp_themeapi', $result, $options, $tag, $Object); $result = apply_filters('shopp_ml_t', $result, $options, $tag, $Object); // @deprecated use shopp_themeapi // Force boolean result if (isset($options['is'])) { if (Shopp::str_true($options['is'])) { if ($result) { return true; } } else { if (false == $result) { return true; } } return false; } // Always return a boolean if the result is boolean if (is_bool($result)) { return $result; } if ($get || isset($options['return']) && Shopp::str_true($options['return']) || isset($options['echo']) && !Shopp::str_true($options['echo'])) { return $result; } // Output the result if (is_scalar($result)) { echo $result; } else { return $result; } }