Merge branch 'master' of github.com:woothemes/woocommerce

This commit is contained in:
Nicola Mustone 2015-05-27 16:09:56 +02:00
commit 4a6df7d7e1
9 changed files with 183 additions and 95 deletions

View File

@ -2,11 +2,11 @@
/**
* Handles taxonomies in admin
*
* @class WC_Admin_Taxonomies
* @version 2.1.0
* @package WooCommerce/Admin
* @category Class
* @author WooThemes
* @class WC_Admin_Taxonomies
* @version 2.3.10
* @package WooCommerce/Admin
* @category Class
* @author WooThemes
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -58,7 +58,7 @@ class WC_Admin_Taxonomies {
* @param mixed $taxonomy
*/
public function create_term( $term_id, $tt_id = '', $taxonomy = '' ) {
if ( $taxonomy != 'product_cat' && ! taxonomy_is_product_attribute( $taxonomy ) ) {
if ( 'product_cat' != $taxonomy && ! taxonomy_is_product_attribute( $taxonomy ) ) {
return;
}
@ -98,8 +98,8 @@ class WC_Admin_Taxonomies {
</div>
<div class="form-field">
<label><?php _e( 'Thumbnail', 'woocommerce' ); ?></label>
<div id="product_cat_thumbnail" style="float:left;margin-right:10px;"><img src="<?php echo wc_placeholder_img_src(); ?>" width="60px" height="60px" /></div>
<div style="line-height:60px;">
<div id="product_cat_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( wc_placeholder_img_src() ); ?>" width="60px" height="60px" /></div>
<div style="line-height: 60px;">
<input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" />
<button type="button" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="button" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button>
@ -107,8 +107,8 @@ class WC_Admin_Taxonomies {
<script type="text/javascript">
// Only show the "remove image" button when needed
if ( ! jQuery('#product_cat_thumbnail_id').val() ) {
jQuery('.remove_image_button').hide();
if ( ! jQuery( '#product_cat_thumbnail_id' ).val() ) {
jQuery( '.remove_image_button' ).hide();
}
// Uploading files
@ -126,30 +126,30 @@ class WC_Admin_Taxonomies {
// Create the media frame.
file_frame = wp.media.frames.downloadable_file = wp.media({
title: '<?php _e( 'Choose an image', 'woocommerce' ); ?>',
title: '<?php _e( "Choose an image", "woocommerce" ); ?>',
button: {
text: '<?php _e( 'Use image', 'woocommerce' ); ?>',
text: '<?php _e( "Use image", "woocommerce" ); ?>'
},
multiple: false
});
// When an image is selected, run a callback.
file_frame.on( 'select', function() {
attachment = file_frame.state().get('selection').first().toJSON();
var attachment = file_frame.state().get( 'selection' ).first().toJSON();
jQuery('#product_cat_thumbnail_id').val( attachment.id );
jQuery('#product_cat_thumbnail img').attr('src', attachment.sizes.thumbnail.url );
jQuery('.remove_image_button').show();
jQuery( '#product_cat_thumbnail_id' ).val( attachment.id );
jQuery( '#product_cat_thumbnail img' ).attr( 'src', attachment.sizes.thumbnail.url );
jQuery( '.remove_image_button' ).show();
});
// Finally, open the modal.
file_frame.open();
});
jQuery( document ).on( 'click', '.remove_image_button', function( event ) {
jQuery('#product_cat_thumbnail img').attr('src', '<?php echo wc_placeholder_img_src(); ?>');
jQuery('#product_cat_thumbnail_id').val('');
jQuery('.remove_image_button').hide();
jQuery( document ).on( 'click', '.remove_image_button', function() {
jQuery( '#product_cat_thumbnail img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' );
jQuery( '#product_cat_thumbnail_id' ).val( '' );
jQuery( '.remove_image_button' ).hide();
return false;
});
@ -189,14 +189,19 @@ class WC_Admin_Taxonomies {
<tr class="form-field">
<th scope="row" valign="top"><label><?php _e( 'Thumbnail', 'woocommerce' ); ?></label></th>
<td>
<div id="product_cat_thumbnail" style="float:left;margin-right:10px;"><img src="<?php echo $image; ?>" width="60px" height="60px" /></div>
<div style="line-height:60px;">
<div id="product_cat_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( $image ); ?>" width="60px" height="60px" /></div>
<div style="line-height: 60px;">
<input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" value="<?php echo $thumbnail_id; ?>" />
<button type="submit" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="submit" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button>
<button type="button" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="button" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button>
</div>
<script type="text/javascript">
// Only show the "remove image" button when needed
if ( '0' === jQuery( '#product_cat_thumbnail_id' ).val() ) {
jQuery( '.remove_image_button' ).hide();
}
// Uploading files
var file_frame;
@ -212,30 +217,30 @@ class WC_Admin_Taxonomies {
// Create the media frame.
file_frame = wp.media.frames.downloadable_file = wp.media({
title: '<?php _e( 'Choose an image', 'woocommerce' ); ?>',
title: '<?php _e( "Choose an image", "woocommerce" ); ?>',
button: {
text: '<?php _e( 'Use image', 'woocommerce' ); ?>',
text: '<?php _e( "Use image", "woocommerce" ); ?>'
},
multiple: false
});
// When an image is selected, run a callback.
file_frame.on( 'select', function() {
attachment = file_frame.state().get('selection').first().toJSON();
var attachment = file_frame.state().get( 'selection' ).first().toJSON();
jQuery('#product_cat_thumbnail_id').val( attachment.id );
jQuery('#product_cat_thumbnail img').attr('src', attachment.sizes.thumbnail.url );
jQuery('.remove_image_button').show();
jQuery( '#product_cat_thumbnail_id' ).val( attachment.id );
jQuery( '#product_cat_thumbnail img' ).attr( 'src', attachment.sizes.thumbnail.url );
jQuery( '.remove_image_button' ).show();
});
// Finally, open the modal.
file_frame.open();
});
jQuery( document ).on( 'click', '.remove_image_button', function( event ) {
jQuery('#product_cat_thumbnail img').attr('src', '<?php echo wc_placeholder_img_src(); ?>');
jQuery('#product_cat_thumbnail_id').val('');
jQuery('.remove_image_button').hide();
jQuery( document ).on( 'click', '.remove_image_button', function() {
jQuery( '#product_cat_thumbnail img' ).attr( 'src', '<?php echo esc_js( wc_placeholder_img_src() ); ?>' );
jQuery( '#product_cat_thumbnail_id' ).val( '' );
jQuery( '.remove_image_button' ).hide();
return false;
});

View File

@ -29,12 +29,12 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr>
<td data-export-label="Home URL"><?php _e( 'Home URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo '<a href="#" class="help_tip" data-tip="' . esc_attr__( 'The URL of your site\'s homepage.', 'woocommerce' ) . '">[?]</a>'; ?></td>
<td><?php echo home_url(); ?></td>
<td><?php form_option( 'home' ); ?></td>
</tr>
<tr>
<td data-export-label="Site URL"><?php _e( 'Site URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo '<a href="#" class="help_tip" data-tip="' . esc_attr__( 'The root URL of your site.', 'woocommerce' ) . '">[?]</a>'; ?></td>
<td><?php echo site_url(); ?></td>
<td><?php form_option( 'siteurl' ); ?></td>
</tr>
<tr>
<td data-export-label="WC Version"><?php _e( 'WC Version', 'woocommerce' ); ?>:</td>

View File

@ -2045,6 +2045,8 @@ class WC_AJAX {
if ( $refund_id && 'shop_order_refund' === get_post_type( $refund_id ) ) {
wc_delete_shop_order_transients( wp_get_post_parent_id( $refund_id ) );
wp_delete_post( $refund_id );
do_action( 'woocommerce_refund_deleted', $refund_id );
}
die();

View File

@ -64,33 +64,7 @@ class WC_Cache_Helper {
private static function delete_version_transients( $version ) {
if ( ! wp_using_ext_object_cache() ) {
global $wpdb;
$wpdb->query( $wpdb->prepare( "
DELETE a, b
FROM {$wpdb->options} a, {$wpdb->options} b
WHERE
( a.option_name LIKE %s OR a.option_name LIKE %s ) AND
a.option_name NOT LIKE '\_transient\_timeout\_%%' AND
a.option_name NOT LIKE '\_site\_transient\_timeout\_%%' AND
(
b.option_name = CONCAT(
'_transient_timeout_',
SUBSTRING(
a.option_name,
CHAR_LENGTH('_transient_') + 1
)
) OR
b.option_name = CONCAT(
'_site_transient_timeout_',
SUBSTRING(
a.option_name,
CHAR_LENGTH('_site_transient_') + 1
)
)
)
",
"\_transient\_%" . $version,
"\_site\_transient\_%" . $version
) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s;", "\_transient\_%" . $version ) );
}
}

View File

@ -350,7 +350,7 @@ class WC_Coupon {
* Ensure coupon amount is valid or throw exception
*/
private function validate_maximum_amount() {
if ( $this->maximum_amount > 0 && wc_format_decimal( $this->minimum_amount ) < wc_format_decimal( WC()->cart->subtotal ) ) {
if ( $this->maximum_amount > 0 && wc_format_decimal( $this->maximum_amount ) < wc_format_decimal( WC()->cart->subtotal ) ) {
throw new Exception( self::E_WC_COUPON_MAX_SPEND_LIMIT_MET );
}
}

View File

@ -1395,6 +1395,60 @@ class WC_Geo_IP {
return $this->_common_get_record( $seek_country );
}
function _geoip_seek_country_v6( $ipnum ) {
// arrays from unpack start with offset 1
// yet another php mystery. array_merge work around
// this broken behaviour
$v6vec = array_merge( unpack( 'C16', $ipnum ) );
$offset = 0;
for ( $depth = 127; $depth >= 0; --$depth ) {
if ( $this->flags & self::GEOIP_MEMORY_CACHE ) {
$buf = $this->_safe_substr(
$this->memory_buffer,
2 * $this->record_length * $offset,
2 * $this->record_length
);
} elseif ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
$buf = @shmop_read(
$this->shmid,
2 * $this->record_length * $offset,
2 * $this->record_length
);
} else {
fseek( $this->filehandle, 2 * $this->record_length * $offset, SEEK_SET ) == 0
or trigger_error( 'GeoIP API: fseek failed', E_USER_ERROR );
$buf = fread( $this->filehandle, 2 * $this->record_length );
}
$x = array( 0, 0 );
for ( $i = 0; $i < 2; ++$i ) {
for ( $j = 0; $j < $this->record_length; ++$j ) {
$x[ $i ] += ord( $buf[ $this->record_length * $i + $j ] ) << ( $j * 8 );
}
}
$bnum = 127 - $depth;
$idx = $bnum >> 3;
$b_mask = 1 << ( $bnum & 7 ^ 7 );
if ( ( $v6vec[ $idx ] & $b_mask ) > 0 ) {
if ( $x[1] >= $this->databaseSegments ) {
return $x[1];
}
$offset = $x[1];
} else {
if ( $x[0] >= $this->databaseSegments ) {
return $x[0];
}
$offset = $x[0];
}
}
trigger_error( 'GeoIP API: Error traversing database - perhaps it is corrupt?', E_USER_ERROR );
return false;
}
private function _geoip_seek_country( $ipnum ) {
$offset = 0;
for ( $depth = 31; $depth >= 0; --$depth ) {
@ -1412,7 +1466,7 @@ class WC_Geo_IP {
);
} else {
fseek( $this->filehandle, 2 * $this->record_length * $offset, SEEK_SET ) == 0
or trigger_error( "GeoIP API: fseek failed", E_USER_ERROR );
or trigger_error( 'GeoIP API: fseek failed', E_USER_ERROR );
$buf = fread( $this->filehandle, 2 * $this->record_length );
}
@ -1438,12 +1492,12 @@ class WC_Geo_IP {
}
}
trigger_error( "GeoIP API: Error traversing database - perhaps it is corrupt?", E_USER_ERROR );
trigger_error( 'GeoIP API: Error traversing database - perhaps it is corrupt?', E_USER_ERROR );
return false;
}
function geoip_record_by_addr( $addr ) {
public function geoip_record_by_addr( $addr ) {
if ( $addr == null ) {
return 0;
}
@ -1452,11 +1506,25 @@ class WC_Geo_IP {
return $this->_get_record( $ipnum );
}
function geoip_country_id_by_addr( $addr ) {
public function geoip_country_id_by_addr_v6( $addr ) {
$ipnum = inet_pton( $addr );
return $this->_geoip_seek_country_v6( $ipnum ) - self::GEOIP_COUNTRY_BEGIN;
}
public function geoip_country_id_by_addr( $addr ) {
$ipnum = ip2long( $addr );
return $this->_geoip_seek_country( $ipnum ) - self::GEOIP_COUNTRY_BEGIN;
}
public function geoip_country_code_by_addr_v6( $addr ) {
$country_id = $this->geoip_country_id_by_addr_v6( $addr );
if ( $country_id !== false ) {
return $this->GEOIP_COUNTRY_CODES[ $country_id ];
}
return false;
}
public function geoip_country_code_by_addr( $addr ) {
if ( $this->databaseType == self::GEOIP_CITY_EDITION_REV1 ) {
$record = $this->geoip_record_by_addr( $addr);

View File

@ -9,7 +9,7 @@
* @author WooThemes
* @category Admin
* @package WooCommerce/Classes
* @version 2.3.0
* @version 2.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -22,14 +22,15 @@ if ( ! defined( 'ABSPATH' ) ) {
class WC_Geolocation {
/** URL to the geolocation database we're using */
const GEOLITE_DB = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz';
const GEOLITE_DB = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz';
const GEOLITE_IPV6_DB = 'http://geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz';
/** @var array API endpoints for looking up user IP address */
private static $ip_lookup_apis = array(
'icanhazip' => 'http://ipv4.icanhazip.com',
'icanhazip' => 'http://icanhazip.com',
'ipify' => 'http://api.ipify.org/',
'ipecho' => 'http://ipecho.net/plain',
'ident' => 'http://v4.ident.me',
'ident' => 'http://ident.me',
'whatismyipaddress' => 'http://bot.whatismyipaddress.com',
'ip.appspot' => 'http://ip.appspot.com'
);
@ -119,12 +120,18 @@ class WC_Geolocation {
*/
public static function geolocate_ip( $ip_address = '', $fallback = true ) {
// If GEOIP is enabled in CloudFlare, we can use that (Settings -> CloudFlare Settings -> Settings Overview)
if ( ! empty( $_SERVER[ "HTTP_CF_IPCOUNTRY" ] ) ) {
$country_code = sanitize_text_field( strtoupper( $_SERVER["HTTP_CF_IPCOUNTRY"] ) );
if ( ! empty( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) {
$country_code = sanitize_text_field( strtoupper( $_SERVER['HTTP_CF_IPCOUNTRY'] ) );
} else {
$ip_address = $ip_address ? $ip_address : self::get_ip_address();
if ( file_exists( self::get_local_database_path() ) ) {
if ( self::is_IPv6( $ip_address ) ) {
$database = self::get_local_database_path( 'v6' );
} else {
$database = self::get_local_database_path();
}
if ( file_exists( $database ) ) {
$country_code = self::geolocate_via_db( $ip_address );
} else {
$country_code = self::geolocate_via_api( $ip_address );
@ -144,11 +151,14 @@ class WC_Geolocation {
/**
* Path to our local db
* @param string $version
* @return string
*/
private static function get_local_database_path() {
private static function get_local_database_path( $version = 'v4' ) {
$version = ( 'v4' == $version ) ? '' : 'v6';
$upload_dir = wp_upload_dir();
return $upload_dir['basedir'] . '/GeoIP.dat';
return $upload_dir['basedir'] . '/GeoIP' . $version . '.dat';
}
/**
@ -164,24 +174,29 @@ class WC_Geolocation {
require_once( ABSPATH . 'wp-admin/includes/file.php' );
$tmp_database = download_url( self::GEOLITE_DB );
$tmp_databases = array(
'v4' => download_url( self::GEOLITE_DB ),
'v6' => download_url( self::GEOLITE_IPV6_DB )
);
if ( ! is_wp_error( $tmp_database ) ) {
$gzhandle = @gzopen( $tmp_database, 'r' );
$handle = @fopen( self::get_local_database_path(), 'w' );
foreach ( $tmp_databases as $tmp_database_version => $tmp_database_path ) {
if ( ! is_wp_error( $tmp_database_path ) ) {
$gzhandle = @gzopen( $tmp_database_path, 'r' );
$handle = @fopen( self::get_local_database_path( $tmp_database_version ), 'w' );
if ( $gzhandle && $handle ) {
while ( ( $string = gzread( $gzhandle, 4096 ) ) != false ) {
fwrite( $handle, $string, strlen( $string ) );
if ( $gzhandle && $handle ) {
while ( ( $string = gzread( $gzhandle, 4096 ) ) != false ) {
fwrite( $handle, $string, strlen( $string ) );
}
gzclose( $gzhandle );
fclose( $handle );
} else {
$logger->add( 'geolocation', 'Unable to open database file' );
}
gzclose( $gzhandle );
fclose( $handle );
@unlink( $tmp_database_path );
} else {
$logger->add( 'geolocation', 'Unable to open database file' );
$logger->add( 'geolocation', 'Unable to download GeoIP Database: ' . $tmp_database_path->get_error_message() );
}
@unlink( $tmp_database );
} else {
$logger->add( 'geolocation', 'Unable to download GeoIP Database: ' . $tmp_database->get_error_message() );
}
}
@ -194,11 +209,19 @@ class WC_Geolocation {
if ( ! class_exists( 'WC_Geo_IP' ) ) {
include_once( 'class-wc-geo-ip.php' );
}
$database = self::get_local_database_path();
$gi = new WC_Geo_IP();
$gi->geoip_open( $database, 0 );
$country_code = $gi->geoip_country_code_by_addr( $ip_address );
$gi = new WC_Geo_IP();
if ( self::is_IPv6( $ip_address ) ) {
$database = self::get_local_database_path( 'v6' );
$gi->geoip_open( $database, 0 );
$country_code = $gi->geoip_country_code_by_addr_v6( $ip_address );
} else {
$database = self::get_local_database_path();
$gi->geoip_open( $database, 0 );
$country_code = $gi->geoip_country_code_by_addr( $ip_address );
}
$gi->geoip_close();
return sanitize_text_field( strtoupper( $country_code ) );
@ -250,6 +273,18 @@ class WC_Geolocation {
return $country_code;
}
/**
* Test if is IPv6
*
* @since 2.4.0
*
* @param string $ip_address
* @return bool
*/
private static function is_IPv6( $ip_address ) {
return false !== filter_var( $ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 );
}
}
WC_Geolocation::init();

View File

@ -72,6 +72,10 @@ if ( ! comments_open() ) {
'comment_field' => ''
);
if ( $account_page_url = wc_get_page_permalink( 'myaccount' ) ) {
$comment_form['must_log_in'] = '<p class="must-log-in">' . sprintf( __( 'You must be <a href="%s">logged in</a> to post a review.' ), esc_url( $account_page_url ) ) . '</p>';
}
if ( get_option( 'woocommerce_enable_review_rating' ) === 'yes' ) {
$comment_form['comment_field'] = '<p class="comment-form-rating"><label for="rating">' . __( 'Your Rating', 'woocommerce' ) .'</label><select name="rating" id="rating">
<option value="">' . __( 'Rate&hellip;', 'woocommerce' ) . '</option>

View File

@ -62,7 +62,7 @@ global $product, $post;
?>
</select> <?php
if ( sizeof( $attributes ) === $loop ) {
echo '<a class="reset_variations" href="#reset">' . __( 'Clear selection', 'woocommerce' ) . '</a>';
echo '<a class="reset_variations" href="#">' . __( 'Clear selection', 'woocommerce' ) . '</a>';
}
?></td>
</tr>