Big changeover to JS templating for the table.

Switching over to building the table with JS — wp.template.

We are now using the same JS template for existing rows and newly
generated rows on the fly — this should simplify things moving forward.

I’ve also started building stuff in an external JS file rather than
straight on the page.  Will continue migrating things to it and
localizing as needed.

Saved ( 2 * displayed tax rates - 1 ) db queries per page load by doing
the locations all in one query and then parceling them out in php.

More coming.
This commit is contained in:
George Stephanis 2015-08-07 11:04:55 -04:00
parent f0656e7e38
commit 729e6c924c
2 changed files with 110 additions and 154 deletions

View File

@ -0,0 +1,15 @@
/**
* Used by woocommerce/includes/admin/settings/views/html-settings-tax.php
*/
(function($, data, wp){
var rowTemplate = wp.template( 'tax-table-row' ),
$ratesTbody = $('#rates');
$(function() {
$ratesTbody.innerHTML = '';
$.each( data.rates, function ( id, rowData ) {
$ratesTbody.append( rowTemplate( rowData ) );
} );
});
})(jQuery, htmlSettingsTaxLocalizeScript, wp);

View File

@ -2,155 +2,71 @@
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $wpdb;
// Get all the rates and locations. Snagging all at once should significantly cut down on the number of queries.
$rates = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rates` WHERE `tax_rate_class` = %s ORDER BY `tax_rate_order`;", sanitize_title( $current_class ) ) );
$locations = $wpdb->get_results( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rate_locations`" );
// Set the rates keys equal to their ids.
$rates = array_combine( wp_list_pluck( $rates, 'tax_rate_id' ), $rates );
// Drop the locations into the rates array.
foreach ( $locations as $location ) {
if ( ! isset( $rates[ $location->tax_rate_id ]->{$location->location_type} ) ) {
$rates[ $location->tax_rate_id ]->{$location->location_type} = array();
}
$rates[ $location->tax_rate_id ]->{$location->location_type}[] = $location->location_code;
}
// Localize and enqueue our js.
wp_register_script( 'htmlSettingsTaxLocalizeScript', WC()->plugin_url() . '/assets/js/admin/settings_views_html-settings-tax.js', array( 'jquery', 'wp-util' ), WC_VERSION );
wp_localize_script( 'htmlSettingsTaxLocalizeScript', 'htmlSettingsTaxLocalizeScript', array(
'current_class' => $current_class,
'rates' => $rates,
'page' => $page,
'limit' => $limit,
'strings' => array(
),
) );
wp_enqueue_script( 'htmlSettingsTaxLocalizeScript' );
?>
<h3><?php printf( __( 'Tax Rates for the "%s" Class', 'woocommerce' ), $current_class ? esc_html( $current_class ) : __( 'Standard', 'woocommerce' ) ); ?></h3>
<p><?php printf( __( 'Define tax rates for countries and states below. <a href="%s">See here</a> for available alpha-2 country codes.', 'woocommerce' ), 'http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes' ); ?></p>
<input type="search" class="tax-search" placeholder="<?php esc_attr_e( 'Search…', 'woocommerce' ); ?>" />
<p class="num-results-found"></p>
<script>
(function($){
function processTaxRateSearch() {
var searchText = this.value.toLowerCase(),
$table = $('table.wc_tax_rates'),
$rows = $table.find('tbody tr' ),
results = 0;
if ( 0 === searchText.length ) {
$rows.removeClass('search-result-match');
$('.num-results-found' ).text('');
return;
}
$rows.each(function(){
var rowText = $(this).find(':input').map( function(){ return this.value; } ).get().join(' ');
if ( -1 !== rowText.toLowerCase().indexOf( searchText.toLowerCase() ) ) {
$(this).toggleClass( 'search-result-match', true );
results++;
} else {
$(this).toggleClass( 'search-result-match', false );
}
});
$('.num-results-found').text( ('<?php echo esc_js( __( '%d results found.', 'woocommerce' ) ); ?>').replace( '%d', results ) );
}
$('.tax-search' ).on( 'keyup search', processTaxRateSearch );
})(jQuery);
</script>
<style>
tr.search-result-match input {
background-color: yellow !important;
}
</style>
<table class="wc_tax_rates wc_input_table sortable widefat">
<thead>
<tr>
<th class="sort">&nbsp;</th>
<th width="8%"><?php _e( 'Country&nbsp;Code', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('A 2 digit country code, e.g. US. Leave blank to apply to all.', 'woocommerce'); ?>">[?]</span></th>
<th width="8%"><?php _e( 'State&nbsp;Code', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('A 2 digit state code, e.g. AL. Leave blank to apply to all.', 'woocommerce'); ?>">[?]</span></th>
<th><?php _e( 'ZIP/Postcode', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('Postcode for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all areas. Wildcards (*) can be used. Ranges for numeric postcodes (e.g. 12345-12350) will be expanded into individual postcodes.', 'woocommerce'); ?>">[?]</span></th>
<th><?php _e( 'City', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('Cities for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all cities.', 'woocommerce'); ?>">[?]</span></th>
<th width="8%"><?php _e( 'Rate&nbsp;%', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e( 'Enter a tax rate (percentage) to 4 decimal places.', 'woocommerce' ); ?>">[?]</span></th>
<th width="8%"><?php _e( 'Tax&nbsp;Name', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('Enter a name for this tax rate.', 'woocommerce'); ?>">[?]</span></th>
<th width="8%"><?php _e( 'Priority', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('Choose a priority for this tax rate. Only 1 matching rate per priority will be used. To define multiple tax rates for a single area you need to specify a different priority per rate.', 'woocommerce'); ?>">[?]</span></th>
<th width="8%"><?php _e( 'Compound', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('Choose whether or not this is a compound rate. Compound tax rates are applied on top of other tax rates.', 'woocommerce'); ?>">[?]</span></th>
<th width="8%"><?php _e( 'Shipping', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php esc_attr_e('Choose whether or not this tax rate also gets applied to shipping.', 'woocommerce'); ?>">[?]</span></th>
</tr>
</thead>
<tbody id="rates">
<?php
$rates = $wpdb->get_results( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates
WHERE tax_rate_class = %s
ORDER BY tax_rate_order
LIMIT %d, %d
" ,
sanitize_title( $current_class ),
( $page - 1 ) * $limit,
$limit
) );
foreach ( $rates as $rate ) {
?>
<tr class="tips" data-tip="<?php echo __( 'Tax rate ID', 'woocommerce' ) . ': ' . $rate->tax_rate_id; ?>">
<td class="sort"><input type="hidden" class="remove_tax_rate" name="remove_tax_rate[<?php echo $rate->tax_rate_id ?>]" value="0" /></td>
<td class="country" width="8%">
<input type="text" value="<?php echo esc_attr( $rate->tax_rate_country ) ?>" placeholder="*" name="tax_rate_country[<?php echo $rate->tax_rate_id ?>]" class="wc_input_country_iso" />
</td>
<td class="state" width="8%">
<input type="text" value="<?php echo esc_attr( $rate->tax_rate_state ) ?>" placeholder="*" name="tax_rate_state[<?php echo $rate->tax_rate_id ?>]" />
</td>
<td class="postcode">
<input type="text" value="<?php
$locations = $wpdb->get_col( $wpdb->prepare( "SELECT location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE location_type='postcode' AND tax_rate_id = %d ORDER BY location_code", $rate->tax_rate_id ) );
echo esc_attr( implode( '; ', $locations ) );
?>" placeholder="*" data-name="tax_rate_postcode[<?php echo $rate->tax_rate_id ?>]" />
</td>
<td class="city">
<input type="text" value="<?php
$locations = $wpdb->get_col( $wpdb->prepare( "SELECT location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE location_type='city' AND tax_rate_id = %d ORDER BY location_code", $rate->tax_rate_id ) );
echo esc_attr( implode( '; ', $locations ) );
?>" placeholder="*" data-name="tax_rate_city[<?php echo $rate->tax_rate_id ?>]" />
</td>
<td class="rate" width="8%">
<input type="number" step="any" min="0" value="<?php echo esc_attr( $rate->tax_rate ) ?>" placeholder="0" name="tax_rate[<?php echo $rate->tax_rate_id ?>]" />
</td>
<td class="name" width="8%">
<input type="text" value="<?php echo esc_attr( $rate->tax_rate_name ) ?>" name="tax_rate_name[<?php echo $rate->tax_rate_id ?>]" />
</td>
<td class="priority" width="8%">
<input type="number" step="1" min="1" value="<?php echo esc_attr( $rate->tax_rate_priority ) ?>" name="tax_rate_priority[<?php echo $rate->tax_rate_id ?>]" />
</td>
<td class="compound" width="8%">
<input type="checkbox" class="checkbox" name="tax_rate_compound[<?php echo $rate->tax_rate_id ?>]" <?php checked( $rate->tax_rate_compound, '1' ); ?> />
</td>
<td class="apply_to_shipping" width="8%">
<input type="checkbox" class="checkbox" name="tax_rate_shipping[<?php echo $rate->tax_rate_id ?>]" <?php checked($rate->tax_rate_shipping, '1' ); ?> />
</td>
</tr>
<?php
}
?>
</tbody>
<tfoot>
<tr>
<th colspan="10">
<a href="#" class="button plus insert"><?php _e( 'Insert row', 'woocommerce' ); ?></a>
<a href="#" class="button minus remove_tax_rates"><?php _e( 'Remove selected row(s)', 'woocommerce' ); ?></a>
<div class="pagination">
<?php
echo str_replace( 'page-numbers', 'page-numbers button', paginate_links( array(
'base' => esc_url_raw( add_query_arg( 'p', '%#%', remove_query_arg( 'p' ) ) ),
'format' => '',
'add_args' => '',
'type' => 'plain',
'prev_text' => '&laquo;',
'next_text' => '&raquo;',
'current' => $page,
'total' => ceil( absint( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(tax_rate_id) FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_class = %s;", sanitize_title( $current_class ) ) ) ) / $limit )
) ) );
echo str_replace( 'page-numbers', 'page-numbers button', paginate_links( array(
'base' => esc_url_raw( add_query_arg( 'p', '%#%', remove_query_arg( 'p' ) ) ),
'format' => '',
'add_args' => '',
'type' => 'plain',
'prev_text' => '&laquo;',
'next_text' => '&raquo;',
'current' => $page,
'total' => ceil( absint( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(tax_rate_id) FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_class = %s;", sanitize_title( $current_class ) ) ) ) / $limit )
) ) );
?>
</div>
@ -159,7 +75,56 @@ if ( ! defined( 'ABSPATH' ) ) {
</th>
</tr>
</tfoot>
<tbody id="rates">
</tbody>
</table>
<script type="text/html" id="tmpl-tax-table-row">
<tr class="tips" data-tip="<?php echo esc_attr( sprintf( __( 'Tax rate ID: %s', 'woocommerce' ), '{{ data.tax_rate_id }}' ) ); ?>">
<td class="sort">
<# if ( ! data.new ) { #>
<input type="hidden" class="remove_tax_rate" name="remove_tax_rate[{{ data.tax_rate_id }}]" value="0" />
<# } #>
</td>
<td class="country">
<input type="text" value="{{ data.tax_rate_country }}" placeholder="*" name="tax_rate_country[{{ data.tax_rate_id }}]" class="wc_input_country_iso" />
</td>
<td class="state">
<input type="text" value="{{ data.tax_rate_state }}" placeholder="*" name="tax_rate_state[{{ data.tax_rate_id }}]" />
</td>
<td class="postcode">
<input type="text" value="<# if ( data.postcode ) print( data.postcode.join( '; ' ) ); #>" placeholder="*" data-name="tax_rate_postcode[{{ data.tax_rate_id }}]" />
</td>
<td class="city">
<input type="text" value="<# if ( data.city ) print( data.city.join( '; ' ) ); #>" placeholder="*" data-name="tax_rate_city[{{ data.tax_rate_id }}]" />
</td>
<td class="rate">
<input type="number" step="any" min="0" value="{{ data.tax_rate }}" placeholder="0" name="tax_rate[{{ data.tax_rate_id }}]" />
</td>
<td class="name">
<input type="text" value="{{ data.tax_rate_name }}" name="tax_rate_name[{{ data.tax_rate_id }}]" />
</td>
<td class="priority">
<input type="number" step="1" min="1" value="{{ data.tax_rate_priority }}" name="tax_rate_priority[{{ data.tax_rate_id }}]" />
</td>
<td class="compound">
<input type="checkbox" class="checkbox" name="tax_rate_compound[{{ data.tax_rate_id }}]" <# if ( 1 === data.tax_rate_compound ) { #> checked="checked" <# } #> />
</td>
<td class="apply_to_shipping">
<input type="checkbox" class="checkbox" name="tax_rate_shipping[{{ data.tax_rate_id }}]" <# if ( 1 === data.tax_rate_shipping ) { #> checked="checked" <# } #> />
</td>
</tr>
</script>
<script type="text/javascript">
jQuery( function() {
jQuery('.wc_tax_rates .remove_tax_rates').click(function() {
@ -231,36 +196,12 @@ if ( ! defined( 'ABSPATH' ) ) {
jQuery('.wc_tax_rates .insert').click(function() {
var $tbody = jQuery('.wc_tax_rates').find('tbody');
var size = $tbody.find('tr').size();
var code = '<tr class="new">\
<td class="sort"></td>\
<td class="country" width="8%">\
<input type="text" placeholder="*" name="tax_rate_country[new-' + size + ']" class="wc_input_country_iso" />\
</td>\
<td class="state" width="8%">\
<input type="text" placeholder="*" name="tax_rate_state[new-' + size + ']" />\
</td>\
<td class="postcode">\
<input type="text" placeholder="*" name="tax_rate_postcode[new-' + size + ']" />\
</td>\
<td class="city">\
<input type="text" placeholder="*" name="tax_rate_city[new-' + size + ']" />\
</td>\
<td class="rate" width="8%">\
<input type="number" step="any" min="0" placeholder="0" name="tax_rate[new-' + size + ']" />\
</td>\
<td class="name" width="8%">\
<input type="text" name="tax_rate_name[new-' + size + ']" />\
</td>\
<td class="priority" width="8%">\
<input type="number" step="1" min="1" value="1" name="tax_rate_priority[new-' + size + ']" />\
</td>\
<td class="compound" width="8%">\
<input type="checkbox" class="checkbox" name="tax_rate_compound[new-' + size + ']" />\
</td>\
<td class="apply_to_shipping" width="8%">\
<input type="checkbox" class="checkbox" name="tax_rate_shipping[new-' + size + ']" checked="checked" />\
</td>\
</tr>';
var code = wp.template( 'tax-table-row' )( {
tax_rate_id : 'new-' + size,
tax_rate_priority : 1,
tax_rate_shipping : 1,
new : true
} );
if ( $tbody.find('tr.current').size() > 0 ) {
$tbody.find('tr.current').after( code );