Related
I am trying to add a city dropdown in my Woocommerce store's admin order edit area. I have tried this code.
add_filter( 'woocommerce_admin_billing_fields' , 'admin_billing_city_select_field' );
function admin_billing_city_select_field( $fields ) {
global $pagenow;
// Only for new order creation
if( $pagenow != 'post-new.php' ) return $fields;
$fields['city'] = array(
'label' => __( 'City', 'woocommerce' ),
'show' => false,
'class' => 'js_field-city select short',
'type' => 'select',
'options' => array(
'' => __( 'Select a city…', 'woocommerce' ),
'Los Angeles' => __( 'Los Angeles', 'woocommerce' ),
'San Antonio' => __( 'San Antonio', 'woocommerce' ),
),
);
return $fields;
}
It's working like this
But I want to add some condition If the state matches then it will show a specific city list. And it should revel the city list after selecting the state. How can I do this?
Edit 1
I have added places as an array. And here is the full code in Github.
global $places;
$places['BD'] = array(
'dhaka' => array(
__('Aam Bagan', 'woocommerce'),
__('12 Tala', 'woocommerce'),
__('Keraniganj Upazila Sadar', 'woocommerce'),
),
'faridpur' => array(
__('Alfadanga', 'woocommerce'),
),
'gazipur' => array(
__('Gazipur Sadar', 'woocommerce'),
__('Kaliakair', 'woocommerce'),
),
'gopalganj' => array(
__('Gopalganj Sadar', 'woocommerce'),
__('Kashiani', 'woocommerce'),
),
'jamalpur' => array(
__('Bakshiganj', 'woocommerce'),
__('Dewanganj', 'woocommerce'),
),
);
function enqueue_scripts()
{
wp_enqueue_script('jquery');
wp_enqueue_script('select2', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js', array('jquery'), '4.0.13', true);
wp_enqueue_script('place-select-js', plugin_dir_url(__FILE__) . 'js/place-select.js', array('jquery', 'select2'), '0.1', true);
}
add_action('admin_enqueue_scripts', 'enqueue_scripts');
add_filter('woocommerce_admin_billing_fields', 'admin_billing_city_select_field');
function admin_billing_city_select_field($fields)
{
global $pagenow, $places;
// Only for new order creation
if ($pagenow != 'post-new.php') return $fields;
$options = array('' => __('Select a city…', 'woocommerce'));
if (isset($places)) {
foreach ($places as $state => $cities) {
foreach ($cities as $city => $city_name) {
$options[$city] = $city_name[0];
}
}
}
$fields['city'] = array(
'label' => __('City', 'woocommerce'),
'show' => false,
'class' => 'js_field-city select short',
'type' => 'select',
'options' => $options,
);
return $fields;
}
The imported jquery file is from #Aurelien - AK Digital's answer. But it's returning only the first item of the array.
If I change $options[$city] = $city_name[0]; to $options[$city] = $city_name; it's returning a string text instead of cities "Array" How can I fix it?
First, for a better user experience, I recommend to move the "State field" before the "City" & "Postcode" fields.
You also may have to think about the amount of data you'll want to load. Will you propose every single US city and town or only a few ? This will conditionned the way data will be load.
But let's assume you will create you're own [short] list.
(All of this code has been tested WP 6.1.1 & WC 7.3.0)
First you need to store that list of cities, including state prefixes, in a WordPress option (ex.: '_wc_cities_by_states') like so :
$state_city_options = array(
'CA-los-angeles' => __( 'Los Angeles', 'woocommerce' ),
'CA-san-antonio' => __( 'San Antonio', 'woocommerce' ),
'WA-seattle' => __( 'Seattle', 'woocommerce' ),
'WA-olympia' => __( 'Olympia', 'woocommerce' ),
);
set_option('_wc_cities_by_states', $state_city_options);
Then, get this custom option to build your city select option list :
add_filter( 'woocommerce_admin_billing_fields' , 'admin_billing_city_select_field' );
function admin_billing_city_select_field( $fields ) {
global $pagenow;
// Get the array of cities by state from WP option
$cities_by_states = get_option('_wc_cities_by_states', )
// Only for new order creation
if( $pagenow != 'post-new.php' || !$cities_by_states ) return $fields;
// Add it to WC city fields
$fields['city'] = array(
'label' => __( 'City', 'woocommerce' ),
'show' => false,
'class' => 'js_field-city select short',
'type' => 'select',
'options' => $cities_by_states;
);
return $fields;
}
Finally, this is the Javascript (jQuery) that will do the trick (NB: Woocommerce use the select2 lib) :
jQuery(document).ready(function ($) {
$(".js_field-city option").hide();
//Required to biding after billing-edit click
$(".edit_address").one("click", function () {
filterCities();
});
//Required to avoid unbiding after Country change
$(".js_field-country").on("select2:select", function (evt) {
filterCities();
});
filterCities = () => {
$(".js_field-state").on("select2:select", function (evt) {
var state = $(this).select2("data")[0].id;
$(".js_field-city option").hide();
$(".js_field-city option[value^='" + state + "']").show();
$(".js_field-city").val(null);
});
};
});
That code works for me, I hope it will work for you as well.
Thanks to let me know !
I'm trying to add a custom settings tab to the WooCommerce settings screen. Basically I want to achieve a similar thing to the Products settings tab, with the subsections/subtabs:
I haven't been able to find any decent documentation on how to do this but I've been able to add a custom tab using this snippet:
class WC_Settings_Tab_Demo {
public static function init() {
add_filter( 'woocommerce_settings_tabs_array', __CLASS__ . '::add_settings_tab', 50 );
}
public static function add_settings_tab( $settings_tabs ) {
$settings_tabs['test'] = __( 'Settings Demo Tab', 'woocommerce-settings-tab-demo' );
return $settings_tabs;
}
}
WC_Settings_Tab_Demo::init();
Based on what I've dug up from various threads/tutorials, I've been trying to add the sections/subtabs to the new settings tab something like this:
// creating a new sub tab in API settings
add_filter( 'woocommerce_get_sections_test','add_subtab' );
function add_subtab( $sections ) {
$sections['custom_settings'] = __( 'Custom Settings', 'woocommerce-custom-settings-tab' );
$sections['more_settings'] = __( 'More Settings', 'woocommerce-custom-settings-tab' );
return $sections;
}
// adding settings (HTML Form)
add_filter( 'woocommerce_get_settings_test', 'add_subtab_settings', 10, 2 );
function add_subtab_settings( $settings, $current_section ) {
// $current_section = (isset($_GET['section']) && !empty($_GET['section']))? $_GET['section']:'';
if ( $current_section == 'custom_settings' ) {
$custom_settings = array();
$custom_settings[] = array( 'name' => __( 'Custom Settings', 'text-domain' ),
'type' => 'title',
'desc' => __( 'The following options are used to ...', 'text-domain' ),
'id' => 'custom_settings'
);
$custom_settings[] = array(
'name' => __( 'Field 1', 'text-domain' ),
'id' => 'field_one',
'type' => 'text',
'default' => get_option('field_one'),
);
$custom_settings[] = array( 'type' => 'sectionend', 'id' => 'test-options' );
return $custom_settings;
} else {
// If not, return the standard settings
return $settings;
}
}
I've been able to add new subsections to the Products tab using similar code to the above, but it isn't working for my new custom tab. Where am I going wrong here?
1) To add a setting tab with sections, you can firstly use the woocommerce_settings_tabs_array filter hook:
// Add the tab to the tabs array
function filter_woocommerce_settings_tabs_array( $settings_tabs ) {
$settings_tabs['my-custom-tab'] = __( 'My custom tab', 'woocommerce' );
return $settings_tabs;
}
add_filter( 'woocommerce_settings_tabs_array', 'filter_woocommerce_settings_tabs_array', 99 );
2) To add new sections to the page, you can use the woocommerce_sections_{$current_tab} composite hook where {$current_tab} need to be replaced by the key slug that is set in the first function:
// Add new sections to the page
function action_woocommerce_sections_my_custom_tab() {
global $current_section;
$tab_id = 'my-custom-tab';
// Must contain more than one section to display the links
// Make first element's key empty ('')
$sections = array(
'' => __( 'Overview', 'woocommerce' ),
'my-section-1' => __( 'My section 1', 'woocommerce' ),
'my-section-2' => __( 'My section 2', 'woocommerce' )
);
echo '<ul class="subsubsub">';
$array_keys = array_keys( $sections );
foreach ( $sections as $id => $label ) {
echo '<li>' . $label . ' ' . ( end( $array_keys ) == $id ? '' : '|' ) . ' </li>';
}
echo '</ul><br class="clear" />';
}
add_action( 'woocommerce_sections_my-custom-tab', 'action_woocommerce_sections_my_custom_tab', 10 );
3) For adding the settings, as well as for processing/saving, we will use a custom function, which we will then call:
// Settings function
function get_custom_settings() {
global $current_section;
$settings = array();
if ( $current_section == 'my-section-1' ) {
// My section 1
$settings = array(
// Title
array(
'title' => __( 'Your title 1', 'woocommerce' ),
'type' => 'title',
'id' => 'custom_settings_1'
),
// Text
array(
'title' => __( 'Your title 1.1', 'text-domain' ),
'type' => 'text',
'desc' => __( 'Your description 1.1', 'woocommerce' ),
'desc_tip' => true,
'id' => 'custom_settings_1_text',
'css' => 'min-width:300px;'
),
// Select
array(
'title' => __( 'Your title 1.2', 'woocommerce' ),
'desc' => __( 'Your description 1.2', 'woocommerce' ),
'id' => 'custom_settings_1_select',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'aa',
'type' => 'select',
'options' => array(
'aa' => __( 'aa', 'woocommerce' ),
'bb' => __( 'bb', 'woocommerce' ),
'cc' => __( 'cc', 'woocommerce' ),
'dd' => __( 'dd', 'woocommerce' ),
),
'desc_tip' => true,
),
// Section end
array(
'type' => 'sectionend',
'id' => 'custom_settings_1'
),
);
} elseif ( $current_section == 'my-section-2' ) {
// My section 2
$settings = array(
// Title
array(
'title' => __( 'Your title 2', 'woocommerce' ),
'type' => 'title',
'id' => 'custom_settings_2'
),
// Text
array(
'title' => __( 'Your title 2.2', 'text-domain' ),
'type' => 'text',
'desc' => __( 'Your description 2.1', 'woocommerce' ),
'desc_tip' => true,
'id' => 'custom_settings_2_text',
'css' => 'min-width:300px;'
),
// Section end
array(
'type' => 'sectionend',
'id' => 'custom_settings_2'
),
);
} else {
// Overview
$settings = array(
// Title
array(
'title' => __( 'Overview', 'woocommerce' ),
'type' => 'title',
'id' => 'custom_settings_overview'
),
// Section end
array(
'type' => 'sectionend',
'id' => 'custom_settings_overview'
),
);
}
return $settings;
}
3.1) Add settings, via the woocommerce_settings_{$current_tab} composite hook:
// Add settings
function action_woocommerce_settings_my_custom_tab() {
// Call settings function
$settings = get_custom_settings();
WC_Admin_Settings::output_fields( $settings );
}
add_action( 'woocommerce_settings_my-custom-tab', 'action_woocommerce_settings_my_custom_tab', 10 );
3.2) Process/save the settings, via the woocommerce_settings_save_{$current_tab} composite hook:
// Process/save the settings
function action_woocommerce_settings_save_my_custom_tab() {
global $current_section;
$tab_id = 'my-custom-tab';
// Call settings function
$settings = get_custom_settings();
WC_Admin_Settings::save_fields( $settings );
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $tab_id . '_' . $current_section );
}
}
add_action( 'woocommerce_settings_save_my-custom-tab', 'action_woocommerce_settings_save_my_custom_tab', 10 );
Result:
Based on:
Implement a custom WooCommerce settings page, including page sections
woocommerce/includes/admin/settings/
I am searching everywhere for an example of how to populate/access images entered inside of repeatable file-list group in CMB2. All the examples I could find is only for a single image: here is the link https://github.com/CMB2/CMB2/wiki/Field-Types#group
MY CODE:
// creating a group
$group_field_id = $bautage->add_field( array(
id' => 'tagen_entries',
'type' => 'group',
'description' => __( 'Tagen', 'cmb2' ),
'repeatable' => true,
'options' => array(
'group_title' => __( 'Tagen {#}', 'cmb2' ), // since version 1.1.4, {#} gets replaced by row number
'add_button' => __( 'Add Another Entry', 'cmb2' ),
'remove_button' => __( 'Remove Entry', 'cmb2' ),
'sortable' => true,
),
) );
// creating repeatable fields
$bautage->add_group_field( $group_field_id, array(
'name' => 'Tag Name',
'id' => 'tag_name',
'type' => 'text',
) );
$bautage->add_group_field( $group_field_id, array(
'name' => 'Tage Photos',
'id' => 'tage_photos',
'type' => 'file_list',
) );
// page code
$tagen_entries = get_post_meta( get_the_ID(), 'tagen_entries', true );
foreach ( (array) $tagen_entries as $key => $entry ) {
if ( isset( $entry['tag_name'] ) ) {
$tag_name = esc_html( $entry['tag_name'] );
echo $tag_name;
}
if ( isset( $entry['tage_bildern'] ) ) {
// loop to bring all the photos
// also need the first photo from each entry to be used as a click trigger to open the slideshow
}
}
In Woocommerce I have been able to add 2 custom dropdowns list in checkout page:
add_action('woocommerce_before_order_notes', 'wps_add_select_checkout_field');
function wps_add_select_checkout_field( $checkout) {
echo '<h2>'.__('Next Day Delivery').'</h2>';
woocommerce_form_field( 'City', array(
'type' => 'select',
'class' => array( 'wps-drop' ),
'label' => __( 'Delivery options' ),
'options' => array(
'blank' => __( 'Select a day part', 'wps' ),
'A' => __( 'A', 'wps' ),
'B' => __( 'B', 'wps' ),
'C' => __( 'C', 'wps' )
)
),
$checkout->get_value( 'City' ));
}
add_action('woocommerce_before_order_notes', 'wps_add_select_checkout1_field');
function wps_add_select_checkout1_field( $checkout1) {
//echo '<h2>'.__('Next Day Delivery').'</h2>';
woocommerce_form_field( 'Dis', array(
'type' => 'select',
'class' => array( 'wps-drop' ),
'label' => __( 'Delivery options' ),
'options' => array(
'blank' => __( 'Select a day part', 'wps' ),
'A' => __( 'ro', 'wps' ),
'B' => __( 'wa', 'wps' ),
'C' => __( 'da', 'wps' )
)
),
$checkout1->get_value( 'Dis' ));
}
//* Process the checkout
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
global $woocommerce;
// Check if set, if its not set add an error.
if ($_POST['City'] == "blank")
wc_add_notice( '<strong>Please select a day part under Delivery options</strong>', 'error' );
}
I would like to generate dynamically the options of the second dropdown list, based on the selected <option> from the first dropdown list.
Example of what I need:
If <option> "A" is selected in the 1st dropdown list, The 2nd dropdown list will show dynamically a specific set of options.
If <option> "C" is selected in the 1st dropdown list, The 2nd dropdown list will show dynamically a different set of options.
And so on …
Is that possible? Where do I have to start?
Any help is appreciated.
I have merged your 2 first functions as they use the same hook.
In this merged function I have added:
The "required" option to both fields.
Changed the slugs for both fields as for example "City" throw a woocommerce error.
different sets of "options" arrays that I pass to javascript (one for each available <option> in the first select field).
Some jQuery code that create dynamically the set of options in the 2nd select field, based on the selected <option> of the first select field.
I have change a bit the condition for the If statement in the last function.
Here is the revisited code:
// Add checkout custom select fields
add_action( 'woocommerce_before_order_notes', 'add_checkout_custom_fields', 20, 1 );
function add_checkout_custom_fields( $checkout) {
$domain = 'woocommerce'; // The domain slug
echo '<h2>'.__( 'Next Day Delivery', $domain ).'</h2>';
// First Select field (Master)
woocommerce_form_field( 'delivery_one', array(
'type' => 'select',
'label' => __( 'Delivery options one' , $domain),
'class' => array( 'form-row-wide' ),
'required' => true,
'options' => array(
'' => __( 'Please select a value', $domain ),
'A' => __( 'A', $domain ),
'B' => __( 'B', $domain ),
'C' => __( 'C', $domain ),
),
),
$checkout->get_value( 'delivery_one' ) );
// Default option value
$default_option2 = __( 'Please select a value', $domain );
// Dynamic select field options for Javascript/jQuery
$options_0 = array( '' => $default_option2 );
$options_a = array(
'' => $default_option2,
'D' => __( 'D', $domain ),
'E' => __( 'E', $domain ),
'F' => __( 'F', $domain ),
'G' => __( 'G', $domain ),
);
$options_b = array(
'' => $default_option2,
'H' => __( 'H', $domain ),
'I' => __( 'I', $domain ),
'J' => __( 'J', $domain ),
);
$options_c = array(
'' => $default_option2,
'K' => __( 'K', $domain ),
'L' => __( 'L', $domain ),
'M' => __( 'M', $domain ),
);
// Second Select field (Dynamic Slave)
woocommerce_form_field( 'delivery_two', array(
'type' => 'select',
'label' => __( 'Delivery options two', $domain ),
'class' => array( 'form-row-wide' ),
'required' => true,
'options' => $options_0,
),
$checkout->get_value( 'delivery_two' ) );
$required = esc_attr__( 'required', 'woocommerce' );
// jQuery code
?>
<script>
jQuery(function($){
var op0 = <?php echo json_encode($options_0); ?>,
opa = <?php echo json_encode($options_a); ?>,
opb = <?php echo json_encode($options_b); ?>,
opc = <?php echo json_encode($options_c); ?>,
select1 = 'select[name="delivery_one"]',
select2 = 'select[name="delivery_two"]';
// Utility function to fill dynamically the select field options
function dynamicSelectOptions( opt ){
var options = '';
$.each( opt, function( key, value ){
options += '<option value="'+key+'">'+value+'</option>';
});
$(select2).html(options);
}
// 1. When dom is loaded we add the select field option for "A" value
// => Disabled (optional) — Uncomment below to enable
// dynamicSelectOptions( opa );
// 2. On live selection event on the first dropdown
$(select1).change(function(){
if( $(this).val() == 'A' )
dynamicSelectOptions( opa );
else if( $(this).val() == 'B' )
dynamicSelectOptions( opb );
else if( $(this).val() == 'C' )
dynamicSelectOptions( opc );
else
dynamicSelectOptions( op0 ); // Reset to default
});
});
</script>
<?php
}
// Check checkout custom fields
add_action( 'woocommerce_checkout_process', 'wps_check_checkout_custom_fields', 20 ) ;
function wps_check_checkout_custom_fields() {
// if custom fields are empty stop checkout process displaying an error notice.
if ( empty($_POST['delivery_one']) || empty($_POST['delivery_two']) ){
$notice = __( 'Please select a day part under Delivery options' );
wc_add_notice( '<strong>' . $notice . '</strong>', 'error' );
}
}
Code goes in function.php file of your active child theme (active theme).
This is a fully working and tested example.
$cmb->add_field( array(
'name' => 'Select Video or Image',
'desc' => 'Select an option',
'id' => 'the_wiki_id_one',
'type' => 'select',
'show_option_none' => true,
'default' => 'custom',
'options' => array(
'standard' => __( 'Option One', 'cmb2' ),
'custom' => __( 'Option Two', 'cmb2' ),
'none' => __( 'Option Three', 'cmb2' ),
),
) );
Above is the code. Now suppose If I have chosen Option two, and I want to execute a logic Like this →
If (Option 2 selected) {
<?php Then execute some PHP code ?>
}
Option 2 selected → layman Language. How can we do this in terms of programming one?
Above is a code from CMB2 Wordpress Plugin
If i get it right, then you just need to get that value from post meta, and make condition.
$the_wiki_id_one = get_post_meta($post_id, 'the_wiki_id_one', true);
// Option 2 is selected
if( 'custom' === $the_wiki_id_one ){
//Then execute some PHP code
}