Reputation: 65
I have a custom WooCommerce payment gateway that saves metadata using:
$order->update_meta_data('_example_data', esc_attr($_POST['_example_data']));
.
And is then displayed in the admin order page, and made editable, using the following:
// In constructor
add_action('woocommerce_admin_order_data_after_order_details', array($this, 'display_payment_type_order_edit_pages'), 10, 1);
add_action('woocommerce_process_shop_order_meta', array($this, 'save_order_custom_field_meta'));
public function display_payment_type_order_edit_pages($order) {
$example_data = $order->get_meta('_example_data');
echo '<br class="clear" />';
echo '<h4>Example Details <a href="#" class="edit_address">Edit</a></h4>';
// Non-edit display.
echo '<div class="address">';
echo '<p><strong>' . __('Example Data') . ':</strong> ' . $example_data . '</p>';
echo '</div>';
echo '<div class="edit_address">';
woocommerce_wp_text_input(array(
'id' => '_example_data',
'label' => 'Example Data:',
'value' => $example_data,
'wrapper_class' => 'form-field-wide'
));
echo '</div>';
}
function save_order_custom_field_meta($post_id) {
if (isset($_POST['_example_data']))
update_post_meta($post_id, '_example_data', sanitize_text_field($_POST['_example_data']));
}
The metadata saves correctly from the checkout, it's displayed correctly and the fields come up when you start to edit. However, the metadata doesn't seem to be saving after editing the order.
Any help would be appreciated!
Edit: I noticed some strange interactions while trialing some other features on a clean install of WP and WC, and I narrowed it down (kinda) to the class not being instantiated in the traditional way.
i.e. I am doing it like this:
add_action('plugins_loaded', 'init_my_payment_gateway', 11);
function init_my_payment_gateway()
{
class My_Payment_Gateway extends WC_Payment_Gateway
{
// Rest of plugin here.
As apposed to the regular way of:
$my_class = new My_Payment_Gateway();
Additionally, I have also found that adding that action like so
add_action('woocommerce_process_shop_order_meta', array('my_payment_gateway', 'save_order_custom_field_meta'));
executes the function when the hook is fired; with an error of course (running non-static in a static way). So it seems adding the action within the plugin file causes it not to work?
Finally, if I see what functions are attached to the hook using $wp_filter['woocommerce_process_shop_order_meta'];
I can actually see that save_order_custom_field_meta
is attached. Yet it does not execute when the hook is run (confirmed with logging, breakpoints, etc).
Upvotes: 2
Views: 1319
Reputation: 254038
Your code first function doesn't display your editable field and you are making things more complicated than they should be. Try the following instead:
add_action( 'woocommerce_admin_order_data_after_order_details', 'display_custom_editable_field_on_admin_orders' );
function display_custom_editable_field_on_admin_orders( $order ) {
echo '<br class="clear" />
<div class="example_data_wrapper">';
woocommerce_wp_text_input( array(
'id' => '_example_data',
'label' => __('Example Data:'),
'wrapper_class' => 'form-field-wide'
) );
echo '</div>';
}
add_action( 'woocommerce_process_shop_order_meta', 'save_order_custom_field_meta' );
function save_order_custom_field_meta( $post_id ) {
if ( isset($_POST['_example_data']) )
update_post_meta( $post_id, '_example_data', sanitize_text_field($_POST['_example_data']) );
}
Code goes on functions.php file of your active child theme (or active theme). Tested and works.
If you want to use the code in a plugin within a Class, you can use the following in a plugin file:
/*
Plugin Name: Admin Order Editable field
Plugin URI:
Description: Your shipping method plugin
Version: 1.0.0
Author: Me
Author URI:
*/
if ( ! class_exists( 'WC_Some_Class' ) ) {
class WC_Some_Class {
// In the constructor
public function __construct() {
# Your settings below to be defined
$this->text_domain = 'my_text_domain'; // The domain name
$this->meta_key = '_example_data'; // The field Id or field slug
$this->label_name = __('Example Data', $this->text_domain ); // Field label
# The hooks to be triggered
add_action( 'woocommerce_admin_order_data_after_order_details', array( $this, 'display_custom_editable_field_on_admin_orders' ) );
add_action( 'woocommerce_process_shop_order_meta', array( $this, 'save_order_custom_field_meta' ) );
}
// Outside the constructor
public function display_custom_editable_field_on_admin_orders( $order ) {
echo '<br class="clear" />
<div class="example_data_wrapper">';
woocommerce_wp_text_input( array(
'id' => $this->meta_key,
'label' => $this->label_name . ':',
'wrapper_class' => 'form-field-wide'
) );
echo '</div>';
}
public function save_order_custom_field_meta( $post_id ) {
if ( isset($_POST[$this->meta_key]) )
update_post_meta( $post_id, '_example_data', sanitize_text_field($_POST[$this->meta_key]) );
}
}
$some_class = new WC_Some_Class();
}
Tested and works.
Upvotes: 3