Customize the WordPress Woocommerce billing address edit forms
https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/
隱藏欄位範例:
So what I did is to add the following filter to the function.php page, for example I will hide the zip code fields, first you need to make it non required, and then hide it as follow:
add_filter( 'woocommerce_billing_fields', 'wc_npr_filter_postcode');
function wc_npr_filter_postcode( $address_fields ) {
$address_fields['billing_postcode']['required'] = false;
$address_fields['billing_postcode']['type'] = 'hidden';
return $address_fields;
}
調整「顯示」順序範例:
add_filter( ‘woocommerce_localisation_address_formats’ , ‘woo_tw_address_formats’ );
function woo_tw_address_formats() {
$address = array(‘default’ => “{first_name}\n{state}{city} ({postcode})\n{address_1}”);
return $address;
}
解法只剩下,欄位全部打掉,換上自己的欄位,就解決了。 @_@;
看了一下 source code:
includes/wc-template-functions.php
原來可以直接改 ‘priority’:
$label_id = $args['id']; $sort = $args['priority'] ? $args['priority'] : ''; $field_container = '<p class="form-row %1$s" id="%2$s" data-sort="' . esc_attr( $sort ) . '">%3$s</p>';
改了,沒有效果。
找到了優秀範例:
WooCommerce Customize Checkout Fields
https://www.kathyisawesome.com/woocommerce-customize-checkout-fields/
https://cloudwp.pro/blog/woocommerce-%E7%B8%A3%E5%B8%82%E6%AC%84%E4%BD%8D%E4%B8%8B%E6%8B%89%E9%81%B8%E5%96%AE/
Customizing checkout fields using actions and filters should be a task you are comfortable with.
If you are unfamiliar with code and resolving potential conflicts, we have an extension that can help: WooCommerce Checkout Field Editor. Installing and activating this extension overrides any code below that you try to implement; and you cannot have custom checkout field code in your functions.php file when the extension is activated.
MARKDOWN_HASH78cd5aa3783a74555c9938a2a81d01c6MARKDOWN_HASH
file.How are checkout fields loaded to WooCommerce?
The billing and shipping fields for checkout pull from the countries class (class-wc-countries.php
) and the get_address_fields
function. This allows WooCommerce to enable/disable fields based on the user’s location.
Before returning these fields, WooCommerce puts the fields through a filter. This allows them to be edited by third-party plugins, themes and your own custom code.
Billing:
$address_fields = apply_filters('woocommerce_billing_fields', $address_fields);
Shipping:
$address_fields = apply_filters('woocommerce_shipping_fields', $address_fields);
The checkout class adds the loaded fields to its ‘checkout_fields’ array, as well as adding a few other fields like “order notes”.
$this->checkout_fields['billing'] = $woocommerce->countries->get_address_fields( $this->get_value('billing_country'), 'billing_' ); $this->checkout_fields['shipping'] = $woocommerce->countries->get_address_fields( $this->get_value('shipping_country'), 'shipping_' ); $this->checkout_fields['account'] = array( 'account_username' => array( 'type' => 'text', 'label' => __('Account username', 'woocommerce'), 'placeholder' => _x('Username', 'placeholder', 'woocommerce') ), 'account_password' => array( 'type' => 'password', 'label' => __('Account password', 'woocommerce'), 'placeholder' => _x('Password', 'placeholder', 'woocommerce'), 'class' => array('form-row-first') ), 'account_password-2' => array( 'type' => 'password', 'label' => __('Account password', 'woocommerce'), 'placeholder' => _x('Password', 'placeholder', 'woocommerce'), 'class' => array('form-row-last'), 'label_class' => array('hidden') ) ); $this->checkout_fields['order'] = array( 'order_comments' => array( 'type' => 'textarea', 'class' => array('notes'), 'label' => __('Order Notes', 'woocommerce'), 'placeholder' => _x('Notes about your order, e.g. special notes for delivery.', 'placeholder', 'woocommerce') ) );
This array is also passed through a filter:
$this->checkout_fields = apply_filters('woocommerce_checkout_fields', $this->checkout_fields);
That means you have full control over checkout fields – you only need to know how to access them.
Overriding core fields
Hooking into the woocommerce_checkout_fields
filter lets you override any field. As an example, let’s change the placeholder on the order_comments fields. Currently, it’s set to:
_x('Notes about your order, e.g. special notes for delivery.', 'placeholder', 'woocommerce')
We can change this by adding a function to our theme functions.php file:
// Hook in add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' ); // Our hooked in function - $fields is passed via the filter! function custom_override_checkout_fields( $fields ) { $fields['order']['order_comments']['placeholder'] = 'My new placeholder'; return $fields; }
You can override other parts, such as labels:
// Hook in add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' ); // Our hooked in function - $fields is passed via the filter! function custom_override_checkout_fields( $fields ) { $fields['order']['order_comments']['placeholder'] = 'My new placeholder'; $fields['order']['order_comments']['label'] = 'My new label'; return $fields; }
Or remove fields:
// Hook in add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' ); // Our hooked in function - $fields is passed via the filter! function custom_override_checkout_fields( $fields ) { unset($fields['order']['order_comments']); return $fields; }
Here’s a full list of fields in the array passed to woocommerce_checkout_fields
:
- Billing
billing_first_name
billing_last_name
billing_company
billing_address_1
billing_address_2
billing_city
billing_postcode
billing_country
billing_state
billing_email
billing_phone
- Shipping
shipping_first_name
shipping_last_name
shipping_company
shipping_address_1
shipping_address_2
shipping_city
shipping_postcode
shipping_country
shipping_state
- Account
account_username
account_password
account_password-2
- Order
order_comments
Each field contains an array of properties:
type
– type of field (text, textarea, password, select)label
– label for the input fieldplaceholder
– placeholder for the inputclass
– class for the inputrequired
– true or false, whether or not the field is requireclear
– true or false, applies a clear fix to the field/labellabel_class
– class for the label elementoptions
– for select boxes, array of options (key => value pairs)
In specific cases you need to use the woocommerce_default_address_fields
filter. This filter is applied to all billing and shipping default fields:
country
first_name
last_name
company
address_1
address_2
city
state
postcode
For example, to make the address_1
field optional:
// Hook in add_filter( 'woocommerce_default_address_fields' , 'custom_override_default_address_fields' ); // Our hooked in function - $address_fields is passed via the filter! function custom_override_default_address_fields( $address_fields ) { $address_fields['address_1']['required'] = false; return $address_fields; }
Defining select options
If you are adding a field with type ‘select’, as stated above you would define key/value pairs. For example:
$fields['billing']['your_field']['options'] = array( 'option_1' => 'Option 1 text', 'option_2' => 'Option 2 text' );
Priority
Priority in regards to PHP code helps establish when a bit of code — called a function — runs in relation to a page load. It is set inside of each function and is useful when overriding existing code for custom display.
Code with a higher number set as the priority will run after code with a lower number, meaning code with a priority of 20 will run after code with 10 priority.
The priority argument is set during the add_action function, after you establish which hook you’re connecting to and what the name of your custom function will be.
In the example below, blue text is the name of the hook we’re modifying, green text is the name of our custom function, and red is the priority we set.
Examples
In this example, the code is set to redirect the “Return to Shop” button found in the cart to a category that lists products for sale at http://example.com/category/specials/.
<?php
/**
* Changes the redirect URL for the Return To Shop button in the cart.
*/
function wc_empty_cart_redirect_url() {
return ‘http://example.com/category/specials/’;
}
add_filter( ‘woocommerce_return_to_shop_redirect’, ‘wc_empty_cart_redirect_url’, 10 );
There, we can see the priority is set to 10. This is the typical default for WooCommerce functions and scripts, so that may not be sufficient to override that button’s functionality.
Instead we can change the priority to any number greater than 10. While 11 would work, best practice dictates we use increments of ten, so 20, 30, and so on.
<?php
/**
* Changes the redirect URL for the Return To Shop button in the cart.
*/
function wc_empty_cart_redirect_url() {
return ‘http://example.com/category/specials/’;
}
add_filter( ‘woocommerce_return_to_shop_redirect’, ‘wc_empty_cart_redirect_url’, 20 );
With priority, we can have two functions that are acting on the same hook. Normally this would cause a variety of problems, but since we’ve established one has a higher priority than the other, our site will only load the appropriate function, and we will be taken to the Specials page as intended with the code below.
<?php
/**
* Changes the redirect URL for the Return To Shop button in the cart.
* BECAUSE THIS FUNCTION HAS THE PRIORITY OF 20, IT WILL RUN AFTER THE FUNCTION BELOW (HIGHER NUMBERS RUN LATER)
*/
function wc_empty_cart_redirect_url() {
return ‘http://example.com/category/specials/’;
}
add_filter( ‘woocommerce_return_to_shop_redirect’, ‘wc_empty_cart_redirect_url’, 20 );
/**
* Changes the redirect URL for the Return To Shop button in the cart.
* EVEN THOUGH THIS FUNCTION WOULD NORMALLY RUN LATER BECAUSE IT’S CODED AFTERWARDS, THE 10 PRIORITY IS LOWER THAN 20 ABOVE
*/
function wc_empty_cart_redirect_url() {
return ‘http://example.com/shop/’;
}
add_filter( ‘woocommerce_return_to_shop_redirect’, ‘wc_empty_cart_redirect_url’, 10 );
?>
Adding custom shipping and billing fields
Adding fields is done in a similar way to overriding fields. For example, let’s add a new field to shipping fields – shipping_phone
:
// Hook in
add_filter( ‘woocommerce_checkout_fields’ , ‘custom_override_checkout_fields’ );
// Our hooked in function – $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
$fields[‘shipping’][‘shipping_phone’] = array(
‘label’ => __(‘Phone’, ‘woocommerce’),
‘placeholder’ => _x(‘Phone’, ‘placeholder’, ‘woocommerce’),
‘required’ => false,
‘class’ => array(‘form-row-wide’),
‘clear’ => true
);
return $fields;
}
/**
* Display field value on the order edit page
*/
add_action( ‘woocommerce_admin_order_data_after_shipping_address’, ‘my_custom_checkout_field_display_admin_order_meta’, 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo ‘<p><strong>’.__(‘Phone From Checkout Form’).’:</strong> ‘ . get_post_meta( $order->id, ‘_shipping_phone’, true ) . ‘</p>’;
}
It’s alive!
What do we do with the new field? Nothing. Because we defined the field in the checkout_fields array, the field is automatically processed and saved to the order post meta (in this case, _shipping_phone). If you want to add validation rules, see the checkout class where there are additional hooks you can use.
Adding a custom special field
To add a custom field is similar. Let’s add a new field to checkout, after the order notes, by hooking into the following:
/**
* Add the field to the checkout
*/
add_action( ‘woocommerce_after_order_notes’, ‘my_custom_checkout_field’ );
function my_custom_checkout_field( $checkout ) {
echo ‘<div id=”my_custom_checkout_field”><h2>’ . __(‘My Field’) . ‘</h2>’;
woocommerce_form_field( ‘my_field_name’, array(
‘type’ => ‘text’,
‘class’ => array(‘my-field-class form-row-wide’),
‘label’ => __(‘Fill in this field’),
‘placeholder’ => __(‘Enter something’),
), $checkout->get_value( ‘my_field_name’ ));
echo ‘</div>’;
}
This gives us:
Next we need to validate the field when the checkout form is posted. For this example the field is required and not optional:
/**
* Process the checkout
*/
add_action(‘woocommerce_checkout_process’, ‘my_custom_checkout_field_process’);
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST[‘my_field_name’] )
wc_add_notice( __( ‘Please enter something into this new shiny field.’ ), ‘error’ );
}
A checkout error is displayed if the field is blank:
Finally, let’s save the new field to order custom fields using the following code:
/**
* Update the order meta with field value
*/
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[‘my_field_name’] ) ) {
update_post_meta( $order_id, ‘My Field’, sanitize_text_field( $_POST[‘my_field_name’] ) );
}
}
The field is now saved to the order.
If you wish to display the custom field value on the admin order edition page, you can add this code:
/**
* Display field value on the order edit page
*/
add_action( ‘woocommerce_admin_order_data_after_billing_address’, ‘my_custom_checkout_field_display_admin_order_meta’, 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo ‘<p><strong>’.__(‘My Field’).’:</strong> ‘ . get_post_meta( $order->id, ‘My Field’, true ) . ‘</p>’;
}
This is the result:
Example: Make phone number not required
Adding custom fields to emails
To add a custom field value to WooCommerce emails — a completed order email, for example — use the following snippet:
/* To use:
1. Add this snippet to your theme’s functions.php file
2. Change the meta key names in the snippet
3. Create a custom field in the order post – e.g. key = “Tracking Code” value = abcdefg
4. When next updating the status, or during any other event which emails the user, they will see this field in their email
*/
add_filter(‘woocommerce_email_order_meta_keys’, ‘my_custom_order_meta_keys’);
function my_custom_order_meta_keys( $keys ) {
$keys[] = ‘Tracking Code’; // This will look for a custom field called ‘Tracking Code’ and add it to emails
return $keys;
}