Wordpress REST API reading post meta but not updating - wordpress

I am trying to create a PowerApp in which I want to integrate the post meta fields. I inserted this code in the functions.php file. But I can read and write the data for default WordPress fields, but I am not able to update the post custom fields.
add_action( 'rest_api_init', 'create_api_posts_meta_field' );
function create_api_posts_meta_field() {
// register_rest_field ( 'name-of-post-type', 'name-of-field-to-return', array-of-callbacks-and-schema() )
register_rest_field( 'post', 'post-meta-fields', array(
'get_callback' => 'get_post_meta_for_api',
'update_callback' => 'get_post_meta_update_for_api',
'schema' => null,
)
);
}
function get_post_meta_for_api( $object ) {
//get the id of the post object array
$post_id = $object['id'];
//return the post meta
return get_post_meta( $post_id );
}
function get_post_meta_update_for_api( $value, $object, $field_name ) {
return update_post_meta( $object[ 'id' ], $field_name, $value );
}

Related

Add custom field to product inventory tab and display value on single product page where meta ends

I'm using the following code in my theme functions.php file to add a additional data field to the product inventory tab:
// Add Custom Field to woocommerce inventory tab for product
add_action('woocommerce_product_options_inventory_product_data', function() {
woocommerce_wp_text_input([
'id' => '_number_in_package',
'label' => __('Number of Pages', 'txtdomain'),
'type' => 'number',
]);
});
add_action('woocommerce_process_product_meta', function($post_id) {
$product = wc_get_product($post_id);
$num_package = isset($_POST['_number_in_package']) ? $_POST['_number_in_package'] : '';
$product->update_meta_data('_number_in_package', sanitize_text_field($num_package));
$product->save();
});
add_action('woocommerce_product_meta_start', function() {
global $post;
$product = wc_get_product($post->ID);
$num_package = $product->get_meta('_number_in_package');
if (!empty($num_package)) {
printf('<div class="custom-sku">%s: %s</div>', __('Number of Pages', 'txtdomain'), $num_package);
}
});
add_filter('woocommerce_product_data_tabs', function($tabs) {
$tabs['additional_info'] = [
'label' => __('Additional info', 'txtdomain'),
'target' => 'additional_product_data',
'class' => ['hide_if_external'],
'priority' => 25
];
return $tabs;
});
However, on the single product page, the custom field is added before category and ISBN. I want to place the custom field at the end after the product ISBN. Any advice?
Some comments/suggestions regarding your code attempt
To save fields you can use the woocommerce_admin_process_product_object hook, opposite the outdated woocommerce_process_product_meta hook
WooCommerce contains by default no ISBN field, but it looks like the woocommerce_product_meta_end hook will answer your question
So you get:
// Add custom field
function action_woocommerce_product_options_inventory_product_data() {
woocommerce_wp_text_input( array(
'id' => '_number_in_package',
'label' => __( 'Number of Pages', 'woocommerce' ),
'description' => __( 'This is a custom field, you can write here anything you want.', 'woocommerce' ),
'desc_tip' => 'true',
'type' => 'number'
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data' );
// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset
if ( isset( $_POST['_number_in_package'] ) ) {
// Update
$product->update_meta_data( '_number_in_package', sanitize_text_field( $_POST['_number_in_package'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Display on single product page
function action_woocommerce_product_meta_end() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get meta
$number = $product->get_meta( '_number_in_package' );
// NOT empty
if ( ! empty ( $number ) ) {
echo '<p>' . $number . '</p>';
}
}
}
add_action( 'woocommerce_product_meta_end', 'action_woocommerce_product_meta_end', 10 );

Woocommerce Rest APi get custom meta field

I'm trying to pull a products custom meta and custom taxonomy value from woocommerce using the rest api. But no matter what I try a can't seem to get it to work. Not sure what I'm missing.
Example, my products have a custom meta value "product_location". The post meta value exists and works because I can use this to pull the value into the woocommerce product page:
get_post_meta($product->get_id(), 'product_location', true );
In my functions.php file I've added:
add_action( 'rest_api_init', 'handle_location' );
function handle_location() {
register_rest_field( 'post', 'product_location', array(
'get_callback' => array( $this, 'get_the_product_location' ),
'schema' => null
));
}
function get_the_product_location( $post, $field_name, $request ) {
return get_post_meta( $post[ 'id' ], $field_name, true );
}
However, when I make a call say https://*******.com/wc-api/v2/products/302341/ the meta data isn't included. So basically how can I include the additional meta data? I plan on trying this for a custom taxonomy as well. Any help is appreciated - Thanks
Try changing your bottom function to
function get_the_product_location( $post, $field_name, $request ) {
return get_post_meta( $post[ 'id' ], 'product_location', $meta_value );
}

Updating custom product meta box field - WooCommerce

I'm trying to update a custom product meta box field using the updating system from WooCommerce core. Here is my code:
The new field Shipping info
add_action( 'woocommerce_product_options_shipping', 'my_product_options_shipping' );
function my_product_options_shipping() {
global $post;
$shipping_info = get_post_meta( $post->ID, '_shipping_info', true );
woocommerce_wp_text_input(
array(
'id' => '_shipping_info',
'value' => $shipping_info,
'label' => __( 'Shipping info', 'woocommerce' ),
'placeholder' => __( 'Shipping in two days', 'woocommerce' ),
)
);
}
And this is the function that adds the new field as prop in WC_Meta_Box_Product_Data::save
add_action( 'woocommerce_admin_process_product_object', 'my_admin_process_product_object' );
function my_admin_process_product_object( $product ) {
$product->set_props(
array(
'shipping_info' => isset( $_POST['_shipping_info'] ) ? wc_clean( wp_unslash( $_POST['_shipping_info'] ) ) : null,
)
);
}
I think I'm missing a step. Shouldn't it be saved automatically from function WC_Meta_Box_Product_Data::save which is attached to woocommerce_process_product_meta?
EDIT
I found the missing step. I need to add my custom post meta in the protected array $extra_data from abstract class WC_Data.
I'm not too good at OOP, so how I can access that array to push my custom data?
I can see you're just doing $shipping_info = get_post_meta( $post->ID, '_shipping_info', true );
So why not save the trouble and just use update_post_meta
add_action( 'woocommerce_admin_process_product_object', 'my_admin_process_product_object' );
function my_admin_process_product_object( $product ) {
update_post_meta($product->get_id(), '_shipping_info', wc_clean( wp_unslash( $_POST['_shipping_info'] ) ) );
}

WP API V2: Query posts by ACF

I would like to query my posts by filtering for a custom meta added with Advanced Custom Fields. It's a boolean meta, so every post will have something like:
GET http://localhost/wp-json/wp/v2/posts
{
...
"acf" : {
"highlight" : true
}
...
}
I'm not able to filter by this meta value, even if I exposed meta_key and meta_value to the REST API in function.php:
function my_add_meta_vars ($current_vars) {
$current_vars = array_merge ($current_vars, array ('meta_key', 'meta_value'));
return $current_vars;
}
add_filter ('rest_query_vars', 'my_add_meta_vars');
But if I try:
GET
http://localhost/wp-json/wp/v2/posts?filter[meta_key]=highlight&filter[meta_value]=true
I see all the posts as if the filter is ignored.
I was able to get this solved with this customization:
add_filter( 'rest_query_vars', function ( $valid_vars ) {
return array_merge( $valid_vars, array( 'highlight', 'meta_query' ) );
} );
add_filter( 'rest_post_query', function( $args, $request ) {
$highlight = $request->get_param( 'highlight' );
if ( ! empty( $highlight ) ) {
$args['meta_query'] = array(
array(
'key' => 'highlight',
'value' => $highlight,
'compare' => '=',
)
);
}
return $args;
}, 10, 2 );
And do a query in this way (highlight is acf boolean)
GET /wp-json/wp/v2/posts?highlight=1

Update user meta after woocommerce checkout form process

I am using woocommerce with Wordpress and have added some custom fields to the checkout:
add_action('woocommerce_after_order_notes', 'my_custom_checkout_field');
function my_custom_checkout_field( $checkout ) {
$extra_fields = array('job_title', 'company', 'telephone', 'occupation');
foreach($extra_fields as $key => $value) {
woocommerce_form_field($value, array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __($label),
'value' => '',
), $checkout->get_value( $value ));
}
}
Now currently, these appear in the checkout fine, not sure if using woocommerce_after_order_notes is right in this case. I have also added some custom fields to the user meta that correspond to the fields added to the checkout - which all display in the user profile page:
function add_contact_methods( $contactmethods ) {
$contactmethods['job_title'] = 'Job Title';
$contactmethods['company'] = 'Company Name';
$contactmethods['telephone'] = 'Telephone';
$contactmethods['occupation'] = 'Occupation';
$contactmethods['refer'] = 'How you heard about us?';
return $contactmethods;
}
add_filter('user_contactmethods','add_contact_methods',10,1);
As you can imagine, if I update any of these field in any profile page, it works fine but what I cant seem to do is update the user meta when a new user makes a purchase, it does not update the user meta for these fields in the database.
I understand alot of how this works, and understand that I must hook into a Woocommerce process to add the fields into the process. So I have added this code into my functions too:
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta');
function my_custom_checkout_field_update_user_meta( $user_id ) {
global $extra_fields;
foreach($extra_fields as $key => $value) {
if ($_POST[$value]) update_user_meta( $user_id, $value, esc_attr($_POST[$value]));
}
}
Now the twist is, this works if a user who is already signed in as a member, makes a repurchase and goes through the checkout - the reason this works is because $user_id already exists, but when a new user is checking out, they do not yet exist as a user, hence the function cannot update the user meta of NIL where $user_id does not exist.
My question is, how do I hook into the checkout process, presumably AFTER the user has been created, so I that I can get the $user_id returned, and execute this function to update the user meta.
class-wc-checkout.php line 639 creates the new user with $this->customer_id = wp_insert_user( apply_filters( 'woocommerce_new_customer_data', $new_customer_data ) ); The new customer data is an array listed just above that line.
Following that, you can access the user id with line 649's action do_action( 'woocommerce_created_customer', $this->customer_id );
It is unlikey, in your case, you will need to use the filter, but simply add the action 'woocommerce_created_customer', pull in the id, and add the meta.
When customer is not logged in checkout page should be acceptable field customer want to create a new account.Below sample code change in checkout page when customer order a new item and update user meta data.
function user_extra_meta_fields(){
return array(
'job_title' => __( 'Job Title', 'yourtext_domain'),
'company' => __( 'Company Name', 'yourtext_domain'),
'telephone' => __( 'Telephone', 'yourtext_domain'),
'occupation' => __( 'Occupation', 'yourtext_domain'),
'refer' => __( 'How you heard about us?', 'yourtext_domain'),
);
}
function add_contact_methods( $contactmethods ) {
$contactmethods = array_merge( $contactmethods, user_extra_meta_fields());
return $contactmethods;
}
add_filter('user_contactmethods','add_contact_methods',10,1);
add_action('woocommerce_after_order_notes', 'my_custom_checkout_field');
function my_custom_checkout_field( $checkout ) {
foreach( user_extra_meta_fields() as $name => $label) {
$value = '';
if( is_user_logged_in() )
$value = get_user_meta( get_current_user_id(), $name, true );
woocommerce_form_field( $name, array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => $label,
), $value );
}
}
add_action( 'woocommerce_checkout_process', 'user_fields_woocommerce_checkout_process' );
function user_fields_woocommerce_checkout_process(){
if( is_user_logged_in() )
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta' );
else
add_action( 'woocommerce_created_customer', 'my_custom_checkout_field_update_user_meta' );
}
function my_custom_checkout_field_update_user_meta( $user_id ) {
foreach( array_keys( user_extra_meta_fields() ) as $meta_name ){
if( isset( $_POST[$meta_name] ) ){
$meta_value = $_POST[$meta_name] ? esc_attr($_POST[$meta_name]) : '';
update_user_meta( $user_id, $meta_name, $meta_value );
}
}
}
// if want to validate field
add_action( 'woocommerce_after_checkout_validation', 'user_fields_woocommerce_after_checkout_validation' );
function user_fields_woocommerce_after_checkout_validation( $posted ){
$validate = true;
if( ! is_user_logged_in() && empty( $posted['createaccount'] ) )
$validate = false;
if( $validate == false )
return;
$meta_data = user_extra_meta_fields();
foreach( array_keys( $meta_data ) as $meta_name ){
if( empty($_POST[$meta_name]) )
wc_add_notice( sprintf( __(' <strong>%s</strong> is required.', 'yourtext_domain'), $meta_data[$meta_name] ), 'error' );
}
}

Resources