I have an array Im passing to the tax_input argument in wp_insert_post(). Below is a result of printing the wp_insert_post() arguments.
[tax_input] => Array
(
[knpvsoftcomp] => Array
(
[0] => 1530
)
[knpvfiletype] => Array
(
[0] => 1497
)
[product_cat] => Array <-- Woo Product Categories
(
[0] => 821
[1] => 829
[2] => 1530
[3] => 908
)
[pa_designer] => Array
(
[0] => 549
)
)
Here is the function inserting the new post.
$newpostargs = [
'post_type' => 'product',
'post_title' => sanitize_text_field($this->submission['fieldvalues']['product_title']),
'post_author' => $this->currentUser->ID,
'post_content' => $this->submission['fieldvalues']['description'],
'post_status' => 'draft',
'tax_input' => $this->knpv_tax_input(),
'meta_input' => $this->knpv_meta_input()
];
$newpost = wp_insert_post($newpostargs);
Here is the function being called to create the taxonomy array.
public function knpv_tax_input(){
$taxarray = [];
$productcategories = [];
foreach ($this->submission['fieldvalues'] as $key => $value) {
//For product_categories
if (strpos($key, 'cat-parent') !== false || strpos($key, 'catchild-') !== false) {
$productcategories[] = $value;
}
//Software version
if (strpos($key, 'software') !== false) {
$taxarray['knpvsoftcomp'] = [$value];
}
//File Types
if (strpos($key, 'file-compat') !== false) {
$taxarray['knpvfiletype'] = [$value];
}
}
//Add product categories to tax array
$productcategories[] = 908;
$taxarray['product_cat'] = $productcategories;
//Supplier (Vendor) Taxonomy
$taxarray['pa_designer'] = [$this->submission['vendor']['vendor_id']];
return $taxarray;
}
All of these are custom taxonomies expect for the Woo Product Categories. However, these are the only terms being assigned to the post. Any thoughts?
Im admin on the site so all permissions are set right.
Replace '$term_id' to your term ID Hope this help you.
// Creates woocommerce product
$product = array(
'post_title' => $name,
'post_content' => '',
'post_status' => 'publish',
'post_author' => $current_user->ID,
'post_type' =>'product'
);
// Insert the post into the database
$product_ID = wp_insert_post($product);
wp_set_object_terms($product_ID, $term_id, 'product_cat')
;
//you-want-multiple-cat
$categories = [ 'Some Category', 'Some other Category' ];
// Overwrite any existing term
wp_set_object_terms( $product_id, $categories, 'product_cat' );
// Or, set last argument to true to append to existing terms
wp_set_object_terms( $product_id, $categories, 'product_cat', true );
Related
I'm trying to query posts, but I'm only interested in certain fields and want to limit the fields that are being returned. In the end I want to return an array of posts with limited fields to pass it to a rest-api endpoint, so I can fetch it in another project.
I managed to query exactly the posts that I want (meta key geo_latitude exists) and pass it to the api endpoint, but the query does return an array of WP_Post objects which don't include the geodata I'm looking for. My big headache is how to customize the return value.
For the return value, I'm trying to achieve this:
Array of queried posts
Each post only contains:
Post Title
Post Link
geo_latitude
geo_longitude
Geodata: https://codex.wordpress.org/Geodata (the values are being copied from the plugin geo mashup)
Working code for querying the posts:
// Query the posts
function get_posts_with_geo( $data ) {
$posts = get_posts( array(
'numberposts' => -1,
'post_type' => 'post',
'meta_query' => [
[
'key' => 'geo_latitude',
'compare' => 'EXISTS',
]
],
) );
if ( empty( $posts ) ) {
return null;
}
return $posts;
}
// Register api endpoint and pass the query post function to it.
add_action( 'rest_api_init', function () {
register_rest_route( 'endpoint', '/posts', array(
'methods' => 'GET',
'callback' => 'get_posts_with_geo',
) );
} );
It returns an array of following wp posts object:
WP_Post Object
(
[ID] =>
[post_author] =>
[post_date] =>
[post_date_gmt] =>
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] =>
[comment_status] =>
[ping_status] =>
[post_password] =>
[post_name] =>
[to_ping] =>
[pinged] =>
[post_modified] =>
[post_modified_gmt] =>
[post_content_filtered] =>
[post_parent] =>
[guid] =>
[menu_order] =>
[post_type] =>
[post_mime_type] =>
[comment_count] =>
[filter] =>
)
Before I tried to use the already available rest-api endpoints, especially /wp-json/wp/v2/posts. We're talking about around 250 posts which have geodata, but over 500 posts overall. Limit per page is 100. I can't query for posts with geodata only in this endpoint, so I would have to receive all posts, loop through pagination and then filter all posts without geodata out. That's pretty wasteful and the reason I'm trying to build my own endpoint which gives me exactly the data that I want.
/edit:
Likely a lot of room of improvement, but working solution so far:
Right before returning the $posts in function get_posts_with_geo, following foreach loop was added:
foreach ( $posts as $key => $post ) {
$posts[ $key ]->title = get_the_title( $post->ID );
$posts[ $key ]->link = get_permalink( $post->ID );
$posts[ $key ]->latitude = get_post_meta( $post->ID, 'geo_latitude', true );
$posts[ $key ]->longitude = get_post_meta( $post->ID, 'geo_longitude', true );
}
It adds the keys to the end of each returned $post, but still returns every other field as well from the WP_Object.
/edit: better solution
I changed the wp query to return only the post ids. From this array of ids, I create a new array with post objects that contains only the fields I want (queried with the post ids). In the end, I return the new array.
function get_posts_with_geo( $data ) {
$posts = get_posts( array(
'numberposts' => -1,
'post_type' => 'post',
'fields' => 'ids',
'meta_query' => [
[
'key' => 'geo_latitude',
'compare' => 'EXISTS',
]
],
) );
// https://codex.wordpress.org/Geodata
if ( empty( $posts ) ) {
return null;
}
$newPosts = [];
$i = 0;
foreach ( $posts as $post ) {
$newPosts[$i] = [
"title" => get_the_title( $post ),
"thumbnail" => get_the_post_thumbnail_url( $post, 'thumbnail' ),
"link" => get_permalink( $post ),
"latitude" => get_post_meta( $post, 'geo_latitude', true ),
"longitude" => get_post_meta( $post, 'geo_longitude', true ),
];
$i++;
}
return $newPosts;
}
// Register the new endpoint and pass the related callback to it.
add_action( 'rest_api_init', function () {
register_rest_route( '(redacted)', '/posts', array(
'methods' => 'GET',
'callback' => 'get_posts_with_geo',
) );
} );
You can use the posts_fields filter to alter what fields get returned.
you need to pass 'suppress_filters => false in the get_posts() arguments in order to get that filter to run.
example :-
function alter_fields_zillion($fields) {
return 'ID,post_title'; // etc
}
add_filter('posts_fields','alter_fields_zillion');
Or you can loop through the posts then add meta_data with the post.
foreach ( $posts as $key => $post ) {
$posts[ $key ]->key1 = get_post_meta( $post->ID, 'key1', true );
$posts[ $key ]->key2 = get_post_meta( $post->ID, 'key2', true );
}
I hope it helps.
I want to get a list of products with sku and post id with this code, everything seems fine and ok with this code :
$statuses = array('publish', 'draft');
// Args on the main query for WC_Product_Query
$args = [
'status' => $statuses,
'orderby' => 'name',
'order' => 'ASC',
'limit' => -1,
];
$vendor_products = wc_get_products($args);
$list_array = array();
foreach ($vendor_products as $key => $product) {
if ($product->get_type() == "variable") {
// Args on product variations query for a variable product using a WP_Query
$args2 = array(
'post_parent' => $product->get_id(),
'post_type' => 'product_variation',
'orderby' => array( 'menu_order' => 'ASC', 'ID' => 'ASC' ),
'fields' => 'ids',
'numberposts' => -1,
);
foreach ( get_posts( $args2 ) as $child_id ) {
// get an instance of the WC_Variation_product Object
$variation = wc_get_product( $child_id );
if ( ! $variation || ! $variation->exists() ) {
continue;
}
$list_array[] = array(
'sku' => $variation->get_sku(),
'postid' => $variation->get_id()
);
}
} else {
$list_array[] = array(
'sku' => $product->get_sku(),
'postid' => $product->get_id()
);
}
}
I have total 1660 (470 published and 1,190 drafted) products but it's just returns 501 products and i don't know why!
this is my products in woocommerce:
this is the final result of query :
this is the result of Janki's code
// Woocommerce get all products
$args = array(
'post_type' => array('product','product_variation'),
'meta_key' => '_sku',
'post_status' => array('publish','draft'),
'meta_query' => array(
array(
'key' => '_sku',
'compare' => 'EXISTS',
),
),
);
$products = new WP_Query($args);
/* using this code you can get all products */
/* this may help you to get details */
Below code is combination of search result($query String) with added $args.
$all_num_normal (counted posts quantity) says its 5 posts as I expected. However, when I foreach title of posts, it shows only 3 titles. print_r also shows only 3 posts information.
When I search same keyword by regular search function, it shows 5 posts(its hit any of title, text, category name or meta value).
<?php
global $query_string;
$args = $query_string;
parse_str( $args, $args );
$args_normal = $args + array(
'posts_per_page' => -1,
'category_name' => $shop_name,
'category__not_in' => array( 3, 137, 571 ),
'meta_query' => array(
array(
'key'=> '2a',
'value' => array('2020-02-01' , $week),
'compare' => 'BETWEEN',
'type' => 'DATE',
),
),
);
echo '<pre>' . print_r( $args_normal, TRUE ) . '</pre>';
$query = new WP_Query($args_normal);
$all_num_normal = $query->found_posts;
?>
<?php
//Must be 5 titles, but its only 3 titles shown
$my_posts = get_posts($args_normal);
//print_r shows information of 3 posts
if ( $my_posts ) {
foreach( $my_posts as $post ) {
echo get_the_title( $post->ID);
}}
?>
print_r shows below text.
Array
(
[s] => rabbit
[posts_per_page] => -1
[category_name] => atsugi
[category__not_in] => Array
(
[0] => 3
[1] => 137
[2] => 571
)
[meta_query] => Array
(
[0] => Array
(
[key] => 2a
[value] => Array
(
[0] => 2020-02-01
[1] => 2020-07-20
)
[compare] => BETWEEN
[type] => DATE
)
)
)
I set 'suppress_filters' => false, and then filtering started correctly.
Regarding 'suppress_filters,' get_post function has default parameter "true", and it means filtering is not enable.
Need some help with WooCommerce adding variations to product attributes.
I created an attribute called Data ( pa_data ), this attribute stores terms from a custom field added with ACF, this field is a date picker.
I want to create an event that is recurring, and for every recurrence, I want to add a variation with price and stock.
So the process is like this:
Add all ACF fields in an array.
Create Variations with this array.
Add variations to attributes.
The problems is that i don't know how to add variations to the attribute ( pa_data );
Here is how is displaying my attributes
https://i.imgur.com/YmbDFlO.png
Here is how i want to be displayed
https://i.imgur.com/oDNvuOD.png
$days = array
array(
'date' => 'April 02, 2020',
'price' => '10',
),
array(
'date' => 'April 03, 2020',
'price' => '20',
),
array(
'date' => 'April 04, 2020',
'price' => '10',
),
);
// This method inserts new data into the post after the post is saved
add_action('post_updated', 'ProductUpdate', 10, 3);
// Callback function after the post is saved
function ProductUpdate($post_id, $post_after, $post_before) {
if ( $post_after && get_post_type($post_id) == 'product' ) {
ProductSetVariations( $post_id, $postDataVariations );
}
};
function ProductSetVariations($productID, $days ) {
// Get product object
$product = wc_get_product($productID);
foreach ($days as $day ) {
$date = $day['date'];
$price = $day['price'];
$variationPost = array(
'post_title' => $product->get_title(),
'post_name' => 'product-' . $productID . '-variation',
'post_status' => 'publish',
'post_parent' => $productID,
'post_type' => 'product_variation',
'guid' => $product->get_permalink()
);
// Insert the new variation post;
$variationID = wp_insert_post($variationPost);
// Create the new post based on the id
$variation = new WC_Product_Variation($variationID);
$taxonomy = 'pa_data';
// If term dosent exsist in taxonomy than add it
if ( !term_exists( $date, $taxonomy )) {
wp_insert_term( $date, $taxonomy );
};
$term_slug = get_term_by('name', $date, $taxonomy)->slug; // Get the term slug
$post_term_names = wp_get_post_terms( $productID, $taxonomy, array('fields' => 'names') );
if( ! in_array( $date, $post_term_names ) ) {
wp_set_post_terms( $productID, $date, $taxonomy, true );
};
$term_slug = get_term_by('name', $date, $taxonomy)->slug; // Get the term slug
update_post_meta( $variationID, 'attribute_'.$taxonomy, $term_slug );
$variation->set_price($price);
$variation->save(); // Save the data
}
};
Resolved!
Solution:
The problem was with WordPress hook 'post_updated', it does save in the database the changes but it doesn't change it in admin.
Here is the solution, for someone who has to update posts from rest api or just post update.
This is only a simple demonstration.
add_action('woocommerce_update_product', 'ProductUpdate', 10, 3);
function ProductUpdate($post_id) {
// Insert Product Attributes
function insert_product_attributes ($post_id, $variations) {
$product = wc_get_product($post_id);
// Set up an array to store the current attributes values.
$values = array();
foreach ($variations as $variation) {
array_push($values, $variation['date']);
}
wp_set_object_terms($post_id, $values, 'pa_data', true );
$product_attributes_data = array('pa_data' =>
array(
'name' => 'pa_data',
'position' => '1',
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1',
);
);
update_post_meta($post_id, '_product_attributes', $product_attributes_data);
};
function insert_product_variations ($post_id, $variations) {
foreach ($variations as $index => $variation) {
$attribute_term = get_term_by('name', $variation['date'], 'pa_data');
if ( $variation['date'] == $attribute_term ) {
return;
}
$variation_post = array( // Setup the post data for the variation
'post_title' => 'Variation #'.$index.' of data for product#'. $post_id,
'post_name' => 'product-'.$post_id.'-variation-'.$index,
'post_status' => 'publish',
'post_parent' => $post_id,
'post_type' => 'product_variation',
'guid' => home_url() . '/?product_variation=product-' . $post_id . '-variation-' . $index
);
$variation_post_id = wp_insert_post($variation_post); // Insert the variation
// We need to insert the slug not the name into the variation post meta
update_post_meta($variation_post_id, 'attribute_pa_data', $attribute_term->slug);
update_post_meta($variation_post_id, '_price', $variation['price']);
update_post_meta($variation_post_id, '_regular_price', $variation['price']);
}
function ProductSetVariations($post_id ) {
// Get product object
$product = wc_get_product($post_id);
// Verify if the product is variable or simple product
if ( !$product->is_type( 'variable' ) ) {
return;
};
$product_data = array(
'days' => array(
array(
'sku' => '123SKU',
'date' => '1 April 2020',
'price' => '10',
'stock' => '20'
),
array(
'sku' => '456SKU',
'date' => '2 April 2020',
'price' => '10',
'stock' => '20'
),
array(
'sku' => '789SKU',
'date' => '3 April 2020',
'price' => '10',
'stock' => '20'
)
)
);
insert_product_attributes($post_id, $product_data['days']); // Insert variations passing the new post id & variations
insert_product_variations($post_id, $product_data['days']);
}
};
i use a Toolset plugin to make view on WP and they give us possibility to manipulate with API.
I try to add argument to my view but it doesn't work.
here is the function :
add_filter( 'wpv_filter_query', 'add_city_tax', 99, 3 );
function add_city_tax( $query_args, $view_settings, $view_id )
{
if($view_id == 7706)
{
$args = array(
'tax_query' => array
(
array
(
[taxonomy] => 'ville',
[field] => 'id',
[terms] => Array
(
[0] => 220
),
[operator] => 'IN'
),
[relation] => 'OR',
),
);
}
$query_args = new WP_Query( $args );
return $query_args;
}
the page make an error
The method you are declaring args is not correct. You should not create array like that. Please check following example.
function add_city_tax( $query_args, $view_settings, $view_id ) {
if($view_id == 7706) {
$args = array(
'tax_query' => array(
array(
'taxonomy' => 'ville',
'field' => 'id',
'terms' => array( 220 ),
'operator' => 'IN',
),
'relation' => 'OR',
),
);
}
$query_args = new WP_Query( $args );
return $query_args;
}
And here doc
Description
When displaying a View listing posts, this filter is applied to the arguments being generated by the View settings before they are passed to the WP_Query class.
Views filters - wpv_filter_query
Note that the filters that you can add to the View are also hooked here, each of them using a different priority that gets up to 100. To ensure that your filter runs after them, you would need to use a higher priority number.
Remember that the filter can take three parameters. If you pass more than one, you need to specify it in your code using the fourth argument:
1
add_filter( 'wpv_filter_query', 'my_callback_function', 99, 3 );
Arguments
array $query_args Τhe query arguments as in WP_Query.
array $view_settings The View settings.
int $view_id The View ID.
No it doesn't work like this.
i have tried like this :
function add_city_tax( $query_args, $view_settings, $view_id ) {
if($view_id == 7706) {
$args = array(
'tax_query' => array(
array(
'taxonomy' => 'ville',
'field' => 'id',
'terms' => array( 220 ),
'operator' => 'IN',
),
'relation' => 'AND',
),
);
}
$query_args[] = $args ;
$msg = '<pre>' . print_r($query_args, true) . '</pre>';
mail('franck#efficonex.fr', 'test', $msg);
return $query_args;
}
add_filter( 'wpv_filter_query', 'add_city_tax', 99, 3 );
But it is the same result without filter.
here is the example of api
//Return only posts from the current author when listing posts of type company:
add_filter( 'wpv_filter_query', 'prefix_show_only_current_author' );
function prefix_show_only_current_author( $query_args ) {
global $current_user;
$types = (array) $query_args['post_type'];
if ( !is_admin() && in_array( 'company', $types ) ) {
$query_args['author'] = empty( $current_user->ID ) ? -1 : $current_user->ID;
}
return $query_args;
}