Add the wc-city-select plugin - version 1.0.3

This commit is contained in:
htdat
2017-02-26 14:58:41 +07:00
parent 58fee75673
commit 1736fa1207
4 changed files with 1625 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
jQuery( function($) {
// wc_city_select_params is required to continue, ensure the object exists
// wc_country_select_params is used for select2 texts. This one is added by WC
if ( typeof wc_country_select_params === 'undefined' || typeof wc_city_select_params === 'undefined' ) {
return false;
}
function getEnhancedSelectFormatString() {
var formatString = {
formatMatches: function( matches ) {
if ( 1 === matches ) {
return wc_country_select_params.i18n_matches_1;
}
return wc_country_select_params.i18n_matches_n.replace( '%qty%', matches );
},
formatNoMatches: function() {
return wc_country_select_params.i18n_no_matches;
},
formatAjaxError: function() {
return wc_country_select_params.i18n_ajax_error;
},
formatInputTooShort: function( input, min ) {
var number = min - input.length;
if ( 1 === number ) {
return wc_country_select_params.i18n_input_too_short_1;
}
return wc_country_select_params.i18n_input_too_short_n.replace( '%qty%', number );
},
formatInputTooLong: function( input, max ) {
var number = input.length - max;
if ( 1 === number ) {
return wc_country_select_params.i18n_input_too_long_1;
}
return wc_country_select_params.i18n_input_too_long_n.replace( '%qty%', number );
},
formatSelectionTooBig: function( limit ) {
if ( 1 === limit ) {
return wc_country_select_params.i18n_selection_too_long_1;
}
return wc_country_select_params.i18n_selection_too_long_n.replace( '%qty%', limit );
},
formatLoadMore: function() {
return wc_country_select_params.i18n_load_more;
},
formatSearching: function() {
return wc_country_select_params.i18n_searching;
}
};
return formatString;
}
// Select2 Enhancement if it exists
if ( $().select2 ) {
var wc_city_select_select2 = function() {
$( 'select.city_select:visible' ).each( function() {
var select2_args = $.extend({
placeholderOption: 'first',
width: '100%'
}, getEnhancedSelectFormatString() );
$( this ).select2( select2_args );
});
};
wc_city_select_select2();
$( document.body ).bind( 'city_to_select', function() {
wc_city_select_select2();
});
}
/* City select boxes */
var cities_json = wc_city_select_params.cities.replace( /"/g, '"' );
var cities = $.parseJSON( cities_json );
$( 'body' ).on( 'country_to_state_changing', function(e, country, $container) {
var $statebox = $container.find( '#billing_state, #shipping_state, #calc_shipping_state' );
var state = $statebox.val();
$( document.body ).trigger( 'state_changing', [country, state, $container ] );
});
$( 'body' ).on( 'change', 'select.state_select, #calc_shipping_state', function() {
var $container = $( this ).closest( 'div' );
var country = $container.find( '#billing_country, #shipping_country, #calc_shipping_country' ).val();
var state = $( this ).val();
$( document.body ).trigger( 'state_changing', [country, state, $container ] );
});
$( 'body' ).on( 'state_changing', function(e, country, state, $container) {
var $citybox = $container.find( '#billing_city, #shipping_city, #calc_shipping_city' );
if ( cities[ country ] ) {
/* if the country has no states */
if( cities[country] instanceof Array) {
cityToSelect( $citybox, cities[ country ] );
} else if ( state ) {
if ( cities[ country ][ state ] ) {
cityToSelect( $citybox, cities[ country ][ state ] );
} else {
cityToInput( $citybox );
}
} else {
disableCity( $citybox );
}
} else {
cityToInput( $citybox );
}
});
/* Ajax replaces .cart_totals (child of .cart-collaterals) on shipping calculator */
if ( $( '.cart-collaterals' ).length && $( '#calc_shipping_state' ).length ) {
var calc_observer = new MutationObserver( function() {
$( '#calc_shipping_state' ).change();
});
calc_observer.observe( document.querySelector( '.cart-collaterals' ), { childList: true });
}
function cityToInput( $citybox ) {
if ( $citybox.is('input') ) {
$citybox.prop( 'disabled', false );
return;
}
var input_name = $citybox.attr( 'name' );
var input_id = $citybox.attr( 'id' );
var placeholder = $citybox.attr( 'placeholder' );
$citybox.parent().find( '.select2-container' ).remove();
$citybox.replaceWith( '<input type="text" class="input-text" name="' + input_name + '" id="' + input_id + '" placeholder="' + placeholder + '" />' );
}
function disableCity( $citybox ) {
$citybox.val( '' ).change();
$citybox.prop( 'disabled', true );
}
function cityToSelect( $citybox, current_cities ) {
var value = $citybox.val();
if ( $citybox.is('input') ) {
var input_name = $citybox.attr( 'name' );
var input_id = $citybox.attr( 'id' );
var placeholder = $citybox.attr( 'placeholder' );
$citybox.replaceWith( '<select name="' + input_name + '" id="' + input_id + '" class="city_select" placeholder="' + placeholder + '"></select>' );
//we have to assign the new object, because of replaceWith
$citybox = $('#'+input_id);
} else {
$citybox.prop( 'disabled', false );
}
var options = '';
for( var index in current_cities ) {
if ( current_cities.hasOwnProperty( index ) ) {
var cityName = current_cities[ index ];
options = options + '<option value="' + cityName + '">' + cityName + '</option>';
}
}
$citybox.html( '<option value="">' + wc_city_select_params.i18n_select_city_text + '</option>' + options );
if ( $('option[value="'+value+'"]', $citybox).length ) {
$citybox.val( value ).change();
} else {
$citybox.val( '' ).change();
}
$( document.body ).trigger( 'city_to_select' );
}
});
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
=== WC City Select ===
Contributors: mantish
Donate link: mailto:paypal@8manos.com
Tags: woocommerce, cities, city, city select, cities select, city dropdown, cities dropdown, woocommerce city, woocommerce cities
Requires at least: 4.0
Tested up to: 4.7.3
Stable tag: 1.0.3
WC requires at least: 2.2
WC tested up to: 2.7.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
City Select for WooCommerce. Show a dropdown select as the cities input.
== Description ==
WooCommerce uses a text input for the customers to enter the city or town. With this plugin you can provide a list of cities to be shown as a select dropdown.
This will be shown in checkout pages, edit addresses pages and shipping calculator if it's configured that way.
A list of cities has to be loaded in the functions.php file (the plugin already includes cities from Colombia and Iran). Please check the Installation section for more info.
### Github
Contribute at https://github.com/8manos/wc-city-select
== Installation ==
1. Upload to the `/wp-content/plugins/` directory
1. Activate the plugin through the 'Plugins' menu in WordPress
1. Use `wc_city_select_cities` filter to load your cities. This is done similarly to [adding states/provinces](https://docs.woothemes.com/document/addmodify-states/). It should be added on your functions.php or a custom plugin.
`
add_filter( 'wc_city_select_cities', 'my_cities' );
/**
* Replace XX with the country code. Instead of YYY, ZZZ use actual state codes.
*/
function my_cities( $cities ) {
$cities['XX'] = array(
'YYY' => array(
'City ',
'Another City'
),
'ZZZ' => array(
'City 3',
'City 4'
)
);
return $cities;
}
`
It's also possible to use a list of cities without grouping them by state:
`
add_filter( 'wc_city_select_cities', 'my_cities' );
function my_cities( $cities ) {
$cities['XX'] = array(
'City ',
'Another City'
);
return $cities;
}
`
== Changelog ==
= 1.0.3 =
* fix some issues when loading cities initially, that were causing warnings.
= 1.0.2 =
* fix some issues with shipping calculator and other edge cases.
* Now works with countries that have no states, only cities.
= 1.0.1 =
* select2 enhancement when available. Adds a JS version of the select dropdown.
= 1.0 =
* First release.
+196
View File
@@ -0,0 +1,196 @@
<?php
/**
* Plugin Name: WC City Select
* Plugin URI: https://wordpress.org/plugins/wc-city-select/
* Description: City Select for WooCommerce. Show a dropdown select as the cities input.
* Version: 1.0.3
* Author: 8manos
* Author URI: http://8manos.com
* License: GPLv2 or later
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
// Check if WooCommerce is active
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
class WC_City_Select {
// plugin version
const VERSION = '1.0.1';
private $plugin_path;
private $plugin_url;
private $cities;
public function __construct() {
add_filter( 'woocommerce_billing_fields', array( $this, 'billing_fields' ), 10, 2 );
add_filter( 'woocommerce_shipping_fields', array( $this, 'shipping_fields' ), 10, 2 );
add_filter( 'woocommerce_form_field_city', array( $this, 'form_field_city' ), 10, 4 );
//js scripts
add_action( 'wp_enqueue_scripts', array( $this, 'load_scripts' ) );
}
public function billing_fields( $fields, $country ) {
$fields['billing_city']['type'] = 'city';
return $fields;
}
public function shipping_fields( $fields, $country ) {
$fields['shipping_city']['type'] = 'city';
return $fields;
}
public function get_cities( $cc = null ) {
if ( empty( $this->cities ) ) {
$this->load_country_cities();
}
if ( ! is_null( $cc ) ) {
return isset( $this->cities[ $cc ] ) ? $this->cities[ $cc ] : false;
} else {
return $this->cities;
}
}
public function load_country_cities() {
global $cities;
// Load only the city files the shop owner wants/needs.
$allowed = array_merge( WC()->countries->get_allowed_countries(), WC()->countries->get_shipping_countries() );
if ( $allowed ) {
foreach ( $allowed as $code => $country ) {
if ( ! isset( $cities[ $code ] ) && file_exists( $this->get_plugin_path() . '/cities/' . $code . '.php' ) ) {
include( $this->get_plugin_path() . '/cities/' . $code . '.php' );
}
}
}
$this->cities = apply_filters( 'wc_city_select_cities', $cities );
}
public function form_field_city( $field, $key, $args, $value ) {
// Do we need a clear div?
if ( ( ! empty( $args['clear'] ) ) ) {
$after = '<div class="clear"></div>';
} else {
$after = '';
}
// Required markup
if ( $args['required'] ) {
$args['class'][] = 'validate-required';
$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>';
} else {
$required = '';
}
// Custom attribute handling
$custom_attributes = array();
if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) {
foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
}
}
// Validate classes
if ( ! empty( $args['validate'] ) ) {
foreach( $args['validate'] as $validate ) {
$args['class'][] = 'validate-' . $validate;
}
}
// field p and label
$field = '<p class="form-row ' . esc_attr( implode( ' ', $args['class'] ) ) .'" id="' . esc_attr( $args['id'] ) . '_field">';
if ( $args['label'] ) {
$field .= '<label for="' . esc_attr( $args['id'] ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label']. $required . '</label>';
}
// Get Country
$country_key = $key == 'billing_city' ? 'billing_country' : 'shipping_country';
$current_cc = WC()->checkout->get_value( $country_key );
$state_key = $key == 'billing_city' ? 'billing_state' : 'shipping_state';
$current_sc = WC()->checkout->get_value( $state_key );
// Get country cities
$cities = $this->get_cities( $current_cc );
if ( is_array( $cities ) ) {
$field .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="city_select ' . esc_attr( implode( ' ', $args['input_class'] ) ) .'" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '">
<option value="">'. __( 'Select an option&hellip;', 'woocommerce' ) .'</option>';
if ( $current_sc && $cities[ $current_sc ] ) {
$dropdown_cities = $cities[ $current_sc ];
} else if ( is_array( reset($cities) ) ) {
$dropdown_cities = array_reduce( $cities, 'array_merge', array() );
sort( $dropdown_cities );
} else {
$dropdown_cities = $cities;
}
foreach ( $dropdown_cities as $city_name ) {
$field .= '<option value="' . esc_attr( $city_name ) . '" '.selected( $value, $city_name, false ) . '>' . $city_name .'</option>';
}
$field .= '</select>';
} else {
$field .= '<input type="text" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) .'" value="' . esc_attr( $value ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" ' . implode( ' ', $custom_attributes ) . ' />';
}
// field description and close wrapper
if ( $args['description'] ) {
$field .= '<span class="description">' . esc_attr( $args['description'] ) . '</span>';
}
$field .= '</p>' . $after;
return $field;
}
public function load_scripts() {
if ( is_cart() || is_checkout() || is_wc_endpoint_url( 'edit-address' ) ) {
$city_select_path = $this->get_plugin_url() . 'assets/js/city-select.js';
wp_enqueue_script( 'wc-city-select', $city_select_path, array( 'jquery', 'woocommerce' ), self::VERSION, true );
$cities = json_encode( $this->get_cities() );
wp_localize_script( 'wc-city-select', 'wc_city_select_params', array(
'cities' => $cities,
'i18n_select_city_text' => esc_attr__( 'Select an option&hellip;', 'woocommerce' )
) );
}
}
public function get_plugin_path() {
if ( $this->plugin_path ) {
return $this->plugin_path;
}
return $this->plugin_path = plugin_dir_path( __FILE__ );
}
public function get_plugin_url() {
if ( $this->plugin_url ) {
return $this->plugin_url;
}
return $this->plugin_url = plugin_dir_url( __FILE__ );
}
}
$GLOBALS['wc_city_select'] = new WC_City_Select();
}