/** * Initializes a shipping module * * Grabs settings that most shipping modules will needs and establishes * the event listeners to trigger module functionality. * * @author Jonathan Davis * @since 1.1 * * @return void **/ public function __construct() { $Order = ShoppOrder(); $this->module = get_class($this); if ($this->singular) { // @todo Remove legacy gateway settings migrations // Attempt to copy old settings if this is a new prefixed gateway class $this->settings = shopp_setting($this->module); if (empty($this->settings) && false !== strpos($this->module, 'Shopp')) { $legacy = substr($this->module, 5); $this->settings = shopp_setting($legacy); if (!empty($this->settings)) { shopp_set_setting($this->module, $this->settings); shopp_rmv_setting($legacy); // Clean up legacy setting } } } else { $active = shopp_setting('active_shipping'); if (isset($active[$this->module]) && is_array($active[$this->module])) { $this->methods = array(); $this->fallbacks = array(); foreach ($active[$this->module] as $index => $set) { $setting = shopp_setting("{$this->module}-{$index}"); if (isset($setting['fallback']) && 'on' == $setting['fallback']) { $this->fallbacks["{$this->module}-{$index}"] = $setting; } else { $this->methods["{$this->module}-{$index}"] = $setting; } } } } $this->base = shopp_setting('base_operations'); $this->units = shopp_setting('weight_unit'); // Setup default packaging for shipping module $this->settings['shipping_packaging'] = shopp_setting('shipping_packaging'); // Shipping module can override the default behavior and the global setting by specifying the local packaging property if (isset($this->packaging) && $this->packaging != $this->settings['shipping_packaging']) { $this->settings['shipping_packaging'] = $this->packaging; } $this->packager = apply_filters('shopp_' . strtolower($this->module) . '_packager', new ShippingPackager(array('type' => $this->settings['shipping_packaging']), $this->module)); $this->destinations = __('Service provider markets', 'Shopp'); add_action('shopp_calculate_shipping_init', array(&$this, 'init')); add_action('shopp_calculate_item_shipping', array(&$this, 'calcitem'), 10, 2); add_action('shopp_calculate_shipping', array(&$this, 'calculate'), 10, 2); if (isset($this->fallbacks) && !empty($this->fallbacks)) { add_action('shopp_calculate_fallback_shipping_init', array(&$this, 'fallbacks')); add_action('shopp_calculate_fallback_shipping', array(&$this, 'calculate')); add_action('shopp_calculate_fallback_shipping', array(&$this, 'reset'), 20); } }
public function recache() { shopp_rmv_setting(self::MODULES_SETTING); shopp_rmv_setting(self::INVALID_FILES_SETTING); $this->installed(); }
public function upgrade_120() { // 1.2 schema changes $db_version = ShoppSettings::dbversion(); if ($db_version < 1120) { $this->upschema('schema-120.sql'); } global $wpdb; // Clear the shopping session table $shopping_table = ShoppDatabaseObject::tablename('shopping'); sDB::query("DELETE FROM {$shopping_table}"); if ($db_version <= 1140) { $summary_table = ShoppDatabaseObject::tablename('summary'); // Force summaries to rebuild sDB::query("UPDATE {$summary_table} SET modified='0000-00-00 00:00:01'"); } $purchase_table = ShoppDatabaseObject::tablename('purchase'); sDB::query("UPDATE {$purchase_table} SET txnstatus='captured' WHERE txnstatus='CHARGED'"); sDB::query("UPDATE {$purchase_table} SET txnstatus='voided' WHERE txnstatus='VOID'"); if ($db_version <= 1130) { // Move settings to meta table $meta_table = ShoppDatabaseObject::tablename('meta'); $setting_table = ShoppDatabaseObject::tablename('setting'); sDB::query("INSERT INTO {$meta_table} (context, type, name, value, created, modified) SELECT 'shopp', 'setting', name, value, created, modified FROM {$setting_table}"); // Clean up unnecessary duplicate settings shopp_rmv_setting('data_model'); shopp_rmv_setting('updates'); shopp_rmv_setting('shopp_setup'); shopp_rmv_setting('maintenance'); // Re-load the Shopp settings registry ShoppSettings()->load(); shopp_set_setting('maintenance', 'on'); $db_version = intval(shopp_setting('db_version')); // Force inventory in 1.2 on to mimic 1.1 behavior (inventory tracking always on) shopp_set_setting('inventory', 'on'); // Convert Shopp 1.1.x shipping settings to Shopp 1.2-compatible settings $active_shipping = array(); $regions = Lookup::regions(); $countries = Lookup::countries(); $areas = Lookup::country_areas(); $calcnaming = array('FlatRates::order' => 'OrderRates', 'FlatRates::item' => 'ItemRates', 'FreeOption' => 'FreeOption', 'ItemQuantity::range' => 'ItemQuantity', 'OrderAmount::range' => 'OrderAmount', 'OrderWeight::range' => 'OrderWeight'); $shipping_rates = shopp_setting('shipping_rates'); foreach ((array) $shipping_rates as $id => $old) { if (isset($calcnaming[$old['method']])) { // Add to active setting registry for that calculator class $calcname = $calcnaming[$old['method']]; if (!isset(${$calcname}) && !is_array(${$calcname})) { ${$calcname} = array(); } ${$calcname}[] = true; $active_shipping[$calcname] = ${$calcname}; // Define the setting name $settingid = end(array_keys(${$calcname})); $setting_name = $calcname . '-' . $settingid; } else { // Not a calculator, must be a shipping rate provider module, add it to the active roster $active_shipping[$old['name']] = true; continue; } $new = array(); $new['label'] = $old['name']; list($new['mindelivery'], $new['maxdelivery']) = explode('-', $old['delivery']); $new['fallback'] = 'off'; // Not used in legacy settings $oldkeys = array_keys($old); $old_destinations = array_diff($oldkeys, array('name', 'delivery', 'method', 'max')); $table = array(); foreach ($old_destinations as $old_dest) { $_ = array(); if ('Worldwide' == $old_dest) { $d = '*'; } $region = array_search($old_dest, $regions); if (false !== $region) { $d = "{$region}"; } if (isset($countries[$old_dest])) { $country = $countries[$old_dest]; $region = $country['region']; $d = "{$region}, {$old_dest}"; } foreach ($areas as $countrykey => $countryarea) { $areakeys = array_keys($countryarea); $area = array_search($old_dest, $areakeys); if (false !== $area) { $country = $countrykey; $region = $countries[$countrykey]['region']; $area = $areakeys[$area]; $d = "{$region}, {$country}, {$area}"; break; } } $_['destination'] = $d; $_['postcode'] = '*'; // Postcodes are new in 1.2, hardcode to wildcard if (isset($old['max']) && !empty($old['max'])) { // Capture tiered rates $_['tiers'] = array(); $prior = 1; foreach ($old['max'] as $index => $oldthreshold) { $tier = array('threshold' => 0, 'rate' => 0); if (in_array($oldthreshold, array('+', '>'))) { $tier['threshold'] = $prior + 1; } elseif (1 == $oldthreshold) { $tier['threshold'] = 1; } else { $tier['threshold'] = $prior + 1; } $prior = $oldthreshold; $tier['rate'] = $old[$old_dest][$index]; $_['tiers'][] = $tier; } } else { $_['rate'] = $old[$old_dest][0]; } // Capture flat rates $table[] = $_; } $new['table'] = $table; shopp_set_setting($setting_name, $new); // Save the converted settings } // End foreach($shipping_rates) to convert old shipping calculator setting format shopp_set_setting('active_shipping', $active_shipping); // Save the active shipping options } if ($db_version <= 1121) { $address_table = ShoppDatabaseObject::tablename('address'); $billing_table = ShoppDatabaseObject::tablename('billing'); $shipping_table = ShoppDatabaseObject::tablename('shipping'); // Move billing address data to the address table sDB::query("INSERT INTO {$address_table} (customer, type, address, xaddress, city, state, country, postcode, created, modified)\n\t\t\t\t\t\tSELECT customer, 'billing', address, xaddress, city, state, country, postcode, created, modified FROM {$billing_table}"); sDB::query("INSERT INTO {$address_table} (customer, type, address, xaddress, city, state, country, postcode, created, modified)\n\t\t\t\t\t\tSELECT customer, 'shipping', address, xaddress, city, state, country, postcode, created, modified FROM {$shipping_table}"); } // Migrate to WP custom posts & taxonomies if ($db_version <= 1131) { // Copy products to posts $catalog_table = ShoppDatabaseObject::tablename('catalog'); $product_table = ShoppDatabaseObject::tablename('product'); $price_table = ShoppDatabaseObject::tablename('price'); $summary_table = ShoppDatabaseObject::tablename('summary'); $meta_table = ShoppDatabaseObject::tablename('meta'); $category_table = ShoppDatabaseObject::tablename('category'); $tag_table = ShoppDatabaseObject::tablename('tag'); $purchased_table = ShoppDatabaseObject::tablename('purchased'); $index_table = ShoppDatabaseObject::tablename('index'); $post_type = 'shopp_product'; // Create custom post types from products, temporarily use post_parent for link to original product entry sDB::query("INSERT INTO {$wpdb->posts} (post_type, post_name, post_title, post_excerpt, post_content, post_status, post_date, post_date_gmt, post_modified, post_modified_gmt, post_parent)\n\t\t\t\t\t\t\tSELECT '{$post_type}', slug, name, summary, description, status, created, created, modified, modified, id FROM {$product_table}"); // Update purchased table product column with new Post ID so sold counts can be updated sDB::query("UPDATE {$purchased_table} AS pd JOIN {$wpdb->posts} AS wp ON wp.post_parent=pd.product AND wp.post_type='{$post_type}' SET pd.product=wp.ID"); // Update product links for prices and meta sDB::query("UPDATE {$price_table} AS price JOIN {$wpdb->posts} AS wp ON price.product=wp.post_parent SET price.product=wp.ID WHERE wp.post_type='{$post_type}'"); sDB::query("UPDATE {$meta_table} AS meta JOIN {$wpdb->posts} AS wp ON meta.parent=wp.post_parent AND wp.post_type='{$post_type}' AND meta.context='product' SET meta.parent=wp.ID"); sDB::query("UPDATE {$index_table} AS i JOIN {$wpdb->posts} AS wp ON i.product=wp.post_parent AND wp.post_type='{$post_type}' SET i.product=wp.ID"); // Preliminary summary data sDB::query("INSERT INTO {$summary_table} (product, featured, variants, addons, modified)\n\t\t\t\t\t\t SELECT wp.ID, p.featured, p.variations, p.addons, '0000-00-00 00:00:01'\n\t\t\t\t\t\t FROM {$product_table} AS p\n\t\t\t\t\t\t JOIN {$wpdb->posts} as wp ON p.id=wp.post_parent AND wp.post_type='{$post_type}'"); // Move product options column to meta setting sDB::query("INSERT INTO {$meta_table} (parent, context, type, name, value)\n\t\t\t\t\t\tSELECT wp.ID, 'product', 'meta', 'options', options\n\t\t\t\t\t\tFROM {$product_table} AS p\n\t\t\t\t\t\tJOIN {$wpdb->posts} AS wp ON p.id=wp.post_parent AND wp.post_type='{$post_type}'"); // Migrate Shopp categories and tags to WP taxonomies // Are there tag entries in the meta table? Old dev data present use meta table tags. No? use tags table. $dev_migration = $db_version >= 1120; // Copy categories and tags to WP taxonomies $tag_current_table = $dev_migration ? "{$meta_table} WHERE context='catalog' AND type='tag'" : $tag_table; $terms = sDB::query("(SELECT id, 'shopp_category' AS taxonomy, name, parent, description, slug FROM {$category_table})\n\t\t\t\t\t\t\t\t\t\t\tUNION\n\t\t\t\t\t\t\t\t\t\t(SELECT id, 'shopp_tag' AS taxonomy, name, 0 AS parent, '' AS description, name AS slug FROM {$tag_current_table}) ORDER BY id", 'array'); // Prep category images for the move $category_image_offset = 65535; sDB::query("UPDATE {$meta_table} set parent=parent+{$category_image_offset} WHERE context='category' AND type='image'"); $mapping = array(); $children = array(); $tt_ids = array(); foreach ($terms as $term) { $term_id = (int) $term->id; $taxonomy = $term->taxonomy; if (!isset($mapping[$taxonomy])) { $mapping[$taxonomy] = array(); } if (!isset($children[$taxonomy])) { $children[$taxonomy] = array(); } $name = $term->name; $parent = $term->parent; $description = $term->description; $slug = strpos($term->slug, ' ') === false ? $term->slug : sanitize_title_with_dashes($term->slug); $term_group = 0; if ($exists = sDB::query("SELECT term_id, term_group FROM {$wpdb->terms} WHERE slug = '{$slug}'", 'array')) { $term_group = $exists[0]->term_group; $id = $exists[0]->term_id; $num = 2; do { $alternate = sDB::escape($slug . "-" . $num++); $alternate_used = sDB::query("SELECT slug FROM {$wpdb->terms} WHERE slug='{$alternate}'"); } while ($alternate_used); $slug = $alternate; if (empty($term_group)) { $term_group = sDB::query("SELECT MAX(term_group) AS term_group FROM {$wpdb->terms} GROUP BY term_group", 'auto', 'col', 'term_group'); sDB::query("UPDATE {$wpdb->terms} SET term_group='{$term_group}' WHERE term_id='{$id}'"); } } // Move the term into the terms table $wpdb->query($wpdb->prepare("INSERT INTO {$wpdb->terms} (name, slug, term_group) VALUES (%s, %s, %d)", $name, $slug, $term_group)); $mapping[$taxonomy][$term_id] = (int) $wpdb->insert_id; // Map the old id to the new id $term_id = $mapping[$taxonomy][$term_id]; // Update the working id to the new id if (!isset($tt_ids[$taxonomy])) { $tt_ids[$taxonomy] = array(); } if ('shopp_category' == $taxonomy) { // If the parent term has already been added to the terms table, set the new parent id if (isset($mapping[$taxonomy][$parent])) { $parent = $mapping[$taxonomy][$parent]; } else { // Parent hasn't been created, keep track of children for the parent to do a mass update when the parent term record is created if (!isset($children[$taxonomy][$parent])) { $children[$taxonomy][$parent] = array(); } $children[$taxonomy][$parent][] = $term_id; } if (!empty($children[$taxonomy][$term->id])) { // If there are children already created for this term, update their parent to our new id $wpdb->query("UPDATE {$wpdb->term_taxonomy} SET parent={$term_id} WHERE term_id IN (" . join(', ', $children[$taxonomy][$term->id]) . ")"); } // Associate the term to the proper taxonomy and parent terms $wpdb->query($wpdb->prepare("INSERT INTO {$wpdb->term_taxonomy} (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, 0)); $tt_ids[$taxonomy][$term_id] = (int) $wpdb->insert_id; if (!empty($term_id)) { // Move category settings to meta $metafields = array('spectemplate', 'facetedmenus', 'variations', 'pricerange', 'priceranges', 'specs', 'options', 'prices'); foreach ($metafields as $field) { sDB::query("INSERT INTO {$meta_table} (parent, context, type, name, value)\n\t\t\t\t\t\t\t\t\t\t\tSELECT {$term_id}, 'category', 'meta', '{$field}', {$field}\n\t\t\t\t\t\t\t\t\t\t\tFROM {$category_table}\n\t\t\t\t\t\t\t\t\t\t\tWHERE id={$term->id}"); } // Update category images to new term ids sDB::query("UPDATE {$meta_table} set parent='{$term_id}' WHERE parent='" . ((int) $term->id + $category_image_offset) . "' AND context='category' AND type='image'"); } } if ('shopp_tag' == $taxonomy) { $wpdb->query($wpdb->prepare("INSERT INTO {$wpdb->term_taxonomy} (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, 0)); $tt_ids[$taxonomy][$term_id] = (int) $wpdb->insert_id; } } update_option('shopp_category_children', ''); // Re-catalog custom post type_products term relationships (new taxonomical catalog) from old Shopp catalog table $wp_taxonomies = array(0 => 'shopp_category', 1 => 'shopp_tag', 'category' => 'shopp_category', 'tag' => 'shopp_tag'); $cols = 'wp.ID AS product, c.parent, c.type'; $where = "type='category' OR type='tag'"; if ($db_version >= 1125) { $cols = 'wp.ID AS product, c.parent, c.taxonomy, c.type'; $where = "taxonomy=0 OR taxonomy=1"; } $rels = sDB::query("SELECT {$cols} FROM {$catalog_table} AS c LEFT JOIN {$wpdb->posts} AS wp ON c.product=wp.post_parent AND wp.post_type='{$post_type}' WHERE {$where}", 'array'); foreach ((array) $rels as $r) { $object_id = $r->product; $taxonomy = $wp_taxonomies[$db_version >= 1125 ? $r->taxonomy : $r->type]; $term_id = $mapping[$taxonomy][$r->parent]; if (!isset($tt_ids[$taxonomy])) { continue; } if (!isset($tt_ids[$taxonomy][$term_id])) { continue; } $tt_id = $tt_ids[$taxonomy][$term_id]; if (empty($tt_id)) { continue; } sDB::query("INSERT {$wpdb->term_relationships} (object_id, term_taxonomy_id) VALUES ({$object_id}, {$tt_id})"); } if (isset($tt_ids['shopp_category'])) { wp_update_term_count_now($tt_ids['shopp_category'], 'shopp_category'); } if (isset($tt_ids['shopp_tag'])) { wp_update_term_count_now($tt_ids['shopp_tag'], 'shopp_tag'); } // Clear custom post type parents sDB::query("UPDATE {$wpdb->posts} SET post_parent=0 WHERE post_type='{$post_type}'"); } // END if ($db_version <= 1131) if ($db_version <= 1133) { // Ditch old WP pages for pseudorific new ones $search = array(); $shortcodes = array('[catalog]', '[cart]', '[checkout]', '[account]'); foreach ($shortcodes as $string) { $search[] = "post_content LIKE '%{$string}%'"; } $results = sDB::query("SELECT ID, post_title AS title, post_name AS slug, post_content FROM {$wpdb->posts} WHERE post_type='page' AND (" . join(" OR ", $search) . ")", 'array'); $pages = $trash = array(); foreach ($results as $post) { $trash[] = $post->ID; foreach ($shortcodes as $code) { if (strpos($post->post_content, $code) === false) { continue; } $pagename = trim($code, '[]'); $pages[$pagename] = array('title' => $post->title, 'slug' => $post->slug); } // end foreach $shortcodes } // end foreach $results shopp_set_setting('storefront_pages', $pages); sDB::query("UPDATE {$wpdb->posts} SET post_name=CONCAT(post_name, '-deprecated'), post_status='trash' where ID IN (" . join(', ', $trash) . ")"); } // Move needed price table columns to price meta records if ($db_version <= 1135) { $meta_table = ShoppDatabaseObject::tablename('meta'); $price_table = ShoppDatabaseObject::tablename('price'); // Move 'options' to meta 'options' record sDB::query("INSERT INTO {$meta_table} (parent, context, type, name, value, created, modified)\n\t\t\t\t\t\tSELECT id, 'price', 'meta', 'options', options, created, modified FROM {$price_table}"); // Merge 'weight', 'dimensions' and 'donation' columns to a price 'settings' record sDB::query("INSERT INTO {$meta_table} (parent, context, type, name, value, created, modified)\n\t\t\t\t\t\t\tSELECT id, 'price', 'meta', 'settings',\n\t\t\t\t\t\t\tCONCAT('a:2:{s:10:\"dimensions\";',\n\t\t\t\t\t\t\t\tIF(weight = 0 AND dimensions = '0', 'a:0:{}',\n\t\t\t\t\t\t\t\t\tIF(dimensions = '0',\n\t\t\t\t\t\t\t\t\t\tCONCAT(\n\t\t\t\t\t\t\t\t\t\t\t'a:1:{s:6:\"weight\";s:', CHAR_LENGTH(weight), ':\"', weight, '\";}'\n\t\t\t\t\t\t\t\t\t\t), dimensions\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t), 's:8:\"donation\";', IF(donation='', 'N;', donation), '}'\n\t\t\t\t\t\t\t), created, modified FROM {$price_table}"); } // END if ($db_version <= 1135) if ($db_version <= 1145) { // Update purchase gateway property to use gateway class names // for proper order event handling on 1.1-generated orders $gateways = array('PayPal Standard' => 'PayPalStandard', 'PayPal Expresss' => 'PayPalExpress', 'PayPal Pro' => 'PayPalPro', '2Checkout.com' => '_2Checkout', 'Authorize.Net' => 'AuthorizeNet', 'Google Checkout' => 'GoogleCheckout', 'HSBC ePayments' => 'HSBCepayments', 'iDeal Mollie' => 'iDealMollie', 'Manual Processing' => 'ManualProcessing', 'Merchant Warrior' => 'MerchantWarrior', 'Offline Payment' => 'OfflinePayment', 'PayPal Payflow Pro' => 'PayflowPro', 'Test Mode' => 'TestMode'); foreach ($gateways as $name => $classname) { sDB::query("UPDATE {$purchase_table} SET gateway='{$classname}' WHERE gateway='{$name}'"); } } // END if ($db_version <= 1145) if ($db_version <= 1148) { $price_table = ShoppDatabaseObject::tablename('price'); sDB::query("UPDATE {$price_table} SET optionkey=(options*7001) WHERE context='addon'"); } if ($db_verison <= 1150) { $meta_table = ShoppDatabaseObject::tablename('meta'); sDB::query("DELETE {$meta_table} FROM {$meta_table} LEFT OUTER JOIN (SELECT MAX(id) AS keepid FROM {$meta_table} WHERE context='category' AND type='meta' GROUP BY parent, name) AS keepRowTable ON {$meta_table}.id = keepRowTable.keepid WHERE keepRowTable.keepid IS NULL AND context='category' AND type='meta'"); } }