-
Reinhold Kainhofer authored
Work on issue #12
Reinhold Kainhofer authoredWork on issue #12
rules_shipping_framework_woocommerce.php 16.19 KiB
<?php
/**
* Shipping by Rules generic helper class (WP/WooCommerce-specific)
* Reinhold Kainhofer, Open Tools, office@open-tools.net
* @copyright (C) 2012-2016 - Reinhold Kainhofer
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
**/
if ( !defined( 'ABSPATH' ) ) {
die( 'Direct Access to ' . basename( __FILE__ ) . ' is not allowed.' );
}
require_once( plugin_dir_path( __FILE__ ) . '/../library/rules_shipping_framework.php');
class RulesShippingFrameworkWooCommerce extends RulesShippingFramework {
protected static $_method_ordering = 'woocommerce_shipping_rules_ordering';
function __construct() {
parent::__construct();
load_plugin_textdomain('woocommerce-shipping-by-rules', false, basename( dirname( __FILE__ ) ) . '/languages' );
$this->registerScopings(array(
"categories" => 'categories',
"subcategories" => 'subcategories',
"products" => 'products',
"skus" => 'products',
"vendors" => 'vendors',
));
}
static function getHelper() {
static $helper = null;
if (!$helper) {
$helper = new RulesShippingFrameworkWooCommerce();
$helper->setup();
}
return $helper;
}
function urlPath($type, $file) {
return plugins_url('library/' . $type . '/' . $file, __FILE__);
}
function isAdvanced() {
return false;
}
function getCustomFunctions() {
// Let other plugins add custom functions!
// The opentools_shipping_by_rules_replacements filter is expected to return an array of the form:
// array ('functionname1' => 'function-to-be-called',
// 'functionname2' => array($classobject, 'memberfunc')),
// ...);
return apply_filters( 'opentools_shipping_by_rules_replacements', array());
}
public function printMessage($message, $type) {
// Keep track of warning messages, so we don't print them twice:
global $printed_messages;
if (!isset($printed_messages))
$printed_messages = array();
if ($type == "debug") {
if ( true === WP_DEBUG ) {
if ( is_array( $message ) || is_object( $message ) ) {
error_log( print_r( $message, true ) );
} else {
error_log( $message );
}
}
} elseif (!in_array($message, $printed_messages)) {
switch ($type) {
case 'error':
case 'warning':
wc_add_notice( $message, 'error'); break;
case 'message':
wc_add_notice( $message, 'success'); break;
case 'notice':
default:
wc_add_notice( $message, 'notice'); break;
}
$printed_messages[] = $message;
}
}
/**
* HELPER FUNCTIONS, WooCommerce-specific
*/
public function __($string) {
$args = func_get_args();
$string = $this->readableString($string);
$string = __($string, 'opentools-shippingrules');
if (count($args)>1) {
$args[0] = $string;
return call_user_func_array("sprintf", $args);
} else {
return $string;
}
}
protected function getCartProducts($package, $method) {
return $package['contents'];
}
protected function getMethodId($method) {
return $method->get_rate_id();
}
protected function getMethodName($method) {
return $method->title;
}
// TODO: Legacy
protected function parseMethodRules (&$method) {
return $this->parseMethodRule(
/* Rules */ isset($method->rules)?$method->rules:'',
/* Countries */array(),
/* Rule info */array(),
/* Method */ $method);
}
/**
* Functions to calculate the cart variables:
* - getOrderCounts($cart, $products, $method)
* - getOrderDimensions
*/
/** Functions to calculate all the different variables for the given cart and given (sub)set of products in the cart */
protected function getOrderCounts ($cart, $products, $method) {
$counts = array(
'articles' => 0,
'products' => count($products),
'quantity' => 0,
'minquantity' => 9999999999,
'maxquantity' => 0,
);
foreach ($products as $product) {
$counts['articles'] += $product['quantity'];
$counts['maxquantity'] = max ($counts['maxquantity'], $product['quantity']);
$counts['minquantity'] = min ($counts['minquantity'], $product['quantity']);
}
$counts['quantity'] = $counts['articles'];
return $counts;
}
protected function getOrderDimensions ($cart, $products, $method) {
/* Cache the value in a static variable and calculate it only once! */
$dimensions=array(
'volume' => 0,
'maxvolume' => 0, 'minvolume' => 99999999,
'maxlength' => 0, 'minlength' => 99999999, 'totallength' => 0,
'maxwidth' => 0, 'minwidth' => 99999999, 'totalwidth' => 0,
'maxheight' => 0, 'minheight' => 99999999, 'totalheight' => 0,
);
foreach ($products as $product) {
$l = $product['data']->get_length();
$w = $product['data']->get_width();
$h = $product['data']->get_height();
$volume = $l * $w * $h;
$dimensions['volume'] += $volume * $product['quantity'];
$dimensions['maxvolume'] = max ($dimensions['maxvolume'], $volume);
$dimensions['minvolume'] = min ($dimensions['minvolume'], $volume);
$dimensions['totallength'] += $l * $product['quantity'];
$dimensions['maxlength'] = max ($dimensions['maxlength'], $l);
$dimensions['minlength'] = min ($dimensions['minlength'], $l);
$dimensions['totalwidth'] += $w * $product['quantity'];
$dimensions['maxwidth'] = max ($dimensions['maxwidth'], $w);
$dimensions['minwidth'] = min ($dimensions['minwidth'], $w);
$dimensions['totalheight'] += $h * $product['quantity'];
$dimensions['maxheight'] = max ($dimensions['maxheight'], $h);
$dimensions['minheight'] = min ($dimensions['minheight'], $h);
}
return $dimensions;
}
protected function getOrderWeights ($cart, $products, $method) {
$dimensions=array(
'weight' => 0,
'maxweight' => 0, 'minweight' => 9999999999,
);
foreach ($products as $product) {
$w = $product['data']->get_weight();
$dimensions['maxweight'] = max ($dimensions['maxweight'], $w);
$dimensions['minweight'] = min ($dimensions['minweight'], $w);
$dimensions['weight'] += $w * $product['quantity'];
}
return $dimensions;
}
protected function getOrderListProperties ($cart, $products, $method) {
$categories = array();
$skus = array();
$tags = array();
$shipping_classes = array();
foreach ($products as $product) {
$id = $product['data']->get_id();
if ($product['data']->get_sku()) {
$skus[] = $product['data']->get_sku();
}
foreach (wc_get_product_terms( $id, 'product_cat') as $c) {
$categories[] = $c->slug;
}
foreach (wc_get_product_terms( $id, 'product_tag') as $c) {
$tags[] = $c->slug;
}
$shipclass = $product['data']->get_shipping_class();
if ($shipclass) {
$shipping_classes[] = $shipclass;
}
}
$skus = array_unique($skus);
$categories = array_unique($categories);
$tags = array_unique($tags);
$shipping_classes = array_unique($shipping_classes);
$data = array (
'skus' => $skus,
'categories' => $categories,
'tags' => $tags,
'shippingclasses' => $shipping_classes,
);
// THIRD-PARTY SUPPORT
// "WC Vendors" support (vendors stored as post author)
if (class_exists("WC_Vendors")) {
$vendorids = array();
foreach ($products as $product) {
$vendorids[] = $product['data']->post->post_author;
}
$data['vendorids'] = array_unique($vendorids);
$vendors = array(); // Requires "WC Vendors" or "WooThemes Product Vendors" plugin
$vendornames = array();
foreach ($data['vendorids'] as $v) {
$vnd = get_user_by('id', $v); // Get user name by user id
if (is_object($vnd)) {
$vendornames[] = $vnd->display_name;
$vendors[] = $vnd->user_login;
}
}
$data['vendornames'] = array_unique($vendornames);
$data['vendors'] = array_unique($vendors);
}
// "WooThemes Vendor Products" support (vendors stored in its own taxonomy)
if (class_exists("WooCommerce_Product_Vendors") && function_exists("get_product_vendors")) {
$vendors = array();
$vendornames = array();
$vendorids = array();
// The plugin provides its own function to retrieve the vendor for a product
foreach ($products as $product) {
foreach (get_product_vendors($product['data']->get_id()) as $vendor) {
// $this->printWarning("<pre>vendor: ".print_r($vendor,1)."</pre>");
$vendors[] = $vendor->slug;
$vendornames[] = $vendor->title;
$vendorids[] = $vendor->ID;
}
}
$data['vendors'] = array_unique($vendors);
$data['vendornames'] = array_unique($vendornames);
$data['vendorids'] = array_unique($vendorids);
}
// "YITH WooCommerce Multi Vendor" support (vendors stored in its own taxonomy)
if (function_exists("yith_get_vendor")) {
$vendors = array();
$vendornames = array();
$vendorids = array();
// The plugin provides its own function to retrieve the vendor for a product
foreach ($products as $product) {
$vendor = yith_get_vendor($product['data']->get_id(), 'product');
// $this->printWarning("<pre>vendor: ".print_r($vendor,1)."</pre>");
if ($vendor->is_valid()) {
$vendors[] = $vendor->slug;
$vendornames[] = $vendor->name;
$vendorids[] = $vendor->term_id;
}
}
$data['vendors'] = array_unique($vendors);
$data['vendornames'] = array_unique($vendornames);
$data['vendorids'] = array_unique($vendorids);
}
// END THIRD-PARTY SUPPORT
return $data;
}
protected function getOrderAddress ($cart, $method) {
$address = $cart['destination'];
$zip = isset($address['postcode'])?trim($address['postcode']):'';
$data = array(
'zip' => $zip,
'postcode' => $zip,
'zip1' => substr($zip,0,1),
'zip2' => substr($zip,0,2),
'zip3' => substr($zip,0,3),
'zip4' => substr($zip,0,4),
'zip5' => substr($zip,0,5),
'zip6' => substr($zip,0,6),
'zipnumeric' => preg_replace('/[^0-9]/', '', $zip),
'zipalphanum' => preg_replace('/[^a-zA-Z0-9]/', '', $zip),
'city' => trim($address['city']),
'country' => trim($address['country']),
'state' => trim($address['state']),
'address1' => trim($address['address']),
'address2' => trim($address['address_2']),
);
/* Get the user from the package information and extract further information about the buyer */
$user = $cart['user'];
$data['userid'] = $user['ID'];
$data['userroles'] = array();
$data['username'] = '';
$data['first_name'] = '';
$data['last_name'] = '';
$data['email'] = '';
if ($user['ID']>0) {
$userinfo = get_userdata($user['ID']);
$data['userroles'] = $userinfo->roles;
$data['username'] = $userinfo->user_login;
$data['first_name'] = $userinfo->first_name;
$data['last_name'] = $userinfo->last_name;
$data['email'] = isset($address['email'])?$address['email']:'';
// TODO: Extract more user fields!
/**
$data['company'] = isset($address['company'])?$address['company']:'';
$data['title'] = isset($address['title'])?$address['title']:'';
$data['middle_name'] = isset($address['middle_name'])?$address['middle_name']:'';
$data['phone1'] = isset($address['phone_1'])?$address['phone_1']:'';
$data['phone2'] = isset($address['phone_2'])?$address['phone_2']:'';
$data['fax'] = isset($address['fax'])?$address['fax']:'';
*/
}
// The country check needs the countryid variable, so duplicate from country:
$data['countryid'] = $data['country'];
return $data;
}
protected function getOrderPrices ($cart, $products, /*$cart_prices, */$method) {
$data = array(
'total' => 0,
'subtotal' => 0,
'taxtotal' => 0,
'taxsubtotal' => 0,
'cost' => 0,
);
// Calculate the prices from the individual products!
// Possible problems are discounts on the order total
foreach ($products as $product) {
$data['total'] += $product['line_total'];
$data['subtotal'] += $product['line_subtotal'];
$data['taxtotal'] += $product['line_tax'];
$data['taxsubtotal'] += $product['line_subtotal_tax'];
$data['cost'] += $product['line_total'] + $product['line_tax'];
}
$data['amount'] = $data['cost'];
$data['amountwithtax'] = $data['cost'];
return $data;
}
/** Allow child classes to add additional variables for the rules or modify existing one
*/
protected function addCustomCartValues ($cart, $products, $method, &$values) {
}
protected function addPluginCartValues($cart, $products, $method, &$values) {
return apply_filters( 'opentools_shipping_by_rules_get_cart_values', array(&$values, $cart, $products, $method));
}
/** Filter the given array of products and return only those that belong to the categories, manufacturers,
* vendors or products given in the $filter_conditions. The $filter_conditions is an array of the form:
* array( 'products'=>array(....), 'categories'=>array(1,2,3,42))
* Notice that giving an empty array for any of the keys means "no restriction" and is exactly the same
* as leaving out the entry altogether
*/
public function filterProducts($products, $filter_conditions) {
$result = array();
// For the subcategories scoping we need all subcategories of the conditions:
$subcategories = array();
if (isset($filter_conditions['subcategories']) && !empty($filter_conditions['subcategories'])) {
foreach ($filter_conditions['subcategories'] as $catslug) {
// Get the term itself (we have only the slug!)
$cat = get_term_by('slug', $catslug, 'product_cat');
if (empty($cat))
continue;
$subcategories[] = $cat->slug;
// Get the list of all subcategories of the given categories
$args=array('child_of' => $cat->term_id, 'hierarchical' => 1);
foreach (get_terms( 'product_cat', $args) as $subcat) {
$subcategories[] = $subcat->slug;
}
}
$subcategories = array_unique($subcategories);
}
// Now filter out all products that do not match the conditions
foreach ($products as $p) {
$prodcategories = array();
foreach (wc_get_product_terms( $p['data']->id, 'product_cat') as $cat) {
$prodcategories[] = $cat->slug;
}
if (!empty($filter_conditions['products']) && !in_array($p['data']->get_sku(), $filter_conditions['products']))
continue;
if (!empty($filter_conditions['categories']) && count(array_intersect($filter_conditions['categories'], $prodcategories))==0)
continue;
if (!empty($filter_conditions['subcategories']) && count(array_intersect($subcategories, $prodcategories))==0)
continue;
if (!empty($filter_conditions['vendors'])) {
// Collect all vendors (ids and slug/login_name - PLUGIN-specific!)
// for the current product. If any of them is in the vendor conditions
// list, this product should not be filtered out!
$vnd_props = array();
// THIRD-PARTY SUPPORT
// "WC Vendors" support (vendors stored as post author)
if (class_exists("WC_Vendors")) {
$vendor = $p['data']->post->post_author;
$vnd = get_user_by('id', $vendor); // Get user name by user id
$vnd_props[] = $vendor;
$vnd_props[] = $vnd->user_login;
}
// "WooThemes Vendor Products" support (vendors stored in its own taxonomy)
if (class_exists("WooCommerce_Product_Vendors") && function_exists("get_product_vendors")) {
foreach (get_product_vendors($p['data']->id) as $vendor) {
$vnd_props[] = $vendor->slug;
}
}
// "YITH WooCommerce Multi Vendor" support (vendors stored in its own taxonomy)
if (function_exists("yith_get_vendor")) {
$vendor = yith_get_vendor($p['data']->id, 'product');
if ($vendor->is_valid()) {
$vnd_props[] = $vendor->slug;
}
}
// END THIRD-PARTY SUPPORT
// Check if any of the vendor properties is matched by the conditions; If not => skip product
if (count(array_intersect($vnd_props, $filter_conditions['vendors']))==0)
continue;
}
$result[] = $p;
}
return $result;
}
protected function createMethodRule ($r, $countries, $ruleinfo) {
return new ShippingRule($this, $r, $countries, $ruleinfo);
}
public function getUpgradeNagSettings() {
$settings = array();
if (!$this->isAdvanced()) {
$settings['opentools_shippingbyrules_upgrade'] = array(
'name' => $this->__( 'Upgrade to the ADVANCED VERSION of the OpenTools Shipping by Rules plugin'),
'type' => 'opentools_shippingbyrules_upgrade',
'link' => 'http://open-tools.net/woocommerce/advanced-shipping-by-rules-for-woocommerce.html',
);
}
return $settings;
}
public function printUpgradeNagBox($settings) {
include plugin_dir_path( __FILE__ ) . 'admin/html/html-upgrade-nag.php';
}
}