I am using the following code to display an additional input field on the edit account page of WooCommerce.
/**
* Step 1. Add your field - Age Range
*/
add_action( 'woocommerce_edit_account_form', 'misha_add_age_range_field_account_form' );
function misha_add_age_range_field_account_form() {
echo "<h4> Please fill in the following details to complete your profile for review </h4>";
woocommerce_form_field(
'certified_age_range',
array(
'type' => 'text',
'required' => true, // remember, this doesn't make the field required, just adds an "*"
'label' => 'Your Age',
'description' => '',
),
get_user_meta( get_current_user_id(), 'certified_age_range', true ) // get the data
);
}
/**
* Step 2. Save field value
*/
add_action( 'woocommerce_save_account_details', 'misha_save_age_range_account_details' );
function misha_save_age_range_account_details( $user_id ) {
update_user_meta( $user_id, 'certified_age_range', sanitize_text_field( $_POST['certified_age_range'] ) );
}
/**
* Step 3. Make it required
*/
add_filter('woocommerce_save_account_details_required_fields', 'misha_make_field_required');
function misha_make_age_range_field_required( $required_fields ){
$required_fields['certified_age_range'] = 'Age';
return $required_fields;
}
add_filter( 'woocommerce_customer_meta_fields', 'misha_admin_age_range_field' );
function misha_admin_age_range_field( $admin_fields ) {
$admin_fields['billing']['fields']['certified_age_range'] = array(
'label' => 'Age',
'description' => 'Get Certified Form Field',
);
return $admin_fields;
}
The code above works perfectly, and this is how the 'Age' field appears on the page:
But now I need to make this field into a dropdown one instead of a simple text field.
This said, I tried doing the above customisation with the following code but without the desired result. Any advice?
add_filter( 'woocommerce_save_account_details_required_fields' , 'custom_override_age_field' );
function custom_override_age_field( $account_fields ) {
$option_age = array(
'' => __( 'Select your Age Range' ),
'18-24' => '18-24',
'25-34' => '25-34',
'35-44' => '35-44',
'45-54' => '45-54',
'55-64' => '55-64',
'65+' => '65+',
);
$account_fields['account_first_name']['type'] = 'select';
$account_fields['account_first_name']['options'] = $option_age;
return $account_fields;
}
Your code says: Step 1. Add your field - in your attempt you are using the hook from step 3.. while step 3 indicates Make it required so that's your first mistake.
The bottom line is that in the first step you have to edit the woocommerce_form_field settings. In your code the type is 'text' and you have to change this to 'select'.
So you get:
/**
* Step 1. Add your field - Age Range
*/
function action_woocommerce_edit_account_form() {
echo "<h4> Please fill in the following details to complete your profile for review </h4>";
// Select field
woocommerce_form_field( 'certified_age_range', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Your age', 'woocommerce' ),
'required' => true, // remember, this doesn't make the field required, just adds an "*"
'options' => array(
'' => __( 'Select your age range', 'woocommerce' ),
'18-24' => '18-24',
'25-34' => '25-34',
'35-44' => '35-44',
'45-54' => '45-54',
'55-64' => '55-64',
'65+' => '65+',
)
), get_user_meta( get_current_user_id(), 'certified_age_range', true ) );
}
add_action( 'woocommerce_edit_account_form', 'action_woocommerce_edit_account_form', 10, 0 );
/**
* Step 2. Make it required
*/
function filter_woocommerce_save_account_details_required_fields( $required_fields ) {
$required_fields['certified_age_range'] = __( 'Age', 'woocommerce' );
return $required_fields;
}
add_filter( 'woocommerce_save_account_details_required_fields', 'filter_woocommerce_save_account_details_required_fields', 10, 1 );
/**
* Step 3. Save field value
*/
function action_woocommerce_save_account_details( $user_id ) {
if ( isset( $_POST['certified_age_range'] ) ) {
// Update field
update_user_meta( $user_id, 'certified_age_range', sanitize_text_field( $_POST['certified_age_range'] ) );
}
}
add_action( 'woocommerce_save_account_details', 'action_woocommerce_save_account_details', 10, 1 );
/**
* Step 4. Get address fields for the edit user pages.
*/
function filter_woocommerce_customer_meta_fields( $args ) {
$args['billing']['fields']['certified_age_range'] = array(
'label' => __( 'Age', 'woocommerce' ),
'description' => __( 'Get Certified Form Field', 'woocommerce' ),
);
return $args;
}
add_filter( 'woocommerce_customer_meta_fields', 'filter_woocommerce_customer_meta_fields', 10, 1 );
Related
I want to hide specific products, based on product category for users under the age of 18.
So if the user is not logged in, or if logged in but under the age of 18 years old (date of birth will be set during check out), these products should be hidden on WooCommerce shop and archive pages.
Via code I found online, and trial and error, this is my code attempt:
add_filter( 'woocommerce_product_categories_hide_empty', 'hide_empty_categories' );
function hide_empty_categories( $hide_empty ) {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
$age = (int) $current_user->user_age;
if ( $age < 18 ) {
$hide_empty = true;
}
}
return $hide_empty;
}
Unfortunately without the desired result. Any advice?
To add the birthday field, I use:
function new_add_custom_checkbox_fields() {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if ($chosen_shipping != 'free_shipping:2'){
add_filter('woocommerce_checkout_fields', function($fields) {
$fields['billing']['billing_date_intervention'] = [
'label' => __('date du jour', 'textdomain'),
'required' => true,
'type' => 'text',
'default' => date("d/m/Y"),
'class' => ['wooccm-required-field'],
'priority' => 125
];
$fields['billing']['billing_date_naissance'] = [
'label' => __('date de naissance', 'textdomain'),
'required' => true,
'type' => 'date',
'class' => ['wooccm-required-field'],
'id' => 'date_of_birth',
'priority' => 70
];
return $fields;
});
}
}
add_action('woocommerce_billing_fields', 'new_add_custom_checkbox_fields');
/**
* Ajout et mise à jour des champs dans la base de donnée
*/
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['billing_date_intervention'] ) ) {
add_post_meta( $order_id, '_billing_date_intervention', sanitize_text_field( $_POST['billing_date_intervention'] ) );
}
if ( ! empty( $_POST['billing_date_naissance'] ) ) {
add_post_meta( $order_id, '_billing_date_naissance', sanitize_text_field( $_POST['billing_date_naissance'] ) );
}
}
If you want to determine the age, it is first and foremost important to make a field available in WooCommerce, so that a user can enter his date of birth
An important note is that you should save data as user_meta and not as post_meta
So to add and save the field, use:
// Display billing birthdate field to checkout and my account addresses
function filter_woocommerce_billing_fields( $fields ) {
$fields['billing_birthdate'] = array(
'type' => 'date',
'label' => __( 'Birthdate', 'woocommerce' ),
'class' => array( 'form-row-wide' ),
'priority' => 25,
'required' => true,
'clear' => true,
);
return $fields;
}
add_filter( 'woocommerce_billing_fields', 'filter_woocommerce_billing_fields', 10, 1 );
// Save/update user data from custom field value
function action_woocommerce_checkout_update_customer( $customer, $data ) {
// Isset
if ( isset( $_POST['billing_birthdate'] ) ) {
$customer->update_meta_data( 'billing_birthdate', sanitize_text_field( $_POST['billing_birthdate'] ) );
}
}
add_action( 'woocommerce_checkout_update_customer', 'action_woocommerce_checkout_update_customer', 10, 2 );
To hide the desired products, belonging to certain categories in frontend, based on age. You can then use the woocommerce_product_query_tax_query hook.
So you get:
function filter_woocommerce_product_query_tax_query( $tax_query, $query ) {
// The desired product category slug(s)
$categories = array( 'categorie-1', 'categorie-2' );
// Initialize
$flag = true;
// Logged in (not logged in, hide products by default)
if ( is_user_logged_in() ) {
// Get user ID
$user_id = get_current_user_id();
// Get meta
$billing_birthdate = get_user_meta( $user_id, 'billing_birthdate', true );
// NOT empty (when empty, hide products by default)
if ( ! empty( $billing_birthdate ) ) {
// Older than 18
if ( time() > strtotime ( '+18 years', strtotime( $billing_birthdate ) ) ) {
$flag = false;
}
}
}
// When true
if ( $flag ) {
$tax_query[] = array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $categories,
'operator' => 'NOT IN'
);
}
return $tax_query;
}
add_filter( 'woocommerce_product_query_tax_query', 'filter_woocommerce_product_query_tax_query', 10, 2 );
We needed another field in our products for Prod ref/Cat numbers and I found the bit of code below which works perfectly.
I now need to add a second field for Nominal Codes used by the accountants software.
I tried using the below code again, adjusted for the new field, but it didn't work.
function jk_add_custom_sku() {
$args = array(
'label' => __( 'Custom SKU', 'woocommerce' ),
'placeholder' => __( 'Enter custom SKU here', 'woocommerce' ),
'id' => 'jk_sku',
'desc_tip' => true,
'description' => __( 'This SKU is for internal use only.', 'woocommerce' ),
);
woocommerce_wp_text_input( $args );
}
add_action( 'woocommerce_product_options_sku', 'jk_add_custom_sku' );
function jk_save_custom_meta( $post_id ) {
// grab the SKU value
$sku = isset( $_POST[ 'jk_sku' ] ) ? sanitize_text_field( $_POST[ 'jk_sku' ] ) : '';
// grab the product
$product = wc_get_product( $post_id );
// save the custom SKU meta field
$product->update_meta_data( 'jk_sku', $sku );
$product->save();
}
add_action( 'woocommerce_process_product_meta', 'jk_save_custom_meta' );
Adding extra fields can be done in a very simple way:
function jk_add_custom_sku() {
$args_1 = array(
'label' => __( 'Custom SKU', 'woocommerce' ),
'placeholder' => __( 'Enter custom SKU here', 'woocommerce' ),
'id' => 'jk_sku',
'desc_tip' => true,
'description' => __( 'This SKU is for internal use only.', 'woocommerce' ),
);
woocommerce_wp_text_input( $args_1 );
// Extra field
$args_2 = array(
'label' => __( 'Nominal codes', 'woocommerce' ),
'placeholder' => __( 'Enter nominal codes here', 'woocommerce' ),
'id' => '_nominal_codes',
'desc_tip' => true,
'description' => __( 'This is for nominal codes.', 'woocommerce' ),
);
woocommerce_wp_text_input( $args_2 );
}
add_action( 'woocommerce_product_options_sku', 'jk_add_custom_sku' );
// Save
function jk_save_custom_meta( $product ){
if( isset($_POST['jk_sku']) ) {
$product->update_meta_data( 'jk_sku', sanitize_text_field( $_POST['jk_sku'] ) );
}
// Extra field
if( isset($_POST['_nominal_codes']) ) {
$product->update_meta_data( '_nominal_codes', sanitize_text_field( $_POST['_nominal_codes'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'jk_save_custom_meta', 10, 1 );
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 need to add more columns to the WooCommerce > Reports under the Customer tab called Customer List.
I want to add columns address (billing_address_1), building number (billing_billing_number), city (billing_city), state(billing_state) and a custom field in my form called Apartment Complex (apt_complex).
How can I do this?
this is kind of near hard. But you can do it this way. This is the closest I can get.
create a filter to woocommerce_admin_reports. Specifically, we need to change the callback of the customer list reports. Below it's 'customer_list_get_report'.
add_filter( 'woocommerce_admin_reports', 'woocommerce_admin_reports' );
function woocommerce_admin_reports( $reports ) {
$reports['customers']['reports']['customer_list']['callback'] = 'customer_list_get_report';
return $reports;
}
then create the function 'customer_list_get_report'. This function generates the reports. Take note of the do_action, this is where we include the class WC_Report_Customer_List for us to be able to extend to it and overwrite some of it's functions.
function customer_list_get_report( $name ) {
$class = 'My_WC_Report_Customer_List';
do_action('class_wc_report_customer_list');
if ( ! class_exists( $class ) )
return;
$report = new $class();
$report->output_report();
}
This, below, is where you make your edits.
add_action( 'class_wc_report_customer_list', 'class_wc_report_customer_list' );
function class_wc_report_customer_list() {
if ( ! class_exists( 'WC_Report_Customer_List' ) ) {
include_once( WC_ABSPATH . 'includes/admin/reports/class-wc-report-customer-list.php' );
}
class My_WC_Report_Customer_List extends WC_Report_Customer_List {
/**
* Get column value.
*
* #param WP_User $user
* #param string $column_name
* #return string
*/
public function column_default( $user, $column_name ) {
global $wpdb;
switch ( $column_name ) {
case 'city' :
return get_user_meta( $user->ID, 'billing_city', true );
}
return parent::column_default( $user, $column_name );
}
/**
* Get columns.
*
* #return array
*/
public function get_columns() {
/* default columns.
$columns = array(
'customer_name' => __( 'Name (Last, First)', 'woocommerce' ),
'username' => __( 'Username', 'woocommerce' ),
'email' => __( 'Email', 'woocommerce' ),
'location' => __( 'Location', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ),
'spent' => __( 'Money spent', 'woocommerce' ),
'last_order' => __( 'Last order', 'woocommerce' ),
'user_actions' => __( 'Actions', 'woocommerce' ),
); */
// sample adding City next to Location.
$columns = array(
'customer_name' => __( 'Name (Last, First)', 'woocommerce' ),
'username' => __( 'Username', 'woocommerce' ),
'email' => __( 'Email', 'woocommerce' ),
'location' => __( 'Location', 'woocommerce' ),
'city' => __( 'City', 'woocommerce' ),
);
return array_merge( $columns, parent::get_columns() );
}
}
}
I added City for you as an example. You can do the others you needed.
It will look something like this:
As you can see, the City column has been added.
In my account page,
I want to use a similar code as below to sell in a specific "cities" or "postcodes", the below code is used to sell in a specific "states":
/**
* Sell only in Alger & Zeralda
*/
function wc_sell_only_states( $states ) {
$states['DZ'] = array(
'ALG' => __( 'Alger', 'woocommerce' ),
'ZLD' => __( 'Zeralda', 'woocommerce' ),
);
return $states;
}
add_filter( 'woocommerce_states', 'wc_sell_only_states' );
What shall I use or modify?
I tried this, but it displays "Error code 500":
// define the woocommerce_countries_base_city callback
function filter_woocommerce_countries_base_city( $var ) {
// make filter magic happen here...
$var['DZ'] = array(
'ALG' => __( 'Alger', 'woocommerce' ),
'ZLD' => __( 'Zeralda', 'woocommerce' ),
);
return $var;
};
// add the filter
add_filter( 'woocommerce_countries_base_city', 'filter_woocommerce_countries_base_city', 10, 1 );
Thank you in advanced!
Try This it worked for me!!
add_filter( 'woocommerce_form_field_args', 'custom_form_field_args', 10, 3 );
function custom_form_field_args( $args, $key, $value ) {
if ( $args['id'] == 'billing_city' ) {
$args = array(
'label' => __( 'Town / City', 'woocommerce' ),
'required' => TRUE,
'clear' => TRUE,
'type' => 'select',
'options' => array(
'' => ('Select City' ),
'Bangalore' => ('Bangalore' ),
'Mysore' => ('Mysore' )
),
'class' => array( 'update_totals_on_change' )
);
} // elseif … and go on
return $args;
};
There is a simpler solution to this. The approach also depends on the some assumption which are listed below:
Assumption : If there is only one City which you want the City field to be set to then you can use jQuery. Using jQuery you will be setting the value of the field and make the fields disabled to avoid change in City field value.
A rough example will be :
jQuery('#billing_city').val('USA').attr('disabled','disabled');
You just need to add this line such that it is execute on Checkout page.