Esempio n. 1
0
 public static function login($result)
 {
     $Customer = ShoppOrder()->Customer;
     if ($Customer->loggedin()) {
         return $result;
     }
     $accounts = shopp_setting('account_system');
     $pleaselogin = '******' . Shopp::__('If you have an account with us, please login now.');
     // This specific !isset condition checks if the loginname is not provided
     // If no loginname is provided, but an account system is used, we need to
     // generate a new login name for the customer
     if ('wordpress' == $accounts && !isset($_POST['loginname'])) {
         ShoppLoginGenerator::object();
         $_POST['loginname'] = ShoppLoginGenerator::name();
         if (apply_filters('shopp_login_required', empty($_POST['loginname']))) {
             return shopp_add_error(Shopp::__('A login could not be created with the information you provided. Enter a different name or email address.') . $pleaselogin);
         }
         shopp_debug('Login set to ' . $_POST['loginname'] . ' for WordPress account creation.');
     }
     // Validate unique email address for new account
     if (in_array($accounts, array('wordpress', 'shopp')) && !$Customer->session(ShoppCustomer::GUEST)) {
         $ShoppCustomer = new ShoppCustomer($_POST['email'], 'email');
         if (apply_filters('shopp_email_exists', 'wordpress' == $accounts ? email_exists($_POST['email']) : $ShoppCustomer->exists())) {
             return shopp_add_error(Shopp::__('The email address you entered is already in use. Enter a different email address to create a new account.') . $pleaselogin);
         }
     }
     // Validate WP login
     if (isset($_POST['loginname'])) {
         if (apply_filters('shopp_login_required', empty($_POST['loginname']))) {
             return shopp_add_error(Shopp::__('You must enter a login name for your account.'));
         }
         if (apply_filters('shopp_login_valid', !validate_username($_POST['loginname']))) {
             $sanitized = sanitize_user($_POST['loginname'], true);
             $illegal = array_diff(str_split($_POST['loginname']), str_split($sanitized));
             return shopp_add_error(Shopp::__('The login name provided includes invalid characters: %s', esc_html(join(' ', $illegal))));
         }
         if (apply_filters('shopp_login_exists', username_exists($_POST['loginname']))) {
             return shopp_add_error(Shopp::__('"%s" is already in use. Enter a different login name to create a new account.', esc_html($_POST['loginname'])) . $pleaselogin);
         }
     }
     return $result;
 }
Esempio n. 2
0
/**
 * Add a sub-menu to a Shopp menu
 *
 * @api
 * @since 1.3
 *
 * @param string $label	The translated label to use for the menu
 * @param string $page The Shopp-internal menu page name (plugin prefix will be automatically added)
 * @param string $menu The Shopp-internal menu page name to append the submenu to
 * @param mixed $handler The callback handler to use to handle the page
 * @param string $access The access capability required to see the menu
 * @return integer The position the menu was added
 **/
function shopp_admin_add_submenu($label, $page, $menu = null, $handler = false, $access = null)
{
    $Admin = ShoppAdmin();
    if (is_null($menu)) {
        $Admin->mainmenu();
    }
    if (is_null($access)) {
        $access = 'none';
    }
    // Restrict access by default
    if (false === $handler) {
        $handler = array(Shopp::object()->Flow, 'admin');
    }
    if (!is_callable($handler)) {
        shopp_debug(__FUNCTION__ . " failed: The specified callback handler is not valid.");
        return false;
    }
    $menupage = add_submenu_page($menu, $label, $label, $access, $page, $handler);
    $Admin->menu($page, $menupage);
    $Admin->addtab($page, $menu);
    do_action("shopp_add_menu_{$page}");
    return $menupage;
}
Esempio n. 3
0
/**
 * Returns the number of addons added to the cartitem.
 *
 * @api
 * 
 * @param $itemkey
 * @return bool|int
 */
function shopp_cart_item_addons_count($itemkey)
{
    if (false === $itemkey) {
        shopp_debug(__FUNCTION__ . " failed: itemkey parameter required.");
        return false;
    }
    if (!($item = shopp_cart_item($itemkey))) {
        shopp_debug(__FUNCTION__ . " failed: no such item {$itemkey}");
        return false;
    }
    if (false === ($addons = shopp_cart_item_addons($itemkey))) {
        return false;
        // Debug message will already have been generated in shopp_cart_item_addons()
    }
    return (int) count($addons);
}
Esempio n. 4
0
 /**
  * Loads session data from another session into this one
  *
  * Used to access third-party session data. This only happens when
  * a payment system uses server-to-server communication that needs
  * session-specific information about the customer or transaction.
  *
  * @since 1.3.6
  *
  * @param string $session The session ID to load
  * @return bool True if successful, false otherwise
  */
 public function preload($session)
 {
     if (!$this->exists($session)) {
         trigger_error('Could not reload the specified session.');
         return false;
     }
     $this->destroy();
     $this->open();
     $this->load($session);
     $this->cook();
     shopp_debug('Session started ' . str_repeat('-', 64));
     return true;
 }
Esempio n. 5
0
/**
 * shopp_rmv_product_download
 *
 * Remove a product download asset
 *
 * @api
 * @since 1.2
 *
 * @param int $download the product asset id
 * @return bool true on success, false on failure
 **/
function shopp_rmv_product_download($download)
{
    if (empty($download)) {
        shopp_debug(__FUNCTION__ . ' failed: download parameter required.');
        return false;
    }
    $File = new ProductDownload($download);
    if (empty($File->id)) {
        shopp_debug(__FUNCTION__ . " failed: No such product download with id {$download}.");
        return false;
    }
    return $File->delete();
}
Esempio n. 6
0
/**
 * Determines if the requested page is a Shopp page or if it matches a given Shopp page
 *
 * Also checks to see if the current loaded query is a Shopp product or product taxonomy.
 *
 * @api
 * @since 1.0
 *
 * @param string $page (optional) System page name ID for the correct ShoppStorefront page {@see ShoppPages class}
 * @param WP_Query $wp_query (optional) will use the global wp_query by default if false, or the provided WP_Query object
 * @return boolean
 **/
function is_shopp_page($page = false, $wp_query = false)
{
    if (false === $wp_query) {
        global $wp_the_query;
        $wp_query = $wp_the_query;
    }
    if (empty($wp_query->query_vars)) {
        shopp_debug('Conditional is_shopp_page functions do not work before the WordPress query is run. Before then, they always return false.');
    }
    $is_shopp_page = false;
    $Page = ShoppPages()->requested();
    if (false === $page) {
        // Check if the current request is a shopp page request
        // Product and collection pages are considered a Shopp page request
        if (is_shopp_product($wp_query) || $wp_query->get('post_type') == ShoppProduct::$posttype) {
            $is_shopp_page = true;
        }
        if (is_shopp_collection($wp_query)) {
            $is_shopp_page = true;
        }
        if (false !== $Page) {
            $is_shopp_page = true;
        }
    } elseif (false !== $Page) {
        // Check if the given shopp page name is the current request
        if ($Page->name() == $page) {
            $is_shopp_page = true;
        }
    }
    return $is_shopp_page;
}
Esempio n. 7
0
 public function content($content)
 {
     global $wp_query;
     // Test that this is the main query and it is a catalog page
     if (!$wp_query->is_main_query() || !is_catalog_frontpage()) {
         return $content;
     }
     shopp_debug('Displaying catalog page request: ' . $_SERVER['REQUEST_URI']);
     ob_start();
     locate_shopp_template(array('catalog.php'), true);
     $content = ob_get_clean();
     return apply_filters('shopp_catalog_template', $content);
 }
Esempio n. 8
0
 public function load(array $options = array())
 {
     $thisclass = get_class($this);
     $slug = isset($this->slug) ? $this->slug : sanitize_key($thisclass);
     $Storefront = ShoppStorefront();
     $Shopping = ShoppShopping();
     $Processing = new ShoppProduct();
     $summary_table = ShoppDatabaseObject::tablename(ProductSummary::$table);
     $defaults = array('columns' => false, 'useindex' => false, 'joins' => array(), 'where' => array(), 'groupby' => false, 'orderby' => false, 'having' => array(), 'limit' => false, 'order' => false, 'page' => false, 'paged' => false, 'nostock' => null, 'pagination' => true, 'published' => true, 'ids' => false, 'adjacent' => false, 'product' => false, 'load' => array('coverimages'), 'inventory' => false, 'taxquery' => false, 'debug' => false);
     $loading = array_merge($defaults, $options);
     $loading = apply_filters("shopp_collection_load_options", $loading);
     $loading = apply_filters("shopp_{$slug}_collection_load_options", $loading);
     extract($loading);
     // Setup pagination
     $this->paged = false;
     $this->pagination = false === $paged ? shopp_setting('catalog_pagination') : $paged;
     $page = false === $page ? get_query_var('paged') : $page;
     $this->page = (int) $page > 0 || preg_match('/(0\\-9|[A-Z])/', $page) ? $page : 1;
     // Hard product limit per category to keep resources "reasonable"
     $hardlimit = apply_filters('shopp_category_products_hardlimit', 1000);
     // Enforce the where parameter as an array
     if (!is_array($where)) {
         return shopp_debug('The "where" parameter for ' . __METHOD__ . ' must be formatted as an array.');
     }
     // Inventory filtering
     if (shopp_setting_enabled('inventory') && (is_null($nostock) && !shopp_setting_enabled('outofstock_catalog') || !is_null($nostock) && !Shopp::str_true($nostock))) {
         $where[] = "( s.inventory='off' OR (s.inventory='on' AND s.stock > 0) )";
     }
     if (Shopp::str_true($published)) {
         $where[] = "p.post_status='publish'";
     }
     // Multiple taxonomy queries
     if (is_array($taxquery)) {
         $tqdefaults = array('relation' => 'AND', 'include_children' => true);
         $taxquery = array_merge($tqdefaults, $taxquery);
         $TQ = new WP_Tax_Query($taxquery);
         $sql = $TQ->get_sql($Processing->_table, 'ID');
         unset($TQ);
         $joins['taxquery'] = self::taxquery($sql['join']);
         $where[] = self::taxquery($sql['where']);
     }
     // Sort Order
     if (!$orderby) {
         $titlesort = "p.post_title ASC";
         $defaultsort = empty($order) ? $titlesort : $order;
         // Define filterable built-in sort methods (you're welcome)
         $sortmethods = apply_filters('shopp_collection_sort_methods', array('bestselling' => "s.sold DESC,{$titlesort}", 'highprice' => "maxprice DESC,{$titlesort}", 'lowprice' => "minprice ASC,{$titlesort}", 'newest' => "p.post_date DESC,{$titlesort}", 'oldest' => "p.post_date ASC,{$titlesort}", 'random' => "RAND(" . crc32($Shopping->session) . ")", 'chaos' => "RAND(" . time() . ")", 'reverse' => "p.post_title DESC", 'title' => $titlesort, 'custom' => is_subclass_of($this, 'ProductTaxonomy') ? "tr.term_order ASC,{$titlesort}" : $defaultsort, 'recommended' => is_subclass_of($this, 'ProductTaxonomy') ? "tr.term_order ASC,{$titlesort}" : $defaultsort, 'default' => $defaultsort));
         // Handle valid user browsing sort change requests
         if (isset($_REQUEST['sort']) && !empty($_REQUEST['sort']) && array_key_exists(strtolower($_REQUEST['sort']), $sortmethods)) {
             $Storefront->browsing['sortorder'] = strtolower($_REQUEST['sort']);
         }
         // Collect sort setting sources (Shopp admin setting, User browsing setting, programmer specified setting)
         $sortsettings = array(shopp_setting('default_product_order'), isset($Storefront->browsing['sortorder']) ? $Storefront->browsing['sortorder'] : false, !empty($order) ? $order : false);
         // Go through setting sources to determine most applicable setting
         $sorting = 'title';
         foreach ($sortsettings as $setting) {
             if (!empty($setting) && isset($sortmethods[strtolower($setting)])) {
                 $sorting = strtolower($setting);
             }
         }
         $orderby = $sortmethods[$sorting];
     }
     if (empty($orderby)) {
         $orderby = 'p.post_title ASC';
     }
     // Pagination
     if (empty($limit)) {
         if ($this->pagination > 0 && is_numeric($this->page) && Shopp::str_true($pagination)) {
             if (!$this->pagination || $this->pagination < 0) {
                 $this->pagination = $hardlimit;
             }
             $start = $this->pagination * ($this->page - 1);
             $limit = "{$start},{$this->pagination}";
         } else {
             $limit = $hardlimit;
         }
         $limited = false;
         // Flag that the result set does not have forced limits
     } else {
         $limited = true;
     }
     // The result set has forced limits
     // Core query components
     // Load core product data and product summary columns
     $cols = array('p.ID', 'p.post_title', 'p.post_name', 'p.post_excerpt', 'p.post_status', 'p.post_date', 'p.post_modified', 's.modified AS summed', 's.sold', 's.grossed', 's.maxprice', 's.minprice', 's.ranges', 's.taxed', 's.stock', 's.lowstock', 's.inventory', 's.featured', 's.variants', 's.addons', 's.sale');
     if ($ids) {
         $cols = array('p.ID');
     }
     $columns = "SQL_CALC_FOUND_ROWS " . join(',', $cols) . ($columns !== false ? ',' . $columns : '');
     $table = "{$Processing->_table} AS p";
     $where[] = "p.post_type='" . ShoppProduct::posttype() . "'";
     $joins[$summary_table] = "LEFT OUTER JOIN {$summary_table} AS s ON s.product=p.ID";
     $options = compact('columns', 'useindex', 'table', 'joins', 'where', 'groupby', 'having', 'limit', 'orderby');
     // Alphabetic pagination
     if ('alpha' === $pagination || preg_match('/(0\\-9|[A-Z])/', $page)) {
         // Setup Roman alphabet navigation
         $alphanav = array_merge(array('0-9'), range('A', 'Z'));
         $this->alpha = array_combine($alphanav, array_fill(0, count($alphanav), 0));
         // Setup alphabetized index query
         $a = $options;
         $a['columns'] = "count(DISTINCT p.ID) AS total,IF(LEFT(p.post_title,1) REGEXP '[0-9]',LEFT(p.post_title,1),LEFT(SOUNDEX(p.post_title),1)) AS letter";
         $a['groupby'] = "letter";
         $alphaquery = sDB::select($a);
         $cachehash = 'collection_alphanav_' . md5($alphaquery);
         $cached = Shopp::cache_get($cachehash, 'shopp_collection_alphanav');
         if ($cached) {
             // Load from object cache,  if available
             $this->alpha = $cached;
             $cached = false;
         } else {
             // Run query and cache results
             $expire = apply_filters('shopp_collection_cache_expire', 43200);
             $alpha = sDB::query($alphaquery, 'array', array($this, 'alphatable'));
             Shopp::cache_set($cachehash, $alpha, 'shopp_collection_alphanav', $expire);
         }
         $this->paged = true;
         if ($this->page == 1) {
             $this->page = '0-9';
         }
         $alphafilter = $this->page == "0-9" ? "(LEFT(p.post_title,1) REGEXP '[0-9]') = 1" : "IF(LEFT(p.post_title,1) REGEXP '[0-9]',LEFT(p.post_title,1),LEFT(SOUNDEX(p.post_title),1))='{$this->page}'";
         $options['where'][] = $alphafilter;
     }
     $query = sDB::select(apply_filters('shopp_collection_query', $options));
     if ($debug) {
         echo $query . BR . BR;
     }
     // Load from cached results if available, or run the query and cache the results
     $cachehash = 'collection_' . md5($query);
     $cached = Shopp::cache_get($cachehash, 'shopp_collection');
     if ($cached) {
         $this->products = $cached->products;
         $this->total = $cached->total;
     } else {
         $expire = apply_filters('shopp_collection_cache_expire', 43200);
         $cache = new stdClass();
         if ($ids) {
             $cache->products = $this->products = sDB::query($query, 'array', 'col', 'ID');
         } else {
             $cache->products = $this->products = sDB::query($query, 'array', array($Processing, 'loader'));
         }
         $cache->total = $this->total = sDB::found();
         // If running a limited set, the reported total found should not exceed the limit (but can because of SQL_CALC_FOUND_ROWS)
         // Don't use the limit if it is offset
         if ($limited && false === strpos($limit, ',')) {
             $cache->total = $this->total = min($limit, $this->total);
         }
         Shopp::cache_set($cachehash, $cache, 'shopp_collection', $expire);
     }
     if (false === $this->products) {
         $this->products = array();
     }
     if ($ids) {
         return $this->size() > 0;
     }
     // Finish up pagination construction
     if ($this->pagination > 0 && $this->total > $this->pagination) {
         $this->pages = ceil($this->total / $this->pagination);
         if ($this->pages > 1) {
             $this->paged = true;
         }
     }
     // Load all requested product meta from other data sources
     $Processing->load_data($load, $this->products);
     // If products are missing summary data, resum them
     if (isset($Processing->resum) && !empty($Processing->resum)) {
         $Processing->load_data(array('prices'), $Processing->resum);
     }
     unset($Processing);
     // Free memory
     $this->loaded = true;
     return $this->size() > 0;
 }
Esempio n. 9
0
 public function valid()
 {
     if (!$this->order()) {
         // boolean false and 0 are both invalid
         shopp_debug('PayPal messsage invalid. Missing or invalid "invoice" field.');
         return false;
     }
     if (false === $this->txnid() && false === $this->txnorigin()) {
         shopp_debug('PayPal messsage invalid. Missing txn_id or parent_txn_id.');
         return false;
     }
     return true;
 }
Esempio n. 10
0
        ?>
			<?php 
        check_admin_referer('shopp_upgrade_notice');
        $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
        $homeurl = wp_specialchars_decode(get_option('home'), ENT_QUOTES);
        $admin = get_bloginfo('admin_email');
        $site = parse_url($homeurl);
        $_ = array();
        $_[] = 'From: "' . $blogname . '" <' . shopp_setting('merchant_email') . '>';
        $_[] = 'To: ' . $admin;
        $_[] = sprintf('Subject: Shopp Upgraded on %s', $site['host']);
        $_[] = '';
        $_[] = sprintf(__('The Shopp installation on %1$s has been upgraded to %2$s and requires a database upgrade. Please login to %1$s and perform the upgrade by deactivating and reactivating the Shopp plugin.', 'Shopp'), $homeurl, ShoppVersion::release());
        $message = apply_filters('shopp_upgrade_notice_message', join("\n", $_));
        if (Shopp::email($message)) {
            shopp_debug('A Shopp upgrade notification was sent.');
        }
        Shopp::_em('### Upgrade Notice Sent

An upgrade notice has been sent to the site administrator.');
        ?>
		<?php 
    } else {
        ?>

			<div class="error"><?php 
        Shopp::_em('### Contact Your Site Administrator

You will need to notify a site administrator to perform the upgrade.');
        ?>
			</div>
Esempio n. 11
0
/**
 * Remove an address
 *
 * @api
 * @since 1.2
 *
 * @param int $address the address id to remove
 * @return bool true on success, false on failure
 **/
function shopp_rmv_customer_address($address = false)
{
    if (!$address) {
        shopp_debug(__FUNCTION__ . " failed: Missing address id parameter.");
        return false;
    }
    $Address = new ShoppAddress($address);
    if (empty($Address->id)) {
        shopp_debug(__FUNCTION__ . " failed: No such address with id {$address}.");
        return false;
    }
    return $Address->delete();
}
Esempio n. 12
0
 /**
  * @deprecated Do not use
  **/
 public function calculate()
 {
     shopp_debug(__CLASS__ . ' is a deprecated class. Use the Theme API instead.');
     return false;
 }
Esempio n. 13
0
 /**
  * Encrypts the session data.
  *
  * The session data is passed by reference and will be encrypted
  * if the stars are aligned (the secured flag is set over an SSL
  * connection with a valid encryption key).
  *
  * The security key is kept on the client-side as a secure cookie
  * so that the server only ever touches it for a short time.
  *
  * @param array $data The session data to encrypt
  * @return void
  **/
 private function encrypt(&$data)
 {
     if (!$this->secured()) {
         return;
     }
     if (!is_ssl()) {
         return;
     }
     if (!($key = $this->securekey())) {
         return;
     }
     shopp_debug('Cart saving in secure mode!');
     $secure = self::ENCRYPTION . sDB::query("SELECT AES_ENCRYPT('{$data}','{$key}') AS data", 'auto', 'col', 'data');
     $db = sDB::object();
     $data = $db->api->escape($secure);
 }
Esempio n. 14
0
 /**
  * Builds a shipping option from a configured/calculated
  * shipping rate array
  *
  * Example:
  * new ShippingOption(array(
  * 		'name' => 'Name of Shipping Rate Method',
  * 		'slug' => 'rate-method-slug',
  * 		'amount' => 0.99,
  * 		'delivery' => '1d-2d',
  * 		'items' => array(
  * 			0 => 0.99,
  * 			1 => 0.50
  * 		)
  * ));
  *
  * @author Jonathan Davis
  * @since 1.1
  *
  * @param array $rate The calculated shipping rate
  * @param boolean $estimate Flag to be included/excluded from estimates
  * @return void
  **/
 public function __construct(array $rate, $estimate = true)
 {
     if (!isset($rate['slug'])) {
         // Fire off an error if the slug is not provided
         return !shopp_debug('A slug (string) value is required in the $rate array parameter when constructing a new ShoppShiprateService');
     }
     $this->name = $rate['name'];
     $this->slug = $rate['slug'];
     $this->amount = $rate['amount'];
     $this->estimate = $estimate;
     if (!empty($rate['delivery'])) {
         $this->delivery = $rate['delivery'];
     }
     if (!empty($rate['items'])) {
         $this->items = $rate['items'];
     }
 }
Esempio n. 15
0
 /**
  * Create a new WordPress user associated with this customer
  *
  * @author Jonathan Davis
  * @since 1.3
  *
  * @return boolean True if successful, false otherwise
  **/
 public function create_wpuser()
 {
     if (empty($this->loginname)) {
         return false;
     }
     if (!validate_username($this->loginname)) {
         shopp_add_error(Shopp::__('This login name is invalid because it uses illegal characters. Valid login names include: letters, numbers, spaces, . - @ _'));
         return false;
     }
     if (username_exists($this->loginname)) {
         shopp_add_error(Shopp::__('The login name is already registered. Please choose another login name.'));
         return false;
     }
     if (empty($this->password)) {
         $this->password = wp_generate_password(12, true);
     }
     // Create the WordPress account
     $wpuser = wp_insert_user(array('user_login' => $this->loginname, 'user_pass' => $this->password, 'user_email' => $this->email, 'display_name' => $this->firstname . ' ' . $this->lastname, 'nickname' => $this->firstname, 'first_name' => $this->firstname, 'last_name' => $this->lastname));
     if (!$wpuser) {
         return false;
     }
     // Link the WP user ID to this customer record
     $this->wpuser = $wpuser;
     if (isset($this->passhash)) {
         global $wpdb;
         $wpdb->update($wpdb->users, array('user_pass' => $this->passhash), array('ID' => $wpuser));
     }
     if (apply_filters('shopp_notify_new_wpuser', true)) {
         // Send email notification of the new account
         $password = isset($this->passhash) ? '*******' : $this->password;
         // Only include generated passwords
         wp_new_user_notification($wpuser, $password);
     }
     shopp_debug(sprintf('Successfully created the WordPress user "%s" for the Shopp account.', $this->loginname));
     // Set the WP user created flag
     $this->session(self::WPUSER, true);
     return true;
 }
Esempio n. 16
0
 /**
  * Validate order data before transaction processing
  *
  * @author Jonathan Davis
  * @since 1.1
  *
  * @return boolean Validity of the order
  **/
 public function isvalid($report = true)
 {
     $Customer = $this->Customer;
     $Shipping = $this->Shipping;
     $Shiprates = $this->Shiprates;
     $Payments = $this->Payments;
     $Cart = $this->Cart;
     $valid = true;
     $errlevel = $report ? SHOPP_TRXN_ERR : SHOPP_DEBUG_ERR;
     shopp_debug('Validating order data for processing');
     if (0 == $Cart->count()) {
         $valid = apply_filters('shopp_ordering_empty_cart', false);
         shopp_add_error(__('There are no items in the cart.', 'Shopp'), $errlevel);
     }
     $stock = true;
     foreach ($Cart as $item) {
         if (!$item->instock()) {
             $valid = apply_filters('shopp_ordering_items_outofstock', false);
             shopp_add_error(sprintf(__('%s does not have sufficient stock to process order.', 'Shopp'), $item->name . (empty($item->option->label) ? '' : '(' . $item->option->label . ')')), $errlevel);
             $stock = false;
         }
     }
     $valid_customer = true;
     if (!$Customer) {
         $valid_customer = apply_filters('shopp_ordering_empty_customer', false);
     }
     // No Customer
     // Always require name and email
     if (empty($Customer->firstname)) {
         $valid_customer = apply_filters('shopp_ordering_empty_firstname', false);
     }
     if (empty($Customer->lastname)) {
         $valid_customer = apply_filters('shopp_ordering_empty_lastname', false);
     }
     if (empty($Customer->email)) {
         $valid_customer = apply_filters('shopp_ordering_empty_email', false);
     }
     if (!$valid_customer) {
         $valid = false;
         shopp_add_error(__('There is not enough customer information to process the order.', 'Shopp'), $errlevel);
     }
     // Check for shipped items but no Shipping information
     $valid_shipping = true;
     if ($Cart->shipped() && shopp_setting_enabled('shipping')) {
         if (empty($Shipping->address)) {
             $valid_shipping = apply_filters('shopp_ordering_empty_shipping_address', false);
         }
         if (empty($Shipping->country)) {
             $valid_shipping = apply_filters('shopp_ordering_empty_shipping_country', false);
         }
         if (empty($Shipping->postcode)) {
             $valid_shipping = apply_filters('shopp_ordering_empty_shipping_postcode', false);
         }
         if ($Shiprates->count() == 0 && !$Shiprates->free()) {
             $valid = apply_filters('shopp_ordering_no_shipping_costs', false);
             $message = __('The order cannot be processed. No shipping is available to the address you provided. Please return to %scheckout%s and try again.', 'Shopp');
             if ($Shiprates->realtime()) {
                 $message = __('The order cannot be processed. The shipping rate service did not provide rates because of a problem and no other shipping is available to the address you provided. Please return to %scheckout%s and try again or contact the store administrator.', 'Shopp');
             }
             if (!$valid) {
                 shopp_add_error(sprintf($message, '<a href="' . Shopp::url(false, 'checkout', $this->security()) . '">', '</a>'), $errlevel);
             }
         }
     }
     if (!$valid_shipping) {
         $valid = false;
         shopp_add_error(__('The shipping address information is incomplete. The order cannot be processed.', 'Shopp'), $errlevel);
     }
     // Alert when no gateway is configured (and the order is not free)
     if ($Payments->count() == 0 && $Cart->total() > 0) {
         $valid = false;
         shopp_add_error(Lookup::errors('gateway', 'nogateways'), $errlevel);
     }
     return $valid;
 }
Esempio n. 17
0
 /**
  * Create a lock for transaction processing
  *
  * @author Jonathan Davis
  * @since 1.2.1
  *
  * @return boolean
  **/
 public function lock($data)
 {
     if (!isset($data['order'])) {
         return false;
     }
     $order = $data['order'];
     $locked = 0;
     for ($attempts = 0; $attempts < 3 && $locked == 0; $attempts++) {
         $locked = sDB::query("SELECT GET_LOCK('{$order}'," . SHOPP_TXNLOCK_TIMEOUT . ") AS locked", 'auto', 'col', 'locked');
         if (0 == $locked) {
             sleep(1);
         }
         // Wait a sec before trying again
     }
     if (1 == $locked) {
         return true;
     }
     shopp_debug("Purchase authed lock for order #{$order} failed. Could not achieve a lock.");
     Shopp::redirect(Shopp::url(false, 'thanks', ShoppOrder()->security()));
 }
Esempio n. 18
0
/**
 * shopp_add_order_event - log an order event
 *
 * @api
 * @since 1.2
 *
 * @param int $order (conditionally required default:false) Will be false for purchase events, but needs the order id otherwise.
 * @param string $type (required) the order event type
 * @param array $message (optional default:array()) the event message protocol
 * @return bool true on success, false on error
 **/
function shopp_add_order_event($order = false, $type = false, $message = array())
{
    if (false !== $order && !shopp_order_exists($order)) {
        shopp_debug(__FUNCTION__ . " '{$type}' failed: Invalid order id.");
        return false;
    }
    if (!$type || !OrderEvent::handler($type)) {
        shopp_debug(__FUNCTION__ . " failed: Missing or invalid order event type");
        return false;
    }
    return OrderEvent::add($order, $type, $message);
}
Esempio n. 19
0
/**
 * Returns an array containing one or more values representing possible product weight (this might be one or multiple
 * weights if for instance the product has variants). The returned array is indexed on the variant ID where appropriate.
 * If there are no variants the actual product weight will have a zero index.
 *
 * @param $product ID or existing product object
 * @return array
 */
function shopp_product_weights($product)
{
    if (!is_a($product, 'ShoppProduct')) {
        $product = shopp_product($product);
    }
    if (false === $product) {
        shopp_debug(__FUNCTION__ . ' failed:  a valid product object or product ID must be specified.');
        return false;
    }
    $weights = array();
    foreach ($product->prices as $price) {
        $weight = isset($price->dimensions['weight']) ? $price->dimensions['weight'] : 0;
        if ('product' === $price->context) {
            $weights[0] = $weight;
        }
        if ('variation' === $price->context) {
            $weights[$price->id] = $weight;
        }
    }
    if (count($weights) > 1) {
        unset($weights[0]);
    }
    // Do not return the 'base' weight if there are variants
    return $weights;
}
Esempio n. 20
0
 /**
  * Determines if the module is a valid and compatible Shopp module
  *
  * @author Jonathan Davis
  * @since 1.1
  *
  * @return boolean True if the addon validates, false otherwise
  **/
 public function valid()
 {
     $error = false;
     if (false === strpos(strtolower($this->package), 'shopp') || empty($this->classname) || empty($this->interface)) {
         $error = true;
     } elseif (empty($this->version)) {
         $error = shopp_debug(sprintf('%s could not be loaded because no @version property was set in the addon header comments.', $this->filename));
     } elseif (empty($this->since)) {
         $error = shopp_debug(sprintf('%s could not be loaded because no @since property was set in the addon header comments.', $this->filename));
     } elseif (class_exists('ShoppVersion')) {
         if (version_compare(self::baseversion(ShoppVersion::release()), self::baseversion($this->since)) == -1) {
             $error = shopp_debug(sprintf('%s could not be loaded because it requires version %s (or higher) of Shopp.', $this->name, $this->since));
         }
     }
     if ($error) {
         return false;
     }
     return true;
 }
Esempio n. 21
0
/**
 * Remove a meta entry by meta id, or parent id, context, type, and name
 *
 * @api
 * @since 1.2
 *
 * @param int $id (required) - meta entry id or, with context, the parent object id
 * @param int $context (required for parent object id) - the parent object context
 * @param string $name (required with parent object context) - the meta name
 * @param string $type  (optional default: meta) - the meta type
 * @return bool true if the meta entry was removed, false on failure
 **/
function shopp_rmv_meta($id = false, $context = false, $name = false, $type = 'meta')
{
    if (!($id || $id && $context)) {
        shopp_debug(__FUNCTION__ . " failed: Must specify at least a meta id or parent id and context.");
        return false;
    }
    // remove existing meta record by meta id
    if ($id && !$context) {
        $meta = new ShoppMetaObject();
        $meta->load($id);
        if ($meta->id) {
            $meta->delete();
        }
        return true;
    }
    // fully spec'd meta entry
    if ($id && $context && $type && $name) {
        $meta = new ShoppMetaObject();
        $meta->load(array('parent' => $id, 'context' => $context, 'type' => $type, 'name' => $name));
        if ($meta->id) {
            $meta->delete();
        }
        return true;
    }
    // general meta entries
    if ($id && $context) {
        $table = ShoppDatabaseObject::tablename(ShoppMetaObject::$table);
        $id = db::escape($id);
        $context = db::escape($context);
        $name = db::escape($name);
        $type = db::escape($type);
        $where = "parent={$id} AND context='{$context}'";
        $where .= $type && !empty($type) ? " AND type='{$type}'" : "";
        $where .= $name && !empty($name) ? " AND type='{$name}'" : "";
        return db::query("DELETE FROM {$table} WHERE {$where}");
    }
}
Esempio n. 22
0
 public function lock()
 {
     if (empty($this->id)) {
         return false;
     }
     $locked = 0;
     for ($attempts = 0; $attempts < 3 && $locked == 0; $attempts++) {
         $locked = sDB::query("SELECT GET_LOCK('{$this->id}'," . SHOPP_TXNLOCK_TIMEOUT . ") AS locked", 'auto', 'col', 'locked');
         if (0 == $locked) {
             sleep(1);
         }
         // Wait a sec before trying again
     }
     if (1 == $locked) {
         return true;
     }
     shopp_debug("Purchase lock for order #{$this->id} failed. Could not achieve a lock.");
     return false;
 }
Esempio n. 23
0
 /**
  * Generates image markup
  *
  * Internal Theme API helper but must remain publicly available for other Theme API classes to access.
  *
  * @internal
  *
  * @param string $result  The output
  * @param array  $options The options
  * - **alt**: The alt property of the image
  * - **bg**: The background color to use with the matte fit (#rrggbb)
  * - **class**: Specifies the CSS class of the image
  * - **fit**: The fit of unproportional images to the requested size:
  *   - **all**: Scale the image down to fit within the new size (the final size may differ from the specified dimensions)
  *   - **crop**: Scale the image down to fit by the smallest dimension to fill the entire image, cropping the extra off the other dimension (specific cropping adjustments can be made in the product editor)
  *   - **height**: Scale the image down to fit the image in the new size by the height, cropping any extra width
  *   - **matte**: Scale the image down to fit within the new size filling extra space with a background color
  *   - **width**: Scale the image down to fit the image in the new size by the width, cropping any extra height
  * - **id**: Specify the image to show by the database ID
  * - **index**: Specify the index of the image to show
  * - **property**: (id,url,src,title,alt,width,height,class) Provide a property of the image rather than the image markup
  * - **quality**: The JPEG image quality (0-100%, default is 80)
  * - **sharpen**: Apply an unsharp mask to the image (100%-500%, default is none)
  * - **size**: The size to use for width and height of the image (used in place of width and height)
  * - **title**: The title property of the image
  * - **width**: The width of the image in pixels
  * - **height**: The height of the image in pixels
  * - **zoom**: `off` Enables the image zoom effect to view the original size image in a modal image viewer (Colorbox)
  * - **zoomfx**: `shopp-zoom` Enables zoom (also known as lightbox) effects for alternate JavaScript-based modal content viewers.
  * @param Object $O       The working object
  * @return string The generated image markup
  **/
 public static function image($result, $options, $O)
 {
     if (empty($O->images)) {
         return;
     }
     // Compatibility defaults
     $_size = 96;
     $_width = shopp_setting('gallery_thumbnail_width');
     $_height = shopp_setting('gallery_thumbnail_height');
     if (!$_width) {
         $_width = $_size;
     }
     if (!$_height) {
         $_height = $_size;
     }
     $defaults = array('alt' => '', 'bg' => false, 'class' => '', 'fit' => null, 'height' => false, 'id' => false, 'img' => false, 'index' => false, 'property' => false, 'quality' => null, 'setting' => '', 'sharpen' => null, 'size' => false, 'title' => '', 'width' => false, 'zoom' => false, 'zoomfx' => 'shopp-zoom');
     // Populate defaults from named image settings to allow specific overrides
     if (!empty($options['setting'])) {
         $setting = $options['setting'];
         $ImageSettings = ImageSettings::object();
         $settings = $ImageSettings->get($setting);
         if ($settings) {
             $defaults = array_merge($defaults, $settings->options());
         }
     }
     $options = array_merge($defaults, $options);
     extract($options);
     // Select image by database id
     if (false !== $id) {
         if (isset($O->images[$id])) {
             $Image = $O->images[$id];
         } else {
             shopp_debug(sprintf('No %s image exists with the specified database ID of %d.', get_class($O), $id));
             return '';
         }
     }
     // Select image by index position in the list
     if (false !== $index) {
         $keys = array_keys($O->images);
         if (isset($keys[$index]) && isset($O->images[$keys[$index]])) {
             $Image = $O->images[$keys[$index]];
         } else {
             shopp_debug(sprintf('No %s image exists at the specified index position %d.', get_class($O), $id));
             return '';
         }
     }
     // Use the current image pointer by default
     if (!isset($Image)) {
         $Image = current($O->images);
     }
     if (false !== $size) {
         $width = $height = $size;
     }
     if (!$width) {
         $width = $_width;
     }
     if (!$height) {
         $height = $_height;
     }
     $lowest_quality = min(ImageSetting::$qualities);
     $scale = $fit ? array_search($fit, ImageAsset::$defaults['scaling']) : null;
     $sharpen = $sharpen ? max($sharpen, ImageAsset::$defaults['sharpen']) : null;
     $quality = $quality ? max($quality, $lowest_quality) : null;
     if ('transparent' == strtolower($bg)) {
         $fill = -1;
     } else {
         $fill = $bg ? hexdec(ltrim($bg, '#')) : false;
     }
     list($width_a, $height_a) = array_values($Image->scaled($width, $height, $scale));
     if ('original' == $size) {
         $width_a = $Image->width;
         $height_a = $Image->height;
     }
     if ($width_a === false) {
         $width_a = $width;
     }
     if ($height_a === false) {
         $height_a = $height;
     }
     $alt = esc_attr(empty($alt) ? empty($Image->alt) ? $Image->name : $Image->alt : $alt);
     $title = empty($title) ? $Image->title : $title;
     $titleattr = empty($title) ? '' : ' title="' . esc_attr($title) . '"';
     $classes = empty($class) ? '' : ' class="' . esc_attr($class) . '"';
     $src = 'original' == $size ? $Image->url() : $Image->url($width, $height, $scale, $sharpen, $quality, $fill);
     switch (strtolower($property)) {
         case 'id':
             return $Image->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;
     }
     $img = '<img src="' . $src . '"' . $titleattr . ' alt="' . $alt . '" width="' . (int) $width_a . '" height="' . (int) $height_a . '" ' . $classes . ' />';
     if (Shopp::str_true($zoom)) {
         return '<a href="' . $Image->url() . '" class="' . $zoomfx . '" rel="product-' . $O->id . '"' . $titleattr . '>' . $img . '</a>';
     }
     return $img;
 }
Esempio n. 24
0
/**
 * shopp_set_image_setting - saves an image setting
 *
 * The settings parameter accepts:
 * 		width => (pixel width)
 * 		height => (pixel height)
 * 		size => (pixels, sets width and height)
 * 		fit => (all,matte,crop,width,height)
 * 		quality => (0-100 quality percentage)
 * 		sharpen => (0-100 sharpen percentage)
 * 		bg => (hex color, such as red: #ff0000)
 *
 * @api
 * @since 1.2
 *
 * @param string $name     The name of the setting that is to be stored.
 * @param array  $settings A named array of settings and values, accepts: width, height, size, fit, quality, sharpen, bg
 * @return bool true on success, false on failure.
 **/
function shopp_set_image_setting($name, array $settings = array())
{
    if (empty($name)) {
        shopp_debug(__FUNCTION__ . " failed: Setting name parameter required.");
        return false;
    }
    $defaults = array('width' => false, 'height' => false, 'fit' => 'all', 'size' => 96, 'quality' => 100, 'sharpen' => 100, 'bg' => false);
    if (isset($settings['size'])) {
        $settings['width'] = $settings['height'] = $settings['size'];
    }
    $settings = array_merge($defaults, $settings);
    if (in_array($settings['fit'], ImageSetting::$fittings)) {
        $settings['fit'] = array_search($settings['fit'], ImageSetting::$fittings);
    }
    // Load/update an existing one there is one
    $ImageSetting = new ImageSetting($name, 'name');
    $ImageSetting->name = $name;
    foreach ($settings as $prop => $value) {
        $ImageSetting->{$prop} = $value;
    }
    $ImageSetting->save();
    return true;
}
Esempio n. 25
0
 /**
  * Redirects the browser to a specified URL
  *
  * A wrapper for the wp_redirect function
  *
  * @author Jonathan Davis
  * @since 1.0
  *
  * @param string $uri The URI to redirect to
  * @param boolean $exit (optional) Exit immediately after the redirect (defaults to true, set to false to override)
  * @return void
  **/
 public static function redirect($uri, $exit = true, $status = 302)
 {
     shopp_debug("Redirecting to: {$uri}");
     remove_action('shutdown', array(ShoppShopping(), 'save'));
     ShoppShopping()->save();
     wp_redirect($uri, $status);
     if ($exit) {
         exit;
     }
 }
Esempio n. 26
0
 public static function process()
 {
     // We have to avoid truthiness, hence the strange logic expression
     if (true !== apply_filters('shopp_validate_registration', true)) {
         return;
     }
     $Customer = ShoppOrder()->Customer;
     do_action('shopp_customer_registration', $Customer);
     if ($Customer->session(ShoppCustomer::GUEST)) {
         $Customer->type = __('Guest', 'Shopp');
         // No cuts
         $Customer->wpuser = 0;
         // No buts
         unset($Customer->password);
         // No coconuts
     } else {
         // WordPress account integration used, customer has no wp user
         if ('wordpress' == shopp_setting('account_system') && empty($Customer->wpuser)) {
             if ($wpuser = get_current_user_id()) {
                 $Customer->wpuser = $wpuser;
             } else {
                 $Customer->create_wpuser();
             }
             // not logged in, create new account
         }
         if (!$Customer->exists(true)) {
             $Customer->id = false;
             shopp_debug('Creating new Shopp customer record');
             if (empty($Customer->password)) {
                 $Customer->password = wp_generate_password(12, true);
             }
             if ('shopp' == shopp_setting('account_system')) {
                 $Customer->notification();
             }
             $Customer->password = wp_hash_password($Customer->password);
             if (isset($Customer->passhash)) {
                 $Customer->password = $Customer->passhash;
             }
         } else {
             unset($Customer->password);
         }
         // Existing customer, do not overwrite password field!
     }
     // New customer, save hashed password
     $Customer->save();
     $Customer->password = '';
     // Update billing and shipping addresses
     $addresses = array('Billing', 'Shipping');
     foreach ($addresses as $Address) {
         if (empty(ShoppOrder()->{$Address}->address)) {
             continue;
         }
         $Address = ShoppOrder()->{$Address};
         $Address->customer = $Customer->id;
         $Address->save();
     }
     do_action('shopp_customer_registered', $Customer);
     // Auto-login
     $Customer->login();
     // Login the customer
     if (!empty($Customer->wpuser)) {
         // Log the WordPress user in
         ShoppLogin::wpuser(get_user_by('id', $Customer->wpuser));
     }
     if (apply_filters('shopp_registration_redirect', false)) {
         Shopp::redirect(Shopp::url(false, 'account'));
     }
 }
Esempio n. 27
0
/**
 * Get count of categories associated with a product
 *
 * @api
 * @since 1.2
 *
 * @param int $product (required) the product id
 * @return int count of categories
 **/
function shopp_product_categories_count($product)
{
    $Product = new ShoppProduct($product);
    if (empty($Product->id)) {
        shopp_debug(__FUNCTION__ . " failed: Invalid product {$product}.");
        return false;
    }
    $terms = wp_get_post_terms($product, ProductCategory::$taxon, array());
    return count($terms);
}