Added priorities for shipping methods to give more control over defaults.

Closes #7871
This commit is contained in:
Mike Jolley 2015-04-13 15:32:54 +01:00
parent 14ed7137d2
commit 9f65d2a1fc
11 changed files with 142 additions and 122 deletions

File diff suppressed because one or more lines are too long

View File

@ -1940,8 +1940,14 @@ table.wc_shipping {
td {
vertical-align: middle;
cursor: move;
padding: 7px;
line-height: 2em;
}
tr:nth-child(odd) {
td {
background: #f9f9f9;
}
}
th {
@ -1970,6 +1976,27 @@ table.wc_shipping {
margin: 0;
}
}
th.sort {
width: 28px;
padding: 0;
}
td.sort {
padding: 0 7px;
cursor: move;
text-align: center;
vertical-align: middle;
&:before {
content: "\e032";
font-family: 'WooCommerce';
text-align: center;
line-height: 1;
color: #ccc;
display: block;
width: 17px;
float: left;
height: 100%;
}
}
}
img.help_tip {

File diff suppressed because one or more lines are too long

View File

@ -60,7 +60,7 @@ jQuery(window).load(function(){
items:'tr',
cursor:'move',
axis:'y',
handle: 'td',
handle: 'td.sort',
scrollSensitivity:40,
helper:function(e,ui){
ui.children().each(function(){

View File

@ -1 +1 @@
jQuery(window).load(function(){jQuery("select#woocommerce_allowed_countries, select#woocommerce_ship_to_countries").change(function(){"specific"==jQuery(this).val()?jQuery(this).parent().parent().next("tr").show():jQuery(this).parent().parent().next("tr").hide()}).change(),jQuery(".colorpick").iris({change:function(a,b){jQuery(this).css({backgroundColor:b.color.toString()})},hide:!0,border:!0}).each(function(){jQuery(this).css({backgroundColor:jQuery(this).val()})}).click(function(){jQuery(".iris-picker").hide(),jQuery(this).closest(".color_box, td").find(".iris-picker").show()}),jQuery("body").click(function(){jQuery(".iris-picker").hide()}),jQuery(".color_box, .colorpick").click(function(a){a.stopPropagation()}),jQuery(function(){var a=!1;jQuery("input, textarea, select, checkbox").change(function(){a=!0}),jQuery(".woo-nav-tab-wrapper a").click(function(){window.onbeforeunload=a?function(){return woocommerce_settings_params.i18n_nav_warning}:""}),jQuery(".submit input").click(function(){window.onbeforeunload=""})}),jQuery("table.wc_gateways tbody, table.wc_shipping tbody").sortable({items:"tr",cursor:"move",axis:"y",handle:"td",scrollSensitivity:40,helper:function(a,b){return b.children().each(function(){jQuery(this).width(jQuery(this).width())}),b.css("left","0"),b},start:function(a,b){b.item.css("background-color","#f6f6f6")},stop:function(a,b){b.item.removeAttr("style")}}),jQuery(".woocommerce").on("click",".select_all",function(){return jQuery(this).closest("td").find("select option").attr("selected","selected"),jQuery(this).closest("td").find("select").trigger("change"),!1}),jQuery(".woocommerce").on("click",".select_none",function(){return jQuery(this).closest("td").find("select option").removeAttr("selected"),jQuery(this).closest("td").find("select").trigger("change"),!1})});
jQuery(window).load(function(){jQuery("select#woocommerce_allowed_countries, select#woocommerce_ship_to_countries").change(function(){"specific"==jQuery(this).val()?jQuery(this).parent().parent().next("tr").show():jQuery(this).parent().parent().next("tr").hide()}).change(),jQuery(".colorpick").iris({change:function(a,b){jQuery(this).css({backgroundColor:b.color.toString()})},hide:!0,border:!0}).each(function(){jQuery(this).css({backgroundColor:jQuery(this).val()})}).click(function(){jQuery(".iris-picker").hide(),jQuery(this).closest(".color_box, td").find(".iris-picker").show()}),jQuery("body").click(function(){jQuery(".iris-picker").hide()}),jQuery(".color_box, .colorpick").click(function(a){a.stopPropagation()}),jQuery(function(){var a=!1;jQuery("input, textarea, select, checkbox").change(function(){a=!0}),jQuery(".woo-nav-tab-wrapper a").click(function(){window.onbeforeunload=a?function(){return woocommerce_settings_params.i18n_nav_warning}:""}),jQuery(".submit input").click(function(){window.onbeforeunload=""})}),jQuery("table.wc_gateways tbody, table.wc_shipping tbody").sortable({items:"tr",cursor:"move",axis:"y",handle:"td.sort",scrollSensitivity:40,helper:function(a,b){return b.children().each(function(){jQuery(this).width(jQuery(this).width())}),b.css("left","0"),b},start:function(a,b){b.item.css("background-color","#f6f6f6")},stop:function(a,b){b.item.removeAttr("style")}}),jQuery(".woocommerce").on("click",".select_all",function(){return jQuery(this).closest("td").find("select option").attr("selected","selected"),jQuery(this).closest("td").find("select").trigger("change"),!1}),jQuery(".woocommerce").on("click",".select_none",function(){return jQuery(this).closest("td").find("select option").removeAttr("selected"),jQuery(this).closest("td").find("select").trigger("change"),!1})});

View File

@ -33,28 +33,28 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
public $availability;
/** @var array Array of countries this method is enabled for. */
public $countries = array();
public $countries = array();
/** @var string If 'taxable' tax will be charged for this method (if applicable) */
public $tax_status = 'taxable';
public $tax_status = 'taxable';
/** @var mixed Fees for the method */
public $fee = 0;
public $fee = 0;
/** @var float Minimum fee for the method */
public $minimum_fee = null;
public $minimum_fee = null;
/** @var bool Enabled for disabled */
public $enabled = false;
public $enabled = false;
/** @var bool Whether the method has settings or not (In WooCommerce > Settings > Shipping) */
public $has_settings = true;
public $has_settings = true;
/** @var array Features this method supports. */
public $supports = array();
public $supports = array();
/** @var array This is an array of rates - methods must populate this array to register shipping costs */
public $rates = array();
public $rates = array();
/**
* Whether or not we need to calculate tax on top of the shipping rate

View File

@ -238,11 +238,10 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
<tr>
<?php
$columns = apply_filters( 'woocommerce_payment_gateways_setting_columns', array(
'default' => __( 'Default', 'woocommerce' ),
'sort' => '',
'name' => __( 'Gateway', 'woocommerce' ),
'id' => __( 'Gateway ID', 'woocommerce' ),
'status' => __( 'Status', 'woocommerce' ),
'settings' => ''
'status' => __( 'Enabled', 'woocommerce' )
) );
foreach ( $columns as $key => $column ) {
@ -263,16 +262,15 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
switch ( $key ) {
case 'default' :
echo '<td width="1%" class="default">
<input type="radio" name="default_gateway" value="' . esc_attr( $gateway->id ) . '" ' . checked( $default_gateway, esc_attr( $gateway->id ), false ) . ' />
case 'sort' :
echo '<td width="1%" class="sort">
<input type="hidden" name="gateway_order[]" value="' . esc_attr( $gateway->id ) . '" />
</td>';
break;
case 'name' :
echo '<td class="name">
' . $gateway->get_title() . '
<a href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( get_class( $gateway ) ) ) . '">' . $gateway->get_title() . '</a>
</td>';
break;
@ -286,19 +284,13 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
echo '<td class="status">';
if ( $gateway->enabled == 'yes' )
echo '<span class="status-enabled tips" data-tip="' . __ ( 'Enabled', 'woocommerce' ) . '">' . __ ( 'Enabled', 'woocommerce' ) . '</span>';
echo '<span class="status-enabled tips" data-tip="' . __ ( 'Yes', 'woocommerce' ) . '">' . __ ( 'Yes', 'woocommerce' ) . '</span>';
else
echo '-';
echo '</td>';
break;
case 'settings' :
echo '<td class="settings">
<a class="button" href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( get_class( $gateway ) ) ) . '">' . __( 'Settings', 'woocommerce' ) . '</a>
</td>';
break;
default :
do_action( 'woocommerce_payment_gateways_setting_column_' . $key, $gateway );
break;

View File

@ -191,63 +191,52 @@ class WC_Settings_Shipping extends WC_Settings_Page {
* Output shipping method settings.
*/
public function shipping_methods_setting() {
$default_shipping_method = esc_attr( get_option('woocommerce_default_shipping_method') );
$selection_priority = get_option( 'woocommerce_shipping_method_selection_priority', array() );
?>
<tr valign="top">
<th scope="row" class="titledesc"><?php _e( 'Shipping Methods', 'woocommerce' ) ?></th>
<td class="forminp">
<table class="wc_shipping widefat" cellspacing="0">
<table class="wc_shipping widefat wp-list-table" cellspacing="0">
<thead>
<tr>
<th class="default"><?php _e( 'Default', 'woocommerce' ); ?></th>
<th class="sort">&nbsp;</th>
<th class="name"><?php _e( 'Name', 'woocommerce' ); ?></th>
<th class="id"><?php _e( 'ID', 'woocommerce' ); ?></th>
<th class="status"><?php _e( 'Status', 'woocommerce' ); ?></th>
<th class="settings">&nbsp;</th>
<th class="status"><?php _e( 'Enabled', 'woocommerce' ); ?></th>
<th class="priority"><?php _e( 'Selection Priority', 'woocommerce' ); ?> <span class="tips" data-tip="<?php echo esc_attr( __( 'Available methods will be chosen by default in this order. If multiple methods have the same priority, they will be sorted by cost.', 'woocommerce' ) ); ?>">[?]</span></th>
</tr>
</thead>
<tbody>
<?php
foreach ( WC()->shipping->load_shipping_methods() as $key => $method ) {
echo '<tr>
<td width="1%" class="default">
<input type="radio" name="default_shipping_method" value="' . esc_attr( $method->id ) . '" ' . checked( $default_shipping_method, $method->id, false ) . ' />
<input type="hidden" name="method_order[]" value="' . esc_attr( $method->id ) . '" />
<?php foreach ( WC()->shipping->load_shipping_methods() as $key => $method ) : ?>
<tr>
<td width="1%" class="sort">
<input type="hidden" name="method_order[<?php echo esc_attr( $method->id ); ?>]" value="<?php echo esc_attr( $method->id ); ?>" />
</td>
<td class="name">
' . $method->get_title() . '
<?php if ( $method->has_settings ) : ?><a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping&section=' . strtolower( get_class( $method ) ) ) ); ?>"><?php endif; ?>
<?php echo esc_html( $method->get_title() ); ?>
<?php if ( $method->has_settings ) : ?></a><?php endif; ?>
</td>
<td class="id">
' . $method->id . '
<?php echo esc_attr( $method->id ); ?>
</td>
<td class="status">';
if ( $method->enabled == 'yes' ) {
echo '<span class="status-enabled tips" data-tip="' . __ ( 'Enabled', 'woocommerce' ) . '">' . __ ( 'Enabled', 'woocommerce' ) . '</span>';
} else {
echo '-';
}
echo '</td>
<td class="settings">';
if ( $method->has_settings ) {
echo '<a class="button" href="' . admin_url( 'admin.php?page=wc-settings&tab=shipping&section=' . strtolower( get_class( $method ) ) ) . '">' . __( 'Settings', 'woocommerce' ) . '</a>';
}
echo '</td>
</tr>';
}
?>
<td class="status">
<?php if ( 'yes' === $method->enabled ) : ?>
<span class="status-enabled tips" data-tip="<?php _e( 'Yes', 'woocommerce' ); ?>"><?php _e( 'Yes', 'woocommerce' ); ?></span>
<?php else : ?>
<span class="na">-</span>
<?php endif; ?>
</td>
<td width="1%" class="priority">
<input type="number" step="1" min="0" name="method_priority[<?php echo esc_attr( $method->id ); ?>]" value="<?php echo isset( $selection_priority[ $method->id ] ) ? absint( $selection_priority[ $method->id ] ) : 1; ?>" />
</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<th width="1%" class="default">
<input type="radio" name="default_shipping_method" value="" <?php checked( $default_shipping_method, '' ); ?> />
</th>
<th><?php _e( 'Automatic', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e( 'The cheapest available shipping method will be selected by default.', 'woocommerce' ); ?>">[?]</a></th>
<th colspan="3"><span class="description"><?php _e( 'Drag and drop the above shipping methods to control their display order.', 'woocommerce' ); ?></span></th>
<th>&nbsp;</th>
<th colspan="4"><span class="description"><?php _e( 'Drag and drop the above shipping methods to control their display order.', 'woocommerce' ); ?></span></th>
</tr>
</tfoot>
</table>

View File

@ -309,7 +309,7 @@ class WC_Customer {
$tax_based_on = get_option( 'woocommerce_tax_based_on' );
// Check shipping method at this point to see if we need special handling
if ( true == apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && WC()->cart->needs_shipping() && sizeof( array_intersect( WC()->session->get( 'chosen_shipping_methods', array( get_option( 'woocommerce_default_shipping_method' ) ) ), apply_filters( 'woocommerce_local_pickup_methods', array( 'local_pickup' ) ) ) ) > 0 ) {
if ( true == apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && WC()->cart->needs_shipping() && sizeof( array_intersect( WC()->session->get( 'chosen_shipping_methods', array() ), apply_filters( 'woocommerce_local_pickup_methods', array( 'local_pickup' ) ) ) ) > 0 ) {
$tax_based_on = 'base';
}

View File

@ -122,8 +122,9 @@ class WC_Shipping {
'WC_Shipping_Local_Pickup'
) );
foreach ( $shipping_methods_to_load as $method )
foreach ( $shipping_methods_to_load as $method ) {
$this->register_shipping_method( $method );
}
$this->sort_shipping_methods();
@ -138,9 +139,9 @@ class WC_Shipping {
* @return void
*/
public function register_shipping_method( $method ) {
if ( ! is_object( $method ) )
if ( ! is_object( $method ) ) {
$method = new $method();
}
$id = empty( $method->instance_id ) ? $method->id : $method->instance_id;
@ -219,18 +220,59 @@ class WC_Shipping {
* @return array
*/
public function get_shipping_classes() {
if ( empty( $this->shipping_classes ) )
if ( empty( $this->shipping_classes ) ) {
$this->shipping_classes = ( $classes = get_terms( 'product_shipping_class', array( 'hide_empty' => '0' ) ) ) ? $classes : array();
}
return $this->shipping_classes;
}
/**
* Get the default method
* @param array $available_methods
* @param boolean $current_chosen_method
* @return string
*/
private function get_default_method( $available_methods, $current_chosen_method = false ) {
$selection_priority = get_option( 'woocommerce_shipping_method_selection_priority', array() );
if ( ! empty( $available_methods ) ) {
// Is a method already chosen?
if ( ! empty( $current_chosen_method ) && ! isset( $available_methods[ $current_chosen_method ] ) ) {
foreach ( $available_methods as $method_id => $method ) {
if ( strpos( $method->id, $current_chosen_method ) === 0 ) {
return $method->id;
}
}
}
// Order by priorities and costs
$prioritized_methods = array();
foreach ( $available_methods as $method_id => $method ) {
$priority = isset( $selection_priority[ $method_id ] ) ? absint( $selection_priority[ $method_id ] ) : 1;
if ( empty( $prioritized_methods[ $priority ] ) ) {
$prioritized_methods[ $priority ] = array();
}
$prioritized_methods[ $priority ][ $method_id ] = $method->cost;
}
ksort( $prioritized_methods );
$prioritized_methods = current( $prioritized_methods );
asort( $prioritized_methods );
return current( array_keys( $prioritized_methods ) );
}
return false;
}
/**
* calculate_shipping function.
*
* Calculate shipping for (multiple) packages of cart items.
*
* @access public
* @param array $packages multi-dimensional array of cart items to calc shipping for
*/
public function calculate_shipping( $packages = array() ) {
@ -238,9 +280,9 @@ class WC_Shipping {
return;
}
$this->shipping_total = null;
$this->shipping_taxes = array();
$this->packages = array();
$this->shipping_total = null;
$this->shipping_taxes = array();
$this->packages = array();
// Calculate costs for passed packages
$package_keys = array_keys( $packages );
@ -271,47 +313,21 @@ class WC_Shipping {
}
// Get available methods for package
$_available_methods = $package['rates'];
$available_methods = $package['rates'];
if ( sizeof( $_available_methods ) > 0 ) {
if ( sizeof( $available_methods ) > 0 ) {
// If not set, not available, or available methods have changed, set to the default option
if ( empty( $chosen_method ) || ! isset( $_available_methods[ $chosen_method ] ) || $method_count != sizeof( $_available_methods ) ) {
$chosen_method = apply_filters( 'woocommerce_shipping_chosen_method', get_option( 'woocommerce_default_shipping_method' ), $_available_methods );
// Loops methods and find a match
if ( ! empty( $chosen_method ) && ! isset( $_available_methods[ $chosen_method ] ) ) {
foreach ( $_available_methods as $method_id => $method ) {
if ( strpos( $method->id, $chosen_method ) === 0 ) {
$chosen_method = $method->id;
break;
}
}
}
if ( empty( $chosen_method ) || ! isset( $_available_methods[ $chosen_method ] ) ) {
// Default to cheapest
foreach ( $_available_methods as $method_id => $method ) {
if ( $method->cost < $_cheapest_cost || ! is_numeric( $_cheapest_cost ) ) {
$_cheapest_cost = $method->cost;
$_cheapest_method = $method_id;
}
}
$chosen_method = $_cheapest_method;
}
// Store chosen method
// If not set, not available, or available methods have changed, set to the DEFAULT option
if ( empty( $chosen_method ) || ! isset( $available_methods[ $chosen_method ] ) || $method_count != sizeof( $available_methods ) ) {
$chosen_method = apply_filters( 'woocommerce_shipping_chosen_method', $this->get_default_method( $available_methods, $chosen_method ), $available_methods );
$chosen_methods[ $i ] = $chosen_method;
$method_counts[ $i ] = sizeof( $_available_methods );
// Do action for this chosen method
$method_counts[ $i ] = sizeof( $available_methods );
do_action( 'woocommerce_shipping_method_chosen', $chosen_method );
}
// Store total costs
if ( $chosen_method ) {
$rate = $_available_methods[ $chosen_method ];
$rate = $available_methods[ $chosen_method ];
// Merge cost and taxes - label and ID will be the same
$this->shipping_total += $rate->cost;
@ -391,7 +407,6 @@ class WC_Shipping {
return $this->packages;
}
/**
* reset_shipping function.
*
@ -407,31 +422,27 @@ class WC_Shipping {
$this->packages = array();
}
/**
* process_admin_options function.
*
* Saves options on the shipping setting page.
*
* @access public
* @return void
*/
public function process_admin_options() {
$default_shipping_method = ( isset( $_POST['default_shipping_method'] ) ) ? esc_attr( $_POST['default_shipping_method'] ) : '';
$method_order = ( isset( $_POST['method_order'] ) ) ? $_POST['method_order'] : '';
$order = array();
$method_order = isset( $_POST['method_order'] ) ? $_POST['method_order'] : '';
$method_priority = isset( $_POST['method_priority'] ) ? $_POST['method_priority'] : '';
$order = array();
$selection_priority = array();
if ( is_array( $method_order ) && sizeof( $method_order ) > 0 ) {
$loop = 0;
foreach ($method_order as $method_id) {
$order[$method_id] = $loop;
$loop++;
foreach ( $method_order as $method_id ) {
$order[ $method_id ] = $loop;
$selection_priority[ $method_id ] = absint( $method_priority[ $method_id ] );
$loop ++;
}
}
update_option( 'woocommerce_default_shipping_method', $default_shipping_method );
update_option( 'woocommerce_shipping_method_selection_priority', $selection_priority );
update_option( 'woocommerce_shipping_method_order', $order );
}
@ -446,5 +457,5 @@ class WC_Shipping {
* @since 1.5.7
*/
function woocommerce_register_shipping_method( $shipping_method ) {
$GLOBALS['woocommerce']->shipping->register_shipping_method( $shipping_method );
WC()->shipping->register_shipping_method( $shipping_method );
}

View File

@ -139,6 +139,7 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
== Changelog ==
* Feature - Show full category hierarchy in permalinks.
* Feature - Added priorities for shipping methods to give more control over defaults.
* Fix - Ensure coupon taxes are reset when calculating totals.
* Fix - Improve discount amount rounding.
* Tweak - Improve save_attributes ajax function to correctly save text attributes.